From e8c0137e32b06dbf7c869d47effca01ef793635f Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Thu, 25 Oct 2018 15:34:12 +0200 Subject: [PATCH 001/220] fix builds --- Dockerfile | 4 ++-- Makefile | 2 +- build/docker/files/entrypoint.sh | 7 ------- build/scripts/docker/entrypoint.sh | 7 +++++++ 4 files changed, 10 insertions(+), 10 deletions(-) delete mode 100755 build/docker/files/entrypoint.sh create mode 100755 build/scripts/docker/entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 74cb887cc..d8699b68f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,8 @@ FROM alpine:latest RUN apk update && apk add --no-cache jq curl WORKDIR /root/ -COPY --from=builder /go/bin/centrifuge . -COPY build/docker/files/entrypoint.sh /root +COPY --from=builder /go/bin/go-centrifuge . +COPY build/scripts/docker/entrypoint.sh /root VOLUME ["/root/config"] diff --git a/Makefile b/Makefile index e064d88e8..548f0dc76 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ build-linux-amd64: install-xgo @echo "Building amd64 with flags [${LD_FLAGS}]" @mkdir -p build/linux-amd64 @xgo -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} . - @mv build/linux-amd64/go-centrifuge-linux-amd64 build/linux-amd64/centrifuge + @mv build/linux-amd64/go-centrifuge-linux-amd64 build/linux-amd64/go-centrifuge @tar -zcvf cent-api-linux-amd64-${TAG}.tar.gz -C build/linux-amd64/ . build-docker: ## Build Docker Image diff --git a/build/docker/files/entrypoint.sh b/build/docker/files/entrypoint.sh deleted file mode 100755 index f5834c4bc..000000000 --- a/build/docker/files/entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env sh - -set -x - -CENT_MODE=${CENT_MODE:-run} - -/root/centrifuge ${CENT_MODE} --config /root/.centrifuge/config/config.yaml $@ diff --git a/build/scripts/docker/entrypoint.sh b/build/scripts/docker/entrypoint.sh new file mode 100755 index 000000000..5cca2e683 --- /dev/null +++ b/build/scripts/docker/entrypoint.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +set -x + +CENT_MODE=${CENT_MODE:-run} + +/root/go-centrifuge ${CENT_MODE} --config /root/.centrifuge/config/config.yaml $@ From 8db8de3203562c2385b03a4e5c44f7d806034901 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 25 Oct 2018 17:21:27 +0200 Subject: [PATCH 002/220] rename COC for github (#382) --- CONDUCT.md => CODE_OF_CONDUCT.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CONDUCT.md => CODE_OF_CONDUCT.md (100%) diff --git a/CONDUCT.md b/CODE_OF_CONDUCT.md similarity index 100% rename from CONDUCT.md rename to CODE_OF_CONDUCT.md From 31fb6d4438417f163180f7e045e9215273252de6 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 29 Oct 2018 11:36:43 +0100 Subject: [PATCH 003/220] Hardcode External IP (#386) * Hardcode External IP * Hardcode External IP --- p2p/server.go | 3 ++- p2p/server_test.go | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/p2p/server.go b/p2p/server.go index 151638f22..9663d911b 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -203,7 +203,8 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { addressFactory := func(addrs []ma.Multiaddr) []ma.Multiaddr { if extMultiAddr != nil { - addrs = append(addrs, extMultiAddr) + // We currently support a single protocol and transport, if we add more to support then we will need to adapt this code + addrs = []ma.Multiaddr{extMultiAddr} } return addrs } diff --git a/p2p/server_test.go b/p2p/server_test.go index ff29c39eb..0d32d67e4 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -73,6 +73,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { assert.NotNil(t, h) addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", externalIP, listenPort)) assert.Nil(t, err) + assert.Equal(t, 1, len(h.Addrs())) assert.Contains(t, h.Addrs(), addr) } From ebecdc14fea346280d1ad96b5aebdf28529bee87 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 30 Oct 2018 09:23:19 +0100 Subject: [PATCH 004/220] Add Connect timeout to p2p conns (#387) * Add Connect timeout to p2p conns * add exported comment --- build/configs/default_config.yaml | 5 +++++ config/configuration.go | 11 ++++++++--- p2p/client.go | 14 +++++--------- resources/data.go | 6 +++--- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index c383d04b8..44a9a52d5 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -32,6 +32,11 @@ networks: anchorRepository: "0x7f854dfa98012d7fa55c803bba2260bcdee4b5ed" paymentObligation: "" +# Peer-to-peer configurations +p2p: + # Timeout when opening connections to peers + connectTimeout: "30s" + # Queue configurations for asynchronous processing queue: # Defines the number of workers/consumers that will be allocated at startup diff --git a/config/configuration.go b/config/configuration.go index bbd110c86..4181ce8b0 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -44,21 +44,26 @@ type IdentityConfig struct { PrivateKey []byte } -// Storage backend +// GetStoragePath returns the data storage backend func (c *Configuration) GetStoragePath() string { return c.V.GetString("storage.Path") } -// P2P Port +// GetP2PPort returns P2P Port func (c *Configuration) GetP2PPort() int { return c.V.GetInt("p2p.port") } -// P2P External IP +// GetP2PExternalIP returns P2P External IP func (c *Configuration) GetP2PExternalIP() string { return c.V.GetString("p2p.externalIP") } +// GetP2PConnectionTimeout returns P2P Connect Timeout +func (c *Configuration) GetP2PConnectionTimeout() time.Duration { + return c.V.GetDuration("p2p.connectTimeout") +} + //////////////////////////////////////////////////////////////////////////////// // Notifications //////////////////////////////////////////////////////////////////////////////// diff --git a/p2p/client.go b/p2p/client.go index 6aab6dd67..ab8e9fcc4 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -17,7 +17,6 @@ import ( pstore "github.com/libp2p/go-libp2p-peerstore" ma "github.com/multiformats/go-multiaddr" "google.golang.org/grpc" - "google.golang.org/grpc/connectivity" ) type Client interface { @@ -62,17 +61,14 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error // so LibP2P knows how to contact it hostInstance.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) - // make a new stream from host B to host A - g, err := grpcProtoInstance.Dial(context.Background(), peerID, grpc.WithInsecure()) + // make a new stream from host B to host A with timeout + // Retrial is handled internally, connection request will be cancelled by the connection timeout context + ctx, _ := context.WithTimeout(context.Background(), config.Config.GetP2PConnectionTimeout()) + g, err := grpcProtoInstance.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) } - for { - if g.GetState() == connectivity.Ready { - break - } - } return p2ppb.NewP2PServiceClient(g), nil } diff --git a/resources/data.go b/resources/data.go index 800044e5d..f7a93bf60 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\x49\x77\xdb\x3a\x0f\xdd\xeb\x57\xe0\x38\x9b\xef\x5b\xd4\xd6\x60\xc9\xb6\x76\x19\x3b\x39\x79\xb6\xe3\x36\x4d\x76\x14\x09\x49\xac\x25\x52\x21\x29\xcb\xee\xaf\x7f\x87\x1a\xd2\x0c\x1d\x5e\x56\x3a\x01\x70\x09\x5c\x5c\x00\x3e\x81\x0b\x4c\x49\x5d\x18\x60\xb8\xc7\x42\x56\x25\x0a\x03\x06\xb5\x11\x68\x80\x64\x84\x0b\x6d\x40\x71\xb1\xc3\xe4\xe8\x50\x14\x46\xf1\xb4\xce\xf0\x06\x4d\x23\xd5\x2e\x06\x55\x6b\xcd\x89\xc8\x79\x51\x38\x2d\x18\x17\x08\x26\x47\x60\x3d\xae\xe8\x3c\x35\x98\x9c\x18\x38\x7f\x42\x80\x92\x70\x61\x2c\xbe\x33\xb8\xc4\x0e\xc0\x09\x2c\x25\x25\x45\x9b\x02\x17\x19\x50\x29\x8c\x22\xd4\x00\x61\x4c\xa1\xd6\xa8\x41\x20\x32\x30\x12\x12\x04\x8d\x06\x1a\x6e\x72\x40\xb1\x87\x3d\x51\x9c\x24\x05\xea\xb1\x03\x43\xbc\x85\x04\xe0\x2c\x86\x20\x08\xda\x6f\x34\x39\x2a\xac\xcb\xbe\x82\x8f\x2c\x86\x79\x30\xef\x6c\x89\x94\x46\x1b\x45\xaa\x15\xa2\xd2\x5d\x2c\xc0\x3b\x18\x4d\x78\x35\x9d\x78\xfe\x6c\xec\x8e\xdd\xb1\x37\x31\xb4\x9a\x04\x73\xdf\xf5\x27\xbc\x4a\xf5\x64\x5d\x6e\xd7\x87\xa4\xd9\xd5\x0f\xf7\xf7\x17\x69\xfd\x63\x9b\x1c\x2e\x4f\x37\xb8\xbd\x39\x5f\xca\x1f\xc7\x63\x18\xce\xf7\x6b\x91\x7d\xdd\xaf\xae\xbf\x2f\xef\x77\xa3\xbf\xc2\x06\x03\xec\xd7\x34\xba\xbc\x89\xca\xdd\xe3\x1d\x7e\xbf\xfb\x7c\xe7\x3f\xae\x6a\x2f\xfa\x56\xb1\xf7\xc1\xee\x93\xf4\xb6\x41\x99\x93\x7c\x75\x16\xde\x62\x28\xbc\x0e\x76\xa0\xeb\x74\x60\x6b\x28\x82\x33\x14\x86\x9b\xe3\x15\xa1\x46\xaa\x63\x0c\xa3\xd1\x2b\xcb\x06\x33\xae\xcd\x0b\x13\x11\x34\x97\x6a\x83\x95\xd4\xfc\x55\x54\x45\x8e\x56\x2a\xff\x24\x05\xcf\x88\xe1\x52\xb4\xb6\xb6\x81\xd7\x84\x8b\x5f\xca\xa9\xef\xb3\x03\xcf\x55\xd3\x25\x78\x02\x37\x75\x89\x8a\x53\xf8\x78\x01\x32\x6d\x15\xf4\x4c\x2b\x3f\x23\xbb\x66\x86\x5e\x1f\x75\x36\x74\x0c\x0a\xae\x8d\x8d\x14\x92\xe1\x5b\xb1\x55\x4a\xee\x79\x6b\x90\x2d\xf6\xb3\x04\x86\xf4\xfe\x83\x02\x82\x70\xec\xfb\xe1\xd8\x77\xdd\xf1\xd4\x7f\xad\x02\xcf\xbf\x08\x3e\x4b\x79\xb7\xe4\x9c\xae\xbf\x36\xdb\x7c\x7b\x76\x1f\x1d\x3e\xd3\x95\x5c\xa6\xd1\x66\x7d\xff\xe9\xaa\x6a\x52\x4f\xcd\xc2\x66\x79\xf0\x1f\x36\x41\x75\xce\xbc\xd7\x5a\xe8\x1f\x98\x47\x63\xdf\x73\x7f\xf7\xc0\xfa\xe1\xfa\x74\xfe\x7e\xf5\x41\xed\x2f\x1f\xce\x16\x0d\xdb\xc9\x2f\xf4\xf4\xb4\x3c\x7f\xf8\x50\x2d\xf0\x78\x7c\x98\xde\x5e\xce\xb3\x2b\x15\xe4\xdb\x9b\x6f\xa3\x9e\xa7\xcb\x5e\xf5\x03\x93\x96\xe6\x77\xb0\xe9\xe7\xfa\x37\x73\x31\xed\x83\x97\xc4\x52\x04\x0c\xab\x42\x1e\x91\xc1\x6d\x49\x94\x81\xf3\x5e\x6a\x1a\x52\xa9\x5a\x52\x33\xbe\x47\xf1\x82\xce\xb7\x72\x84\xdf\xea\xd1\x3d\x2c\x5c\xe6\x2f\xa6\xe1\xcc\xc3\x59\x30\x9f\xfa\xd1\x62\x46\xa2\x28\x99\x91\xc5\x82\xb8\x0b\xc6\x22\x3a\x0b\x58\x10\x46\xec\x0f\xca\x75\x0f\x8b\x28\x72\xa9\x1b\x2c\x58\xe0\x79\xd3\x30\x20\xa9\xcb\xc2\x39\x0d\xa3\x28\x9a\xf9\x01\x5b\x50\x3f\x25\x33\x16\x21\xfd\x83\xc6\xdd\xc3\x2c\x9d\x87\x53\x96\x92\xc5\xdc\xf5\x7c\x36\x4b\x49\x18\xd2\xb9\x1b\x24\x09\xf1\xfd\xc8\x4d\x28\x43\x9c\x26\x21\xb2\xbf\x4c\xc3\x09\xac\x6b\xac\xd1\xd2\x90\xf2\xac\x56\xad\xa9\xe3\x8b\xe8\xa3\xa0\xb9\x92\x42\xd6\xda\xaa\x93\xa2\xd6\x5c\x64\xce\xa3\x0d\xe8\x16\x61\xb7\x4c\x75\x4b\xad\xa8\xcb\x04\x95\xd5\xb7\x6d\x0e\x2a\x3d\xa1\x52\x68\x3b\x32\xbd\xd6\x1b\xab\xe4\x04\x81\x14\x85\xa4\xc4\x20\x03\x62\x40\x1b\xa2\x4c\x5d\x39\x60\xe3\xef\xba\xc0\x18\xfc\x16\xfd\x4a\x21\x6a\xa8\x2b\x38\x5f\x7d\x01\x7a\xa4\x05\x6a\x68\x72\x14\xfd\x03\xc0\x35\x34\x84\xb7\x3b\xd8\xe6\x8b\x7b\x14\x46\x3b\xd0\x9b\xef\x08\x37\x5b\x5e\xe2\xf5\x6d\x0c\x9e\x2d\xf4\x49\x60\xba\x42\xca\x53\x4e\x5f\x16\xed\x0c\xf2\xea\x4a\xbb\xc5\x02\xad\x72\x9a\x9c\xd3\xfc\x49\x7a\x40\x28\x95\xb5\x5d\x18\x12\x6a\x8d\xc3\x1e\x90\x96\x84\x7e\x80\x19\x70\xd1\xfe\x93\xd6\xda\xc8\xb2\x7f\x04\x52\x5e\xa0\x03\xc3\xcd\x39\xed\x60\x6e\x48\x89\x31\x8c\xec\x9d\x19\x3d\x5d\x16\x9b\xcc\x00\xfc\xf4\x2e\x2d\xb8\xdd\x53\x76\x75\xc0\xff\x1a\x04\x85\x8f\x35\x57\x08\x8d\x06\xa9\x80\x57\xb4\x3f\x37\xf6\xba\xd8\x4f\x4a\x8c\x4d\xbb\xa5\xe4\xff\x96\x5d\xc9\xf0\xcb\x66\x19\x43\xa3\xe3\xc9\xc4\x36\xa0\xc8\xa5\x36\xf1\x22\x9c\x46\x43\x2b\xdb\x63\x98\x11\x5b\x09\xa7\x36\xd9\x8c\xe8\x95\xfd\x8c\xc1\x73\x87\xbf\x37\xce\x05\x2f\xb9\xe9\x9c\x97\xf6\x33\x86\xe9\xcc\xf3\x83\xf9\xbc\xf5\xb4\x1d\x90\x75\xcb\x97\xed\x55\x27\x2c\xf1\xb3\x2e\xa3\x88\xd0\x84\xb6\x35\xf7\x15\x30\xd6\x1d\x4f\x02\x49\x21\xe9\x0e\x88\x60\x7d\x21\x60\x14\xcf\x32\x54\xc8\x9c\x6e\x70\xf1\x60\x86\x36\xcb\xda\xc4\x30\x8a\x5c\x57\x77\x4c\xde\x58\xa6\x9e\xa3\x57\x52\x16\x50\x92\x03\x28\x34\x8a\x77\x7b\x56\xa3\x60\x40\x5e\xb8\xc9\x3d\x2a\x07\xac\xe3\xa6\xf3\x8b\xc1\xef\xab\xfe\x35\x24\x17\x06\xd5\x9e\x14\x2d\xee\xb1\x13\x28\xb1\xd9\xd1\x5a\xa9\xf6\xb6\x3c\x8b\xc8\x89\x86\x04\xd1\x1e\x1f\x83\xd4\xb4\x85\x0c\x00\xf6\x3d\x3b\xdb\x7e\x5f\xc1\x05\xd7\x6d\x37\x5b\x44\x2d\xcb\x37\x6a\xd0\xc0\x24\x08\x69\x40\xd7\x55\x25\x95\x01\x73\x68\x33\x22\x15\xb7\x3f\x2f\x0e\x2b\x29\x8b\x53\x6a\xc7\xf6\x52\x58\x24\x16\x83\x51\x35\x3a\xce\xbf\x01\x00\x00\xff\xff\x75\xa8\x4f\xcf\x53\x09\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\x49\x77\xdb\xbc\x0e\xdd\xeb\x57\xe0\x38\x9b\xf7\x16\xb1\x35\x58\xb2\xad\x5d\xc6\xaf\x83\x93\x67\x3b\x6e\xd3\x64\x47\x91\x90\xc5\x5a\x22\x15\x92\xf2\xd0\x5f\xff\x0e\x29\x29\xcd\xd0\xe1\xcb\x4a\xc7\x04\x2e\x70\x81\x0b\x20\x27\x70\x89\x39\x69\x4a\x03\x0c\x77\x58\xca\xba\x42\x61\xc0\xa0\x36\x02\x0d\x90\x0d\xe1\x42\x1b\x50\x5c\x6c\x31\x3b\x7a\x14\x85\x51\x3c\x6f\x36\x78\x8b\x66\x2f\xd5\x36\x05\xd5\x68\xcd\x89\x28\x78\x59\x7a\x0e\x8c\x0b\x04\x53\x20\xb0\x0e\x57\xb4\x96\x1a\x4c\x41\x0c\x5c\x3c\x23\x40\x45\xb8\x30\x16\xdf\xeb\x4d\x52\x0f\xe0\x04\xe6\x92\x92\xd2\xa5\xc0\xc5\x06\xa8\x14\x46\x11\x6a\x80\x30\xa6\x50\x6b\xd4\x20\x10\x19\x18\x09\x19\x82\x46\x03\x7b\x6e\x0a\x40\xb1\x83\x1d\x51\x9c\x64\x25\xea\xa1\x07\xbd\xbf\x85\x04\xe0\x2c\x85\x28\x8a\xdc\x37\x9a\x02\x15\x36\x55\xc7\xe0\x23\x4b\x61\x1a\x4d\xdb\xb7\x4c\x4a\xa3\x8d\x22\xf5\x02\x51\xe9\xd6\x17\xe0\x14\x06\x23\x5e\x8f\x47\x41\x38\x19\xfa\x43\x7f\x18\x8c\x0c\xad\x47\xd1\x34\xf4\xc3\x11\xaf\x73\x3d\x5a\x56\xeb\xe5\x21\xdb\x6f\x9b\xc7\x87\x87\xcb\xbc\xf9\xb1\xce\x0e\x57\x67\x2b\x5c\xdf\x5e\xcc\xe5\x8f\xe3\x31\x8e\xa7\xbb\xa5\xd8\x7c\xdd\x2d\x6e\xbe\xcf\x1f\xb6\x83\xbf\xc2\x46\x3d\xec\xd7\x3c\xb9\xba\x4d\xaa\xed\xd3\x3d\x7e\xbf\xff\x7c\x1f\x3e\x2d\x9a\x20\xf9\x56\xb3\x7f\xa2\xed\x27\x19\xac\xa3\xaa\x20\xc5\xe2\x3c\xbe\xc3\x58\x04\x2d\x6c\x5f\xae\xb3\xbe\x5a\x3d\x09\xce\x50\x18\x6e\x8e\xd7\x84\x1a\xa9\x8e\x29\x0c\x06\x6f\x5e\x56\xb8\xe1\xda\xbc\x7a\x22\x82\x16\x52\xad\xb0\x96\x9a\xbf\xf1\xaa\xc9\xd1\x4a\xe5\x7f\x59\xc9\x37\xc4\x70\x29\xdc\x9b\x6b\xe0\x0d\xe1\xe2\x97\x72\xea\xfa\xec\xc1\x4b\xd5\xb4\x09\x9e\xc0\x6d\x53\xa1\xe2\x14\x3e\x5e\x82\xcc\x9d\x82\x5e\x68\xe5\xa7\x67\xdb\xcc\x38\xe8\xbc\xce\xfb\x8e\x41\xc9\xb5\xb1\x9e\x42\x32\x7c\x2f\xb6\x5a\xc9\x1d\x77\x0f\xd2\x61\xbf\x48\xa0\x4f\xef\x5f\x28\x20\x8a\x87\x61\x18\x0f\x43\xdf\x1f\x8e\xc3\xb7\x2a\x08\xc2\xcb\xe8\xb3\x94\xf7\x73\xce\xe9\xf2\xeb\x7e\x5d\xac\xcf\x1f\x92\xc3\x67\xba\x90\xf3\x3c\x59\x2d\x1f\x3e\x5d\xd7\xfb\x3c\x50\x93\x78\x3f\x3f\x84\x8f\xab\xa8\xbe\x60\xc1\x5b\x2d\x74\x01\xa6\xc9\x30\x0c\xfc\xdf\x05\x58\x3e\xde\x9c\x4d\xff\x59\x7c\x50\xbb\xab\xc7\xf3\xd9\x9e\x6d\xe5\x17\x7a\x76\x56\x5d\x3c\x7e\xa8\x67\x78\x3c\x3e\x8e\xef\xae\xa6\x9b\x6b\x15\x15\xeb\xdb\x6f\x83\xae\x4e\x57\x9d\xea\xfb\x4a\xda\x32\x9f\xc2\xaa\x9b\xeb\xdf\xcc\xc5\xb8\x73\x9e\x13\x5b\x22\x60\x58\x97\xf2\x88\x0c\xee\x2a\xa2\x0c\x5c\x74\x52\xd3\x90\x4b\xe5\x8a\xba\xe1\x3b\x14\xaf\xca\xf9\x5e\x8e\xf0\x5b\x3d\xfa\x87\x99\xcf\xc2\xd9\x38\x9e\x04\x38\x89\xa6\xe3\x30\x99\x4d\x48\x92\x64\x13\x32\x9b\x11\x7f\xc6\x58\x42\x27\x11\x8b\xe2\x84\xfd\x41\xb9\xfe\x61\x96\x24\x3e\xf5\xa3\x19\x8b\x82\x60\x1c\x47\x24\xf7\x59\x3c\xa5\x71\x92\x24\x93\x30\x62\x33\x1a\xe6\x64\xc2\x12\xa4\x7f\xd0\xb8\x7f\x98\xe4\xd3\x78\xcc\x72\x32\x9b\xfa\x41\xc8\x26\x39\x89\x63\x3a\xf5\xa3\x2c\x23\x61\x98\xf8\x19\x65\x88\xe3\x2c\x46\xf6\x97\x69\x38\x01\x2b\xa3\x53\x23\x4f\x6b\x44\x65\xab\x91\xf3\x4d\xa3\x9c\x85\xf6\xea\xb0\x6e\x37\xde\x9a\x57\x28\x1b\x03\xfb\x02\x05\xc8\x1a\x45\xb7\xf8\x04\x52\x67\x69\x45\x6b\x01\xb4\x07\xfd\xcf\x9d\x4b\x0a\x83\xc8\xd7\x2e\xd2\xb2\xc1\x06\xdf\x84\x70\x9d\x21\xfa\x28\x68\xa1\xa4\x90\x8d\xb6\x73\x40\x51\x6b\x2e\x36\xde\x93\x75\x68\x13\x68\xd7\xb6\x76\x4d\x14\x4d\x95\xa1\xb2\x93\x64\x65\x80\x4a\x8f\xa8\x14\xda\x0e\x67\x37\x55\x7b\x3b\x33\x19\x02\x29\x4b\x49\x89\x41\x06\xc4\x80\x36\x44\x99\xa6\xf6\xc0\xfa\xdf\xb7\x8e\x29\x84\x0e\xfd\x5a\x21\x6a\x68\x6a\xb8\x58\x7c\x01\x7a\xa4\x25\xea\x96\x6a\x1b\x00\xb8\x86\x3d\xe1\x6e\xdb\xdb\x7c\x71\x87\xc2\x58\xaa\xed\xf3\x3d\xe1\x8e\xed\xcd\x5d\x0a\x81\x25\xfa\x2c\x65\x5d\x23\xe5\x39\xa7\xaf\x49\x7b\xbd\x90\x5b\x6a\x77\x58\xa2\xd5\xe8\xbe\xe0\xb4\x78\x16\x39\x10\x4a\x65\x63\x57\x93\x84\x46\x63\xbf\x71\xa4\x2d\x42\xb7\x2a\x18\x70\xe1\x7e\xa4\x8d\x36\xb2\xea\x82\x40\xce\x4b\xf4\xa0\xbf\x6e\x67\x2d\xcc\x2d\xa9\x30\x85\x81\xbd\x68\x83\xe7\x1b\x66\x93\xe9\x81\x9f\xe3\xd2\x92\xdb\x8d\x68\x97\x14\xfc\x67\x8f\xa0\xf0\xa9\xe1\x0a\x61\xaf\x41\x2a\xe0\x35\xed\x0e\x9b\xbd\x63\xf6\x93\x12\x63\xd3\x76\x25\xf9\xaf\xad\xae\x64\xf8\x65\x35\x4f\x61\xaf\xd3\xd1\xc8\x36\xa0\x2c\xa4\x36\xe9\x2c\x1e\x27\x7d\x2b\xdd\xd9\xdd\x10\xcb\x84\x53\x9b\xec\x86\xe8\x85\xfd\x4c\x21\xf0\xfb\xbf\x77\xc6\x25\xaf\xb8\x69\x8d\xe7\xf6\x33\x85\xf1\x24\x08\xa3\xe9\xf4\x95\x44\x8d\x74\xbd\x6a\x85\x25\x7e\xf2\x32\x8a\x08\x4d\x9c\x5c\x7b\x06\x8c\xb5\x67\x9a\x40\x56\x4a\xba\x05\x22\x58\x47\x04\x8c\xe2\x9b\x0d\x2a\x64\xad\xa0\x0d\x1e\x4c\xdf\xe6\x56\xd4\x89\x6f\x55\xed\xce\x82\xad\xd4\x4b\xf4\x5a\xca\x12\x2a\x72\x00\x85\x46\xf1\x76\xa3\x6b\x14\x0c\xc8\x2b\x33\xb9\x43\xe5\x81\x35\x5c\xb5\x76\x29\x84\x1d\xeb\x5f\x43\x72\x61\x50\xed\x48\xe9\x70\x8f\xad\x40\x89\xcd\x8e\x36\x4a\xb9\x2b\xf6\xc2\xa3\x20\x1a\x32\x44\x7b\xe6\x0c\x52\xe3\x88\xf4\x00\x36\x9e\xdd\x22\x61\xc7\xe0\x92\x6b\xd7\x4d\x87\xa8\x65\xf5\x4e\x0d\x1a\x98\x04\x21\x0d\xe8\xa6\xae\xa5\x32\x60\x0e\x2e\x23\x52\x73\xfb\x8f\xcc\x61\x21\x65\x79\x46\xed\xd8\x5e\x09\x8b\xc4\x52\x30\xaa\x41\xcf\xfb\x7f\x00\x00\x00\xff\xff\x2d\xa4\xea\x9a\xbd\x09\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 2387, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 2493, mode: os.FileMode(420), modTime: time.Unix(1540814510, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From 0f7bcac94f7bac1ab704a3e91ca332049ff98497 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 30 Oct 2018 12:55:17 +0100 Subject: [PATCH 005/220] Added timeout for eth read operations (#388) * Added timeout for read operations * fix unit test * manual group import --- anchors/anchor_test.go | 13 ++++++++++++ anchors/ethereum_anchor_repository.go | 4 +++- anchors/ethereum_anchor_repository_test.go | 23 +++++++++++----------- build/configs/default_config.yaml | 2 ++ config/configuration.go | 4 ++++ ethereum/geth_client.go | 20 ++++++++++++++++--- identity/ethereum_identity.go | 14 ++++++++----- resources/data.go | 4 ++-- 8 files changed, 61 insertions(+), 23 deletions(-) diff --git a/anchors/anchor_test.go b/anchors/anchor_test.go index 7b5170d80..9c0253453 100644 --- a/anchors/anchor_test.go +++ b/anchors/anchor_test.go @@ -3,12 +3,25 @@ package anchors import ( + "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &config.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, nil) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestNewAnchorId(t *testing.T) { tests := []struct { name string diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 022c63c7f..c126ca798 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -48,7 +48,9 @@ func NewEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorR // Commits takes an anchorID and returns the corresponding documentRoot from the chain func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocRoot, err error) { - return ethRepository.anchorRepositoryContract.Commits(ethereum.GetGethCallOpts(), anchorID.BigInt()) + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := ethereum.GetGethCallOpts() + return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) } //PreCommitAnchor will call the transaction PreCommit on the smart contract diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 2b49334e5..78e40ece5 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -1,12 +1,11 @@ // +build unit -package anchors_test +package anchors import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" @@ -19,7 +18,7 @@ import ( type mockAnchorRepo struct { mock.Mock - anchors.AnchorRepositoryContract + AnchorRepositoryContract } func (m *mockAnchorRepo) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) { @@ -36,10 +35,10 @@ func TestCorrectCommitSignatureGen(t *testing.T) { correctCommitToSign := "0x15f9cb57608a7ef31428fd6b1cb7ea2002ab032211d882b920c1474334004d6b" correctCommitSignature := "0xb4051d6d03c3bf39f4ec4ba949a91a358b0cacb4804b82ed2ba978d338f5e747770c00b63c8e50c1a7aa5ba629870b54c2068a56f8b43460aa47891c6635d36d01" testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") - anchorIDTyped, _ := anchors.NewAnchorID(anchorID) + anchorIDTyped, _ := NewAnchorID(anchorID) centIdTyped, _ := identity.ToCentID(centrifugeId) - docRootTyped, _ := anchors.NewDocRoot(documentRoot) - messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) + docRootTyped, _ := NewDocRoot(documentRoot) + messageToSign := GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) assert.Equal(t, correctCommitToSign, hexutil.Encode(messageToSign), "messageToSign not calculated correctly") signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) assert.Equal(t, correctCommitSignature, hexutil.Encode(signature), "signature not correct") @@ -55,16 +54,16 @@ func TestGenerateAnchor(t *testing.T) { var documentProofs [][32]byte documentProofs = append(documentProofs, documentProof) centIdTyped, _ := identity.ToCentID(centrifugeId) - messageToSign := anchors.GenerateCommitHash(currentAnchorID, centIdTyped, currentDocumentRoot) + messageToSign := GenerateCommitHash(currentAnchorID, centIdTyped, currentDocumentRoot) signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) var documentRoot32Bytes [32]byte copy(documentRoot32Bytes[:], currentDocumentRoot[:32]) - commitData := anchors.NewCommitData(0, currentAnchorID, documentRoot32Bytes, centIdTyped, documentProofs, signature) + commitData := NewCommitData(0, currentAnchorID, documentRoot32Bytes, centIdTyped, documentProofs, signature) - anchorID, _ := anchors.NewAnchorID(currentAnchorID[:]) - docRoot, _ := anchors.NewDocRoot(documentRoot32Bytes[:]) + anchorID, _ := NewAnchorID(currentAnchorID[:]) + docRoot, _ := NewDocRoot(documentRoot32Bytes[:]) assert.Equal(t, commitData.AnchorID, anchorID, "Anchor should have the passed ID") assert.Equal(t, commitData.DocumentRoot, docRoot, "Anchor should have the passed document root") @@ -75,10 +74,10 @@ func TestGenerateAnchor(t *testing.T) { func TestGetDocumentRootOf(t *testing.T) { repo := &mockAnchorRepo{} - anchorID, err := anchors.NewAnchorID(utils.RandomSlice(32)) + anchorID, err := NewAnchorID(utils.RandomSlice(32)) assert.Nil(t, err) - ethRepo := anchors.NewEthereumAnchorRepository(config.Config, repo) + ethRepo := NewEthereumAnchorRepository(config.Config, repo) docRoot := utils.RandomByte32() repo.On("Commits", mock.Anything, mock.Anything).Return(docRoot, nil) gotRoot, err := ethRepo.GetDocumentRootOf(anchorID) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 44a9a52d5..85518be7d 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -56,6 +56,8 @@ ethereum: gasLimit: 4712388 # Timeout to wait for an ethereum transaction to be added to a block and events triggered contextWaitTimeout: "600s" + # Timeout to wait for read only operations against ethereum + contextReadWaitTimeout: "15s" # Node transaction pool max retries to send a transaction over maxRetries: 200 # Node transaction pool interval retry when a concurrent transaction has been detected diff --git a/config/configuration.go b/config/configuration.go index 4181ce8b0..952312d23 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -102,6 +102,10 @@ func (c *Configuration) GetEthereumNodeURL() string { return c.V.GetString("ethereum.nodeURL") } +func (c *Configuration) GetEthereumContextReadWaitTimeout() time.Duration { + return c.V.GetDuration("ethereum.contextReadWaitTimeout") +} + func (c *Configuration) GetEthereumContextWaitTimeout() time.Duration { return c.V.GetDuration("ethereum.contextWaitTimeout") } diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index ab60bd97a..b20c8f5a8 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -27,11 +27,23 @@ var log = logging.Logger("geth-client") var gc EthereumClient var gcInit sync.Once -// GetDefaultContextTimeout retrieves the default duration before an Ethereum call context should time out +// GetDefaultContextTimeout retrieves the default duration before an Ethereum write call context should time out func GetDefaultContextTimeout() time.Duration { return config.Config.GetEthereumContextWaitTimeout() } +// GetDefaultReadContextTimeout retrieves the default duration before an Ethereum read call context should time out +func GetDefaultReadContextTimeout() time.Duration { + return config.Config.GetEthereumContextReadWaitTimeout() +} + +// DefaultWaitForReadContext returns context with timeout for read operations +func DefaultWaitForReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { + toBeDone := time.Now().Add(GetDefaultReadContextTimeout()) + return context.WithDeadline(context.Background(), toBeDone) +} + +// DefaultWaitForTransactionMiningContext returns context with timeout for write operations func DefaultWaitForTransactionMiningContext() (ctx context.Context, cancelFunc context.CancelFunc) { toBeDone := time.Now().Add(GetDefaultContextTimeout()) return context.WithDeadline(context.TODO(), toBeDone) @@ -254,8 +266,10 @@ func CalculateIncrement(chainNonce uint64, res map[string]map[string]map[string] } } -func GetGethCallOpts() (auth *bind.CallOpts) { +func GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { // Assuring that pending transactions are taken into account by go-ethereum when asking for things like // specific transactions and client's nonce - return &bind.CallOpts{Pending: true} + // with timeout context, in case eth node is not in sync + ctx, cancelFunc := DefaultWaitForReadContext() + return &bind.CallOpts{Pending: true, Context: ctx}, cancelFunc } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index 559cfc06c..2cb32235f 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -101,7 +101,8 @@ func (id *EthereumIdentity) FetchKey(key []byte) (Key, error) { if err != nil { return nil, err } - opts := ethereum.GetGethCallOpts() + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := ethereum.GetGethCallOpts() key32, _ := utils.SliceToByte32(key) keyInstance, err := contract.GetKey(opts, key32) if err != nil { @@ -135,7 +136,8 @@ func (id *EthereumIdentity) findContract() (exists bool, err error) { return true, nil } - opts := ethereum.GetGethCallOpts() + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := ethereum.GetGethCallOpts() idAddress, err := id.RegistryContract.GetIdentityByCentrifugeId(opts, id.CentrifugeId.BigInt()) if err != nil { return false, err @@ -219,7 +221,8 @@ func (id *EthereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdenti if err != nil { return nil, err } - opts := ethereum.GetGethCallOpts() + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := ethereum.GetGethCallOpts() bigInt := big.NewInt(int64(keyPurpose)) keys, err := contract.GetKeysByPurpose(opts, bigInt) if err != nil { @@ -372,7 +375,8 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Address, error) { - opts := ethereum.GetGethCallOpts() + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := ethereum.GetGethCallOpts() address, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centID.BigInt()) if err != nil { return common.Address{}, err @@ -389,7 +393,7 @@ func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Id id := NewEthereumIdentity(centrifugeID, ids.registryContract, ids.config) exists, err := id.CheckIdentityExists() if !exists { - return id, fmt.Errorf("identity [%s] does not exist", id.CentrifugeId) + return id, fmt.Errorf("identity [%s] does not exist with err [%v]", id.CentrifugeId, err) } if err != nil { diff --git a/resources/data.go b/resources/data.go index f7a93bf60..80111fde7 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\x49\x77\xdb\xbc\x0e\xdd\xeb\x57\xe0\x38\x9b\xf7\x16\xb1\x35\x58\xb2\xad\x5d\xc6\xaf\x83\x93\x67\x3b\x6e\xd3\x64\x47\x91\x90\xc5\x5a\x22\x15\x92\xf2\xd0\x5f\xff\x0e\x29\x29\xcd\xd0\xe1\xcb\x4a\xc7\x04\x2e\x70\x81\x0b\x20\x27\x70\x89\x39\x69\x4a\x03\x0c\x77\x58\xca\xba\x42\x61\xc0\xa0\x36\x02\x0d\x90\x0d\xe1\x42\x1b\x50\x5c\x6c\x31\x3b\x7a\x14\x85\x51\x3c\x6f\x36\x78\x8b\x66\x2f\xd5\x36\x05\xd5\x68\xcd\x89\x28\x78\x59\x7a\x0e\x8c\x0b\x04\x53\x20\xb0\x0e\x57\xb4\x96\x1a\x4c\x41\x0c\x5c\x3c\x23\x40\x45\xb8\x30\x16\xdf\xeb\x4d\x52\x0f\xe0\x04\xe6\x92\x92\xd2\xa5\xc0\xc5\x06\xa8\x14\x46\x11\x6a\x80\x30\xa6\x50\x6b\xd4\x20\x10\x19\x18\x09\x19\x82\x46\x03\x7b\x6e\x0a\x40\xb1\x83\x1d\x51\x9c\x64\x25\xea\xa1\x07\xbd\xbf\x85\x04\xe0\x2c\x85\x28\x8a\xdc\x37\x9a\x02\x15\x36\x55\xc7\xe0\x23\x4b\x61\x1a\x4d\xdb\xb7\x4c\x4a\xa3\x8d\x22\xf5\x02\x51\xe9\xd6\x17\xe0\x14\x06\x23\x5e\x8f\x47\x41\x38\x19\xfa\x43\x7f\x18\x8c\x0c\xad\x47\xd1\x34\xf4\xc3\x11\xaf\x73\x3d\x5a\x56\xeb\xe5\x21\xdb\x6f\x9b\xc7\x87\x87\xcb\xbc\xf9\xb1\xce\x0e\x57\x67\x2b\x5c\xdf\x5e\xcc\xe5\x8f\xe3\x31\x8e\xa7\xbb\xa5\xd8\x7c\xdd\x2d\x6e\xbe\xcf\x1f\xb6\x83\xbf\xc2\x46\x3d\xec\xd7\x3c\xb9\xba\x4d\xaa\xed\xd3\x3d\x7e\xbf\xff\x7c\x1f\x3e\x2d\x9a\x20\xf9\x56\xb3\x7f\xa2\xed\x27\x19\xac\xa3\xaa\x20\xc5\xe2\x3c\xbe\xc3\x58\x04\x2d\x6c\x5f\xae\xb3\xbe\x5a\x3d\x09\xce\x50\x18\x6e\x8e\xd7\x84\x1a\xa9\x8e\x29\x0c\x06\x6f\x5e\x56\xb8\xe1\xda\xbc\x7a\x22\x82\x16\x52\xad\xb0\x96\x9a\xbf\xf1\xaa\xc9\xd1\x4a\xe5\x7f\x59\xc9\x37\xc4\x70\x29\xdc\x9b\x6b\xe0\x0d\xe1\xe2\x97\x72\xea\xfa\xec\xc1\x4b\xd5\xb4\x09\x9e\xc0\x6d\x53\xa1\xe2\x14\x3e\x5e\x82\xcc\x9d\x82\x5e\x68\xe5\xa7\x67\xdb\xcc\x38\xe8\xbc\xce\xfb\x8e\x41\xc9\xb5\xb1\x9e\x42\x32\x7c\x2f\xb6\x5a\xc9\x1d\x77\x0f\xd2\x61\xbf\x48\xa0\x4f\xef\x5f\x28\x20\x8a\x87\x61\x18\x0f\x43\xdf\x1f\x8e\xc3\xb7\x2a\x08\xc2\xcb\xe8\xb3\x94\xf7\x73\xce\xe9\xf2\xeb\x7e\x5d\xac\xcf\x1f\x92\xc3\x67\xba\x90\xf3\x3c\x59\x2d\x1f\x3e\x5d\xd7\xfb\x3c\x50\x93\x78\x3f\x3f\x84\x8f\xab\xa8\xbe\x60\xc1\x5b\x2d\x74\x01\xa6\xc9\x30\x0c\xfc\xdf\x05\x58\x3e\xde\x9c\x4d\xff\x59\x7c\x50\xbb\xab\xc7\xf3\xd9\x9e\x6d\xe5\x17\x7a\x76\x56\x5d\x3c\x7e\xa8\x67\x78\x3c\x3e\x8e\xef\xae\xa6\x9b\x6b\x15\x15\xeb\xdb\x6f\x83\xae\x4e\x57\x9d\xea\xfb\x4a\xda\x32\x9f\xc2\xaa\x9b\xeb\xdf\xcc\xc5\xb8\x73\x9e\x13\x5b\x22\x60\x58\x97\xf2\x88\x0c\xee\x2a\xa2\x0c\x5c\x74\x52\xd3\x90\x4b\xe5\x8a\xba\xe1\x3b\x14\xaf\xca\xf9\x5e\x8e\xf0\x5b\x3d\xfa\x87\x99\xcf\xc2\xd9\x38\x9e\x04\x38\x89\xa6\xe3\x30\x99\x4d\x48\x92\x64\x13\x32\x9b\x11\x7f\xc6\x58\x42\x27\x11\x8b\xe2\x84\xfd\x41\xb9\xfe\x61\x96\x24\x3e\xf5\xa3\x19\x8b\x82\x60\x1c\x47\x24\xf7\x59\x3c\xa5\x71\x92\x24\x93\x30\x62\x33\x1a\xe6\x64\xc2\x12\xa4\x7f\xd0\xb8\x7f\x98\xe4\xd3\x78\xcc\x72\x32\x9b\xfa\x41\xc8\x26\x39\x89\x63\x3a\xf5\xa3\x2c\x23\x61\x98\xf8\x19\x65\x88\xe3\x2c\x46\xf6\x97\x69\x38\x01\x2b\xa3\x53\x23\x4f\x6b\x44\x65\xab\x91\xf3\x4d\xa3\x9c\x85\xf6\xea\xb0\x6e\x37\xde\x9a\x57\x28\x1b\x03\xfb\x02\x05\xc8\x1a\x45\xb7\xf8\x04\x52\x67\x69\x45\x6b\x01\xb4\x07\xfd\xcf\x9d\x4b\x0a\x83\xc8\xd7\x2e\xd2\xb2\xc1\x06\xdf\x84\x70\x9d\x21\xfa\x28\x68\xa1\xa4\x90\x8d\xb6\x73\x40\x51\x6b\x2e\x36\xde\x93\x75\x68\x13\x68\xd7\xb6\x76\x4d\x14\x4d\x95\xa1\xb2\x93\x64\x65\x80\x4a\x8f\xa8\x14\xda\x0e\x67\x37\x55\x7b\x3b\x33\x19\x02\x29\x4b\x49\x89\x41\x06\xc4\x80\x36\x44\x99\xa6\xf6\xc0\xfa\xdf\xb7\x8e\x29\x84\x0e\xfd\x5a\x21\x6a\x68\x6a\xb8\x58\x7c\x01\x7a\xa4\x25\xea\x96\x6a\x1b\x00\xb8\x86\x3d\xe1\x6e\xdb\xdb\x7c\x71\x87\xc2\x58\xaa\xed\xf3\x3d\xe1\x8e\xed\xcd\x5d\x0a\x81\x25\xfa\x2c\x65\x5d\x23\xe5\x39\xa7\xaf\x49\x7b\xbd\x90\x5b\x6a\x77\x58\xa2\xd5\xe8\xbe\xe0\xb4\x78\x16\x39\x10\x4a\x65\x63\x57\x93\x84\x46\x63\xbf\x71\xa4\x2d\x42\xb7\x2a\x18\x70\xe1\x7e\xa4\x8d\x36\xb2\xea\x82\x40\xce\x4b\xf4\xa0\xbf\x6e\x67\x2d\xcc\x2d\xa9\x30\x85\x81\xbd\x68\x83\xe7\x1b\x66\x93\xe9\x81\x9f\xe3\xd2\x92\xdb\x8d\x68\x97\x14\xfc\x67\x8f\xa0\xf0\xa9\xe1\x0a\x61\xaf\x41\x2a\xe0\x35\xed\x0e\x9b\xbd\x63\xf6\x93\x12\x63\xd3\x76\x25\xf9\xaf\xad\xae\x64\xf8\x65\x35\x4f\x61\xaf\xd3\xd1\xc8\x36\xa0\x2c\xa4\x36\xe9\x2c\x1e\x27\x7d\x2b\xdd\xd9\xdd\x10\xcb\x84\x53\x9b\xec\x86\xe8\x85\xfd\x4c\x21\xf0\xfb\xbf\x77\xc6\x25\xaf\xb8\x69\x8d\xe7\xf6\x33\x85\xf1\x24\x08\xa3\xe9\xf4\x95\x44\x8d\x74\xbd\x6a\x85\x25\x7e\xf2\x32\x8a\x08\x4d\x9c\x5c\x7b\x06\x8c\xb5\x67\x9a\x40\x56\x4a\xba\x05\x22\x58\x47\x04\x8c\xe2\x9b\x0d\x2a\x64\xad\xa0\x0d\x1e\x4c\xdf\xe6\x56\xd4\x89\x6f\x55\xed\xce\x82\xad\xd4\x4b\xf4\x5a\xca\x12\x2a\x72\x00\x85\x46\xf1\x76\xa3\x6b\x14\x0c\xc8\x2b\x33\xb9\x43\xe5\x81\x35\x5c\xb5\x76\x29\x84\x1d\xeb\x5f\x43\x72\x61\x50\xed\x48\xe9\x70\x8f\xad\x40\x89\xcd\x8e\x36\x4a\xb9\x2b\xf6\xc2\xa3\x20\x1a\x32\x44\x7b\xe6\x0c\x52\xe3\x88\xf4\x00\x36\x9e\xdd\x22\x61\xc7\xe0\x92\x6b\xd7\x4d\x87\xa8\x65\xf5\x4e\x0d\x1a\x98\x04\x21\x0d\xe8\xa6\xae\xa5\x32\x60\x0e\x2e\x23\x52\x73\xfb\x8f\xcc\x61\x21\x65\x79\x46\xed\xd8\x5e\x09\x8b\xc4\x52\x30\xaa\x41\xcf\xfb\x7f\x00\x00\x00\xff\xff\x2d\xa4\xea\x9a\xbd\x09\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\xc9\x76\xdb\x3a\x0f\xde\xeb\x29\x70\x9c\xcd\xff\x2f\x62\x6b\xb0\x64\x5b\xbb\x8c\x9d\x9c\x5c\xc7\x71\x9b\x26\x3b\x8a\x84\x2c\xd6\x12\xa9\x90\x94\x87\x3e\xfd\x3d\xa4\xa4\x34\x43\xd3\x5e\xaf\x78\x0c\xe0\xc3\xf4\x01\xd0\x11\x9c\x63\x4e\x9a\xd2\x00\xc3\x2d\x96\xb2\xae\x50\x18\x30\xa8\x8d\x40\x03\x64\x4d\xb8\xd0\x06\x14\x17\x1b\xcc\x0e\x1e\x45\x61\x14\xcf\x9b\x35\x5e\xa3\xd9\x49\xb5\x49\x41\x35\x5a\x73\x22\x0a\x5e\x96\x9e\x03\xe3\x02\xc1\x14\x08\xac\xc3\x15\xad\xa6\x06\x53\x10\x03\x67\x4f\x08\x50\x11\x2e\x8c\xc5\xf7\x7a\x95\xd4\x03\x38\x82\xb9\xa4\xa4\x74\x21\x70\xb1\x06\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x86\xa0\xd1\xc0\x8e\x9b\x02\x50\x6c\x61\x4b\x14\x27\x59\x89\x7a\xe8\x41\x6f\x6f\x21\x01\x38\x4b\x21\x8a\x22\xf7\x46\x53\xa0\xc2\xa6\xea\x32\xf8\xc4\x52\x98\x46\xd3\x56\x96\x49\x69\xb4\x51\xa4\x5e\x20\x2a\xdd\xda\x02\x1c\xc3\x60\xc4\xeb\xf1\x28\x08\x27\x43\x7f\xe8\x0f\x83\x91\xa1\xf5\x28\x9a\x86\x7e\x38\xe2\x75\xae\x47\x37\xd5\xea\x66\x9f\xed\x36\xcd\xc3\xfd\xfd\x79\xde\xfc\x5c\x65\xfb\x8b\x93\x25\xae\xae\xcf\xe6\xf2\xe7\xe1\x10\xc7\xd3\xed\x8d\x58\x7f\xdb\x2e\xae\x7e\xcc\xef\x37\x83\xbf\xc2\x46\x3d\xec\xb7\x3c\xb9\xb8\x4e\xaa\xcd\xe3\x1d\xfe\xb8\xfb\x72\x17\x3e\x2e\x9a\x20\xf9\x5e\xb3\x0f\xd1\xe6\xb3\x0c\x56\x51\x55\x90\x62\x71\x1a\xdf\x62\x2c\x82\x16\xb6\x2f\xd7\x49\x5f\xad\x3e\x09\xce\x50\x18\x6e\x0e\x97\x84\x1a\xa9\x0e\x29\x0c\x06\xaf\x24\x4b\x5c\x73\x6d\x5e\x88\x88\xa0\x85\x54\x4b\xac\xa5\xe6\xaf\xac\x6a\x72\xb0\x54\xf9\x27\x2b\xf9\x9a\x18\x2e\x85\x93\xb9\x06\x5e\x11\x2e\x7e\x4b\xa7\xae\xcf\x1e\x3c\x67\x4d\x1b\xe0\x11\x5c\x37\x15\x2a\x4e\xe1\xd3\x39\xc8\xdc\x31\xe8\x19\x57\x7e\x59\xb6\xcd\x8c\x83\xce\xea\xb4\xef\x18\x94\x5c\x1b\x6b\x29\x24\xc3\xb7\x64\xab\x95\xdc\x72\x27\x90\x0e\xfb\x59\x00\x7d\x78\xff\x81\x01\x51\x3c\x0c\xc3\x78\x18\xfa\xfe\x70\x1c\xbe\x66\x41\x10\x9e\x47\x5f\xa4\xbc\x9b\x73\x4e\x6f\xbe\xed\x56\xc5\xea\xf4\x3e\xd9\x7f\xa1\x0b\x39\xcf\x93\xe5\xcd\xfd\xe7\xcb\x7a\x97\x07\x6a\x12\xef\xe6\xfb\xf0\x61\x19\xd5\x67\x2c\x78\xcd\x85\xce\xc1\x34\x19\x86\x81\xff\x9e\x83\x9b\x87\xab\x93\xe9\x87\xc5\x47\xb5\xbd\x78\x38\x9d\xed\xd8\x46\x7e\xa5\x27\x27\xd5\xd9\xc3\xc7\x7a\x86\x87\xc3\xc3\xf8\xf6\x62\xba\xbe\x54\x51\xb1\xba\xfe\x3e\xe8\xea\x74\xd1\xb1\xbe\xaf\xa4\x2d\xf3\x31\x2c\xbb\xb9\x7e\x67\x2e\xc6\x9d\xf1\x9c\xd8\x12\x01\xc3\xba\x94\x07\x64\x70\x5b\x11\x65\xe0\xac\xa3\x9a\x86\x5c\x2a\x57\xd4\x35\xdf\xa2\x78\x51\xce\xb7\x74\x84\x77\xf9\xe8\xef\x67\x3e\x0b\x67\xe3\x78\x12\xe0\x24\x9a\x8e\xc3\x64\x36\x21\x49\x92\x4d\xc8\x6c\x46\xfc\x19\x63\x09\x9d\x44\x2c\x8a\x13\xf6\x07\xe6\xfa\xfb\x59\x92\xf8\xd4\x8f\x66\x2c\x0a\x82\x71\x1c\x91\xdc\x67\xf1\x94\xc6\x49\x92\x4c\xc2\x88\xcd\x68\x98\x93\x09\x4b\x90\xfe\x81\xe3\xfe\x7e\x92\x4f\xe3\x31\xcb\xc9\x6c\xea\x07\x21\x9b\xe4\x24\x8e\xe9\xd4\x8f\xb2\x8c\x84\x61\xe2\x67\x94\x21\x8e\xb3\x18\xd9\x5f\xa6\xe1\x08\x2c\x8d\x8e\x8d\x3c\xae\x11\x95\xad\x46\xce\xd7\x8d\x72\x1a\xda\xab\xc3\xba\xdd\x78\x2b\x5e\xa1\x6c\x0c\xec\x0a\x14\x20\x6b\x14\xdd\xe2\x13\x48\x9d\xa6\x25\xad\x05\xd0\x1e\xf4\x7f\x77\x26\x29\x0c\x22\x5f\x3b\x4f\x37\x0d\x36\xf8\xca\x85\xeb\x0c\xd1\x07\x41\x0b\x25\x85\x6c\xb4\x9d\x03\x8a\x5a\x73\xb1\xf6\x1e\xad\x41\x1b\x40\xbb\xb6\xb5\x6b\xa2\x68\xaa\x0c\x95\x9d\x24\x4b\x03\x54\x7a\x44\xa5\xd0\x76\x38\xbb\xa9\xda\xd9\x99\xc9\x10\x48\x59\x4a\x4a\x0c\x32\x20\x06\xb4\x21\xca\x34\xb5\x07\xd6\xfe\xae\x35\x4c\x21\x74\xe8\x97\x0a\x51\x43\x53\xc3\xd9\xe2\x2b\xd0\x03\x2d\x51\xb7\xa9\xb6\x0e\x80\x6b\xd8\x11\xee\xb6\xbd\x8d\x17\xb7\x28\x8c\x4d\xb5\x15\xdf\x11\xee\xb2\xbd\xba\x4d\x21\xb0\x89\x3e\x51\x59\xd7\x48\x79\xce\xe9\xcb\xa4\xbd\x9e\xc8\x6d\x6a\xb7\x58\xa2\xe5\xe8\xae\xe0\xb4\x78\x22\x39\x10\x4a\x65\x63\x57\x93\x84\x46\x63\xbf\x71\xa4\x2d\x42\xb7\x2a\x18\x70\xe1\xfe\xa4\x8d\x36\xb2\xea\x9c\x40\xce\x4b\xf4\xa0\xbf\x6e\x27\x2d\xcc\x35\xa9\x30\x85\x81\xbd\x68\x83\xa7\x1b\x66\x83\xe9\x81\x9f\xfc\xd2\x92\xdb\x8d\x68\x97\x14\xfc\x6f\x87\xa0\xf0\xb1\xe1\x0a\x61\xa7\x41\x2a\xe0\x35\xed\x0e\x9b\xbd\x63\xf6\x49\x89\xb1\x61\xbb\x92\xfc\xdf\x56\x57\x32\xfc\xba\x9c\xa7\xb0\xd3\xe9\x68\x64\x1b\x50\x16\x52\x9b\x74\x16\x8f\x93\xbe\x95\xee\xec\xae\x89\xcd\x84\x53\x1b\xec\x9a\xe8\x85\x7d\xa6\x10\xf8\xfd\xef\x8d\x72\xc9\x2b\x6e\x5a\xe5\xb9\x7d\xa6\x30\x9e\x04\x61\x34\x9d\xbe\xa0\xa8\x91\xae\x57\x2d\xb1\xc4\xaf\xbc\x8c\x22\x42\x13\x47\xd7\x3e\x03\xc6\xda\x33\x4d\x20\x2b\x25\xdd\x00\x11\xac\x4b\x04\x8c\xe2\xeb\x35\x2a\x64\x2d\xa1\x0d\xee\x4d\xdf\xe6\x96\xd4\x89\x6f\x59\xfd\x9e\x63\x85\x84\x81\x14\xe5\xc1\x0e\x4b\x4f\xf5\xfe\x5b\xa5\x0f\xe9\x17\xf4\x12\x09\x7b\x09\x1f\xc4\x1d\xfa\xb5\xed\xc3\xf3\xd8\x6b\x29\x4b\xa8\xc8\x1e\x14\x1a\xc5\xdb\x7b\xa1\x51\x30\x20\x2f\xd4\xe4\x16\x95\x07\x56\x71\xd9\xea\xa5\x10\x76\x35\xfd\x3d\x24\x17\x06\xd5\x96\x94\x0e\xf7\xd0\xd2\x9f\xd8\x00\x69\xa3\x94\xbb\x91\xcf\x2c\x0a\xa2\x21\x43\xb4\x47\xd4\x20\x35\xae\x4c\x3d\x80\xf5\x67\x77\x54\xd8\x65\x70\xce\xb5\xe3\x8a\x43\xd4\xb2\x7a\xc3\x35\x0d\x4c\x82\x90\x06\x74\x53\xd7\x52\x19\x30\x7b\x17\x11\xa9\xb9\xfd\x4c\xda\x2f\xa4\x2c\x4f\xa8\x5d\x0a\x17\xc2\x22\xb1\x14\x8c\x6a\xd0\xf3\xfe\x0d\x00\x00\xff\xff\x0a\x16\x18\x68\x1b\x0a\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 2493, mode: os.FileMode(420), modTime: time.Unix(1540814510, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 2587, mode: os.FileMode(420), modTime: time.Unix(1540892585, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From 9e0ad4d6222f52038c5d740e4777eb8d099d9b49 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 31 Oct 2018 10:53:29 +0100 Subject: [PATCH 006/220] Flatten Core document and P2P packages (#385) --- coredocument/coredocument_test.go | 5 -- coredocument/{processor => }/processor.go | 29 ++++++----- .../{processor => }/processor_test.go | 48 +++++++------------ coredocument/validator_test.go | 13 +---- documents/invoice/bootstrapper.go | 4 +- documents/invoice/service.go | 5 +- documents/purchaseorder/bootstrapper.go | 4 +- documents/purchaseorder/service.go | 5 +- p2p/client.go | 3 +- p2p/{p2phandler => }/handler.go | 2 +- .../handler_integration_test.go | 12 +++-- p2p/{p2phandler => }/handler_test.go | 18 +------ p2p/server.go | 3 +- p2p/{p2phandler => }/validator.go | 2 +- p2p/{p2phandler => }/validator_test.go | 2 +- 15 files changed, 59 insertions(+), 96 deletions(-) rename coredocument/{processor => }/processor.go (91%) rename coredocument/{processor => }/processor_test.go (93%) rename p2p/{p2phandler => }/handler.go (99%) rename p2p/{p2phandler => }/handler_integration_test.go (96%) rename p2p/{p2phandler => }/handler_test.go (93%) rename p2p/{p2phandler => }/validator.go (99%) rename p2p/{p2phandler => }/validator_test.go (99%) diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 4c01639f9..78e563232 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -23,10 +22,6 @@ var ( id3 = utils.RandomSlice(32) id4 = utils.RandomSlice(32) id5 = utils.RandomSlice(32) - - centID = utils.RandomSlice(identity.CentIDLength) - key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) func TestGetSigningProofHashes(t *testing.T) { diff --git a/coredocument/processor/processor.go b/coredocument/processor.go similarity index 91% rename from coredocument/processor/processor.go rename to coredocument/processor.go index 2fb58bba1..94d39902e 100644 --- a/coredocument/processor/processor.go +++ b/coredocument/processor.go @@ -1,4 +1,4 @@ -package coredocumentprocessor +package coredocument import ( "context" @@ -9,12 +9,10 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" - "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" @@ -34,15 +32,22 @@ type Processor interface { SendDocument(ctx context.Context, model documents.Model) error } +// client defines the methods for p2pclient +// we redefined it here so that we can avoid cyclic dependencies with p2p +type client interface { + OpenClient(target string) (p2ppb.P2PServiceClient, error) + GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error +} + // defaultProcessor implements Processor interface type defaultProcessor struct { IdentityService identity.Service - P2PClient p2p.Client + P2PClient client AnchorRepository anchors.AnchorRepository } // DefaultProcessor returns the default implementation of CoreDocument Processor -func DefaultProcessor(idService identity.Service, p2pClient p2p.Client, repository anchors.AnchorRepository) Processor { +func DefaultProcessor(idService identity.Service, p2pClient client, repository anchors.AnchorRepository) Processor { return defaultProcessor{ IdentityService: idService, P2PClient: p2pClient, @@ -111,7 +116,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) er } // calculate the signing root - err = coredocument.CalculateSigningRoot(cd) + err = CalculateSigningRoot(cd) if err != nil { return fmt.Errorf("failed to calculate signing root: %v", err) } @@ -140,7 +145,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model document return fmt.Errorf("failed to pack core document: %v", err) } - psv := coredocument.PreSignatureRequestValidator() + psv := PreSignatureRequestValidator() err = psv.Validate(nil, model) if err != nil { return fmt.Errorf("failed to validate model for signature request: %v", err) @@ -166,13 +171,13 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { return fmt.Errorf("failed to pack core document: %v", err) } - psv := coredocument.PostSignatureRequestValidator() + psv := PostSignatureRequestValidator() err = psv.Validate(nil, model) if err != nil { return fmt.Errorf("failed to validate signatures: %v", err) } - err = coredocument.CalculateDocumentRoot(cd) + err = CalculateDocumentRoot(cd) if err != nil { return fmt.Errorf("failed to generate document root: %v", err) } @@ -192,7 +197,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to pack core document: %v", err) } - pav := coredocument.PreAnchorValidator() + pav := PreAnchorValidator() err = pav.Validate(nil, model) if err != nil { return fmt.Errorf("pre anchor validation failed: %v", err) @@ -247,13 +252,13 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Mod return fmt.Errorf("failed to pack core document: %v", err) } - av := coredocument.PostAnchoredValidator(dp.AnchorRepository) + av := PostAnchoredValidator(dp.AnchorRepository) err = av.Validate(nil, model) if err != nil { return fmt.Errorf("post anchor validations failed: %v", err) } - extCollaborators, err := coredocument.GetExternalCollaborators(cd) + extCollaborators, err := GetExternalCollaborators(cd) if err != nil { return fmt.Errorf("get external collaborators failed: %v", err) } diff --git a/coredocument/processor/processor_test.go b/coredocument/processor_test.go similarity index 93% rename from coredocument/processor/processor_test.go rename to coredocument/processor_test.go index 764c4ed66..7041e1a0f 100644 --- a/coredocument/processor/processor_test.go +++ b/coredocument/processor_test.go @@ -1,23 +1,19 @@ // +build unit -package coredocumentprocessor +package coredocument import ( "context" "fmt" "math/big" - "os" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" - "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -29,16 +25,6 @@ import ( var dp defaultProcessor -func TestMain(m *testing.M) { - dp = defaultProcessor{} - ibootstappers := []bootstrap.TestBootstrapper{ - &config.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - result := m.Run() - os.Exit(result) -} - func TestCoreDocumentProcessor_SendNilDocument(t *testing.T) { err := dp.Send(nil, nil, [identity.CentIDLength]byte{}) assert.Error(t, err, "should have thrown an error") @@ -75,13 +61,13 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // failed to get id pub, _ := config.Config.GetSigningKeyPair() config.Config.V.Set("keys.signing.publicKey", "wrong path") - cd = coredocument.New() + cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) + assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() err = dp.PrepareForSignatureRequests(model) @@ -117,7 +103,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { type p2pClient struct { mock.Mock - p2p.Client + client } func (p p2pClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { @@ -145,13 +131,13 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { assert.Contains(t, err.Error(), "failed to validate model for signature request") // failed signature collection - cd = coredocument.New() + cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) + assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() @@ -214,14 +200,14 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { assert.Contains(t, err.Error(), "failed to validate signatures") // failed unpack - cd = coredocument.New() + cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) - err = coredocument.CalculateSigningRoot(cd) + assert.Nil(t, FillSalts(cd)) + err = CalculateSigningRoot(cd) assert.Nil(t, err) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) @@ -306,21 +292,21 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Contains(t, err.Error(), "pre anchor validation failed") // get ID failed - cd = coredocument.New() + cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd)) + assert.Nil(t, FillSalts(cd)) + assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) c, err := cented25519.GetIDConfig() assert.Nil(t, err) s := signatures.Sign(c, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) + assert.Nil(t, CalculateDocumentRoot(cd)) pubkey, err := utils.SliceToByte32(c.PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ @@ -432,22 +418,22 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Contains(t, err.Error(), "post anchor validations failed") // failed send - cd = coredocument.New() + cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } cd.Collaborators = [][]byte{[]byte("some id")} - assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd)) + assert.Nil(t, FillSalts(cd)) + assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(6) c, err := cented25519.GetIDConfig() assert.Nil(t, err) s := signatures.Sign(c, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) + assert.Nil(t, CalculateDocumentRoot(cd)) pubkey, err := utils.SliceToByte32(c.PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index f7dae91cf..4e5b4fe5c 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -33,22 +33,13 @@ func TestMain(m *testing.M) { flag.Parse() config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) } -type mockModel struct { - mock.Mock - documents.Model -} - -func (m mockModel) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { - args := m.Called() - cd, _ := args.Get(0).(*coredocumentpb.CoreDocument) - return cd, args.Error(1) -} - func TestUpdateVersionValidator(t *testing.T) { uvv := UpdateVersionValidator() diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 395682a46..f5dd211e0 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -7,7 +7,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/coredocument/processor" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" @@ -22,7 +22,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } // register service - srv := DefaultService(getRepository(), coredocumentprocessor.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) + srv := DefaultService(getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index aec19c6e0..2dd3047be 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -13,7 +13,6 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/coredocument/processor" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" centED25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" @@ -54,13 +53,13 @@ type Service interface { // service always returns errors of type `centerrors` with proper error code type service struct { repo documents.Repository - coreDocProcessor coredocumentprocessor.Processor + coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository } // DefaultService returns the default implementation of the service -func DefaultService(repo documents.Repository, processor coredocumentprocessor.Processor, anchorRepository anchors.AnchorRepository) Service { +func DefaultService(repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { return service{repo: repo, coreDocProcessor: processor, notifier: ¬ification.WebhookSender{}, anchorRepository: anchorRepository} } diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index f84205219..4bb36d372 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -7,7 +7,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/coredocument/processor" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" @@ -22,7 +22,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } // register service - srv := DefaultService(getRepository(), coredocumentprocessor.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) + srv := DefaultService(getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index a6ac17bb6..9fcd56d6b 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -13,7 +13,6 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/coredocument/processor" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" centED25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" @@ -54,13 +53,13 @@ type Service interface { // service always returns errors of type `centerrors` with proper error code type service struct { repo documents.Repository - coreDocProcessor coredocumentprocessor.Processor + coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository } // DefaultService returns the default implementation of the service -func DefaultService(repo documents.Repository, processor coredocumentprocessor.Processor, anchorRepository anchors.AnchorRepository) Service { +func DefaultService(repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { return service{repo: repo, coreDocProcessor: processor, notifier: ¬ification.WebhookSender{}, anchorRepository: anchorRepository} } diff --git a/p2p/client.go b/p2p/client.go index ab8e9fcc4..78dd65231 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -28,8 +28,7 @@ func NewP2PClient() Client { return &defaultClient{} } -type defaultClient struct { -} +type defaultClient struct{} // Opens a client connection with libp2p func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error) { diff --git a/p2p/p2phandler/handler.go b/p2p/handler.go similarity index 99% rename from p2p/p2phandler/handler.go rename to p2p/handler.go index 21b637ab7..3bec3544a 100644 --- a/p2p/p2phandler/handler.go +++ b/p2p/handler.go @@ -1,4 +1,4 @@ -package p2phandler +package p2p import ( "context" diff --git a/p2p/p2phandler/handler_integration_test.go b/p2p/handler_integration_test.go similarity index 96% rename from p2p/p2phandler/handler_integration_test.go rename to p2p/handler_integration_test.go index 6679696d7..a54f296e0 100644 --- a/p2p/p2phandler/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -1,9 +1,10 @@ // +build integration -package p2phandler_test +package p2p_test import ( "context" + "flag" "math/big" "os" "testing" @@ -19,7 +20,7 @@ import ( cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/p2p/p2phandler" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -31,10 +32,15 @@ import ( "golang.org/x/crypto/ed25519" ) -var handler = p2phandler.Handler{Notifier: ¬ification.WebhookSender{}} +var handler = p2p.Handler{Notifier: ¬ification.WebhookSender{}} func TestMain(m *testing.M) { cc.TestFunctionalEthereumBootstrap() + flag.Parse() + config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/p2p/p2phandler/handler_test.go b/p2p/handler_test.go similarity index 93% rename from p2p/p2phandler/handler_test.go rename to p2p/handler_test.go index 47bc1d483..f7d9ee410 100644 --- a/p2p/p2phandler/handler_test.go +++ b/p2p/handler_test.go @@ -1,26 +1,22 @@ // +build unit -package p2phandler +package p2p import ( "context" "fmt" - "os" "strconv" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/any" @@ -39,18 +35,6 @@ func (wh *MockWebhookSender) Send(notification *notificationpb.NotificationMessa return } -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &storage.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - var coreDoc = testingutils.GenerateCoreDocument() func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { diff --git a/p2p/server.go b/p2p/server.go index 9663d911b..5190e56a9 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/p2p/p2phandler" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-ipfs-addr" @@ -76,7 +75,7 @@ func (c *CentP2PServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr grpcProto := p2pgrpc.NewGRPCProtocol(context.Background(), hostInstance) GRPCProtoInstance = *grpcProto - p2ppb.RegisterP2PServiceServer(grpcProto.GetGRPCServer(), &p2phandler.Handler{Notifier: ¬ification.WebhookSender{}}) + p2ppb.RegisterP2PServiceServer(grpcProto.GetGRPCServer(), &Handler{Notifier: ¬ification.WebhookSender{}}) errOut := make(chan error) go func(proto *p2pgrpc.GRPCProtocol, errOut chan<- error) { errOut <- proto.Serve() diff --git a/p2p/p2phandler/validator.go b/p2p/validator.go similarity index 99% rename from p2p/p2phandler/validator.go rename to p2p/validator.go index 74fed95a0..14f2b79d2 100644 --- a/p2p/p2phandler/validator.go +++ b/p2p/validator.go @@ -1,4 +1,4 @@ -package p2phandler +package p2p import ( "fmt" diff --git a/p2p/p2phandler/validator_test.go b/p2p/validator_test.go similarity index 99% rename from p2p/p2phandler/validator_test.go rename to p2p/validator_test.go index a6b139ed3..ada43f4fd 100644 --- a/p2p/p2phandler/validator_test.go +++ b/p2p/validator_test.go @@ -1,6 +1,6 @@ // +build unit -package p2phandler +package p2p import ( "testing" From f680d10d231a20e6ae8afaed60aad5a115d621d0 Mon Sep 17 00:00:00 2001 From: Lucas Vogelsang Date: Wed, 31 Oct 2018 11:16:58 +0100 Subject: [PATCH 007/220] Fix Gopkg github repo URLs (#393) * Fix github links * try http --- Gopkg.lock | 9 +-------- Gopkg.toml | 8 +------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c5a7f5dc5..10024bd9d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -44,7 +44,6 @@ packages = ["."] pruneopts = "T" revision = "c60964592c1a2b83c5676878c937cdbe6719869d" - source = "git@github.com:centrifuge/centrifuge-ethereum-contracts" [[projects]] digest = "1:c6e2ed36c71d00b36eb36fa5b7aad8c06a1c07f58701557c4bb7b8e0084356d8" @@ -60,7 +59,6 @@ ] pruneopts = "T" revision = "838c11114163b6152d7b56574536f046b858e68d" - source = "git@github.com:centrifuge/centrifuge-protobufs" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" @@ -68,7 +66,6 @@ packages = ["."] pruneopts = "UT" revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" - source = "git@github.com:centrifuge/gocelery" [[projects]] digest = "1:9ecc8c63be5b2a2e9c4daefc265ea476757d91a04394fbb984bcdb3c652129da" @@ -79,7 +76,6 @@ ] pruneopts = "UT" revision = "c673e56ee0de0d721a10dee5cd2aa59015e4420a" - source = "git@github.com:centrifuge/precise-proofs" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" @@ -135,7 +131,6 @@ ] pruneopts = "T" revision = "89451f7c382ad2185987ee369f16416f89c28a7d" - source = "git@github.com:ethereum/go-ethereum" version = "v1.8.15" [[projects]] @@ -271,7 +266,6 @@ ] pruneopts = "T" revision = "8558711daa6c2853489043207b563dceacbc19cf" - source = "git@github.com:grpc-ecosystem/grpc-gateway" version = "v1.5.0" [[projects]] @@ -921,7 +915,7 @@ packages = ["."] pruneopts = "UT" revision = "04711f07389ecbca09d7999474dda4a88c955c73" - source = "git@github.com:vedhavyas/go-libp2p-grpc.git" + source = "github.com/vedhavyas/go-libp2p-grpc" [[projects]] digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9" @@ -1425,7 +1419,6 @@ "google.golang.org/genproto/googleapis/api/annotations", "google.golang.org/grpc", "google.golang.org/grpc/codes", - "google.golang.org/grpc/connectivity", "google.golang.org/grpc/credentials", "google.golang.org/grpc/grpclog", "google.golang.org/grpc/status", diff --git a/Gopkg.toml b/Gopkg.toml index db755fc10..fd0cf3084 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,12 +28,10 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - source = "git@github.com:centrifuge/centrifuge-protobufs" revision = "838c11114163b6152d7b56574536f046b858e68d" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - source = "git@github.com:centrifuge/centrifuge-ethereum-contracts" branch = "develop" [[constraint]] @@ -42,12 +40,10 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/precise-proofs" - source = "git@github.com:centrifuge/precise-proofs" revision = "c673e56ee0de0d721a10dee5cd2aa59015e4420a" [[constraint]] name = "github.com/centrifuge/gocelery" - source = "git@github.com:centrifuge/gocelery" revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" [[override]] @@ -56,7 +52,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/ethereum/go-ethereum" - source = "git@github.com:ethereum/go-ethereum" version = "1.8.15" [[override]] @@ -77,7 +72,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/grpc-ecosystem/grpc-gateway" - source = "git@github.com:grpc-ecosystem/grpc-gateway" version= "1.5.0" [[constraint]] @@ -222,7 +216,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/paralin/go-libp2p-grpc" - source = "git@github.com:vedhavyas/go-libp2p-grpc.git" + source = "github.com/vedhavyas/go-libp2p-grpc" revision = "04711f07389ecbca09d7999474dda4a88c955c73" [[constraint]] From 8d6ff1d460b7d740d3b16b491c1f10d8e272dde0 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 31 Oct 2018 11:56:32 +0100 Subject: [PATCH 008/220] Upgrading to Go 1.11.x (#391) --- .travis.yml | 2 +- Dockerfile | 2 +- Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53d1fdccd..7b69ec4bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.10.x + - 1.11.x # Maybe this helps with building branches in a fork go_import_path: github.com/centrifuge/go-centrifuge diff --git a/Dockerfile b/Dockerfile index d8699b68f..e8a9dbff3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10-alpine as builder +FROM golang:1.11-alpine as builder RUN apk update && apk add --no-cache openssh git jq curl gcc libc-dev build-base diff --git a/Makefile b/Makefile index 548f0dc76..9bc0ace25 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ build-linux-amd64: ## Build linux/amd64 build-linux-amd64: install-xgo @echo "Building amd64 with flags [${LD_FLAGS}]" @mkdir -p build/linux-amd64 - @xgo -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} . + @xgo -go 1.11.x -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} . @mv build/linux-amd64/go-centrifuge-linux-amd64 build/linux-amd64/go-centrifuge @tar -zcvf cent-api-linux-amd64-${TAG}.tar.gz -C build/linux-amd64/ . From 430099c01d89d85b19264ff32094ecce421de09f Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 1 Nov 2018 11:00:30 +0100 Subject: [PATCH 009/220] Identity Config cleanup (#396) * identity cleanup * 20byte for secp * some test --- config/configuration.go | 7 --- coredocument/coredocument.go | 11 ++-- coredocument/coredocument_test.go | 16 ++++++ coredocument/processor.go | 14 ++--- coredocument/processor_test.go | 47 +++++++--------- coredocument/validator.go | 6 +-- coredocument/validator_test.go | 15 +++--- documents/invoice/model.go | 2 +- documents/invoice/model_test.go | 2 +- documents/invoice/service.go | 7 ++- documents/invoice/service_test.go | 24 ++++++--- documents/model.go | 14 ++--- documents/purchaseorder/model.go | 2 +- documents/purchaseorder/model_test.go | 2 +- documents/purchaseorder/service.go | 7 ++- documents/purchaseorder/service_test.go | 24 ++++++--- identity/identity.go | 70 ++++++++++++++++-------- identity/identity_test.go | 71 +++++++++++++++++++++++-- keytools/ed25519/ed25519.go | 20 ------- keytools/ed25519/ed25519_test.go | 29 ---------- keytools/secp256k1/secp256k1.go | 25 --------- keytools/secp256k1/secp256k1_test.go | 29 ---------- p2p/handler_integration_test.go | 49 +++++++---------- signatures/signatures.go | 10 ++-- signatures/signatures_test.go | 15 ++++-- testingutils/utils.go | 18 +++---- 26 files changed, 261 insertions(+), 275 deletions(-) diff --git a/config/configuration.go b/config/configuration.go index 952312d23..2ebe27341 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -37,13 +37,6 @@ type AccountConfig struct { Password string } -// IdentityConfig holds ID, public and private key of a single entity -type IdentityConfig struct { - ID []byte - PublicKey []byte - PrivateKey []byte -} - // GetStoragePath returns the data storage backend func (c *Configuration) GetStoragePath() string { return c.V.GetString("storage.Path") diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index 80d160910..c2c7eab37 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -7,7 +7,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -212,13 +211,17 @@ func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, // GetExternalCollaborators returns collaborators of a document without the own centID func GetExternalCollaborators(doc *coredocumentpb.CoreDocument) ([][]byte, error) { var collabs [][]byte - idConfig, err := ed25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { - return nil, fmt.Errorf("failed to decode collaborator: %v", err) + return nil, fmt.Errorf("failed to get identity config: %v", err) } for _, collab := range doc.Collaborators { - if !utils.IsSameByteSlice(collab, idConfig.ID) { + collabID, err := identity.ToCentID(collab) + if err != nil { + return nil, fmt.Errorf("failed to convert to CentID: %v", err) + } + if !idConfig.ID.Equal(collabID) { collabs = append(collabs, collab) } } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 78e563232..2b6774cad 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -224,3 +225,18 @@ func TestGetExternalCollaborators(t *testing.T) { assert.NotNil(t, collaborators) assert.Equal(t, [][]byte{c1, c2}, collaborators) } + +func TestGetExternalCollaborators_ErrorConfig(t *testing.T) { + c1 := utils.RandomSlice(6) + c2 := utils.RandomSlice(6) + c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} + cd, err := NewWithCollaborators(c) + assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) + currentKeyPath, _ := config.Config.GetSigningKeyPair() + //Wrong path + config.Config.V.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + collaborators, err := GetExternalCollaborators(cd) + assert.NotNil(t, err) + assert.Nil(t, collaborators) + config.Config.V.Set("keys.signing.publicKey", currentKeyPath) +} diff --git a/coredocument/processor.go b/coredocument/processor.go index 94d39902e..8a908a7b2 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" @@ -86,15 +85,16 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp log.Infof("Done opening connection against [%s]\n", lastB58Key) - idConfig, err := ed25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { err = centerrors.Wrap(err, "failed to extract bytes") log.Error(err) return err } + centIDBytes, _ := idConfig.ID.MarshalBinary() header := &p2ppb.CentrifugeHeader{ - SenderCentrifugeId: idConfig.ID, + SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config.GetNetworkID(), } @@ -122,11 +122,11 @@ func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) er } // sign document with own key and append it to signatures - idConfig, err := ed25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { return fmt.Errorf("failed to get keys for signing: %v", err) } - sig := signatures.Sign(idConfig, cd.SigningRoot) + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) @@ -219,7 +219,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { } // generate message authentication code for the anchor call - secpIDConfig, err := secp256k1.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { return fmt.Errorf("failed to get eth keys: %v", err) } @@ -229,7 +229,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to get anchor ID: %v", err) } - mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), secpIDConfig.PrivateKey) + mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { return fmt.Errorf("failed to generate ethereum MAC: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 7041e1a0f..06ec431a8 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -13,7 +13,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -96,9 +95,9 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.NotNil(t, cd.Signatures) assert.Len(t, cd.Signatures, 1) sig := cd.Signatures[0] - id, err := cented25519.GetIDConfig() + id, err := identity.GetIdentityConfig() assert.Nil(t, err) - assert.True(t, ed25519.Verify(id.PublicKey, cd.SigningRoot, sig.Signature)) + assert.True(t, ed25519.Verify(id.Keys[identity.KeyPurposeSigning].PublicKey, cd.SigningRoot, sig.Signature)) } type p2pClient struct { @@ -212,11 +211,11 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() - c, err := cented25519.GetIDConfig() + c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, cd.SigningRoot) + s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - pubkey, err := utils.SliceToByte32(c.PublicKey) + pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ Key: pubkey, @@ -225,9 +224,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - centID, err := identity.ToCentID(c.ID) - assert.Nil(t, err) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv err = dp.PrepareForAnchoring(model) @@ -243,9 +240,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model.On("UnpackCoreDocument", cd).Return(nil).Once() id = &testingcommons.MockID{} srv = &testingcommons.MockIDService{} - centID, err = identity.ToCentID(c.ID) - assert.Nil(t, err) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv err = dp.PrepareForAnchoring(model) @@ -302,12 +297,12 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - c, err := cented25519.GetIDConfig() + c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, cd.SigningRoot) + s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} assert.Nil(t, CalculateDocumentRoot(cd)) - pubkey, err := utils.SliceToByte32(c.PublicKey) + pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ Key: pubkey, @@ -316,9 +311,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - centID, err := identity.ToCentID(c.ID) - assert.Nil(t, err) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv oldID := config.Config.V.GetString("identityId") @@ -334,7 +327,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // wrong ID model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv err = dp.AnchorDocument(model) @@ -350,7 +343,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { config.Config.V.Set("keys.ethauth.publicKey", "wrong path") model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv err = dp.AnchorDocument(model) @@ -364,7 +357,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // failed anchor commit model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv repo := mockRepo{} @@ -381,7 +374,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // success model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv repo = mockRepo{} @@ -429,12 +422,12 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(6) - c, err := cented25519.GetIDConfig() + c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, cd.SigningRoot) + s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} assert.Nil(t, CalculateDocumentRoot(cd)) - pubkey, err := utils.SliceToByte32(c.PublicKey) + pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ Key: pubkey, @@ -443,9 +436,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - centID, err := identity.ToCentID(c.ID) - assert.Nil(t, err) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv docRoot, err := anchors.NewDocRoot(cd.DocumentRoot) diff --git a/coredocument/validator.go b/coredocument/validator.go index e1e16967d..5e65f3858 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -7,7 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -212,12 +212,12 @@ func readyForSignaturesValidator() documents.Validator { return fmt.Errorf("expecting only one signature") } - c, err := ed25519.GetIDConfig() + c, err := identity.GetIdentityConfig() if err != nil { return fmt.Errorf("failed to get keys for signature calculation: %v", err) } - s := signatures.Sign(c, cd.SigningRoot) + s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { err = documents.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 4e5b4fe5c..38a9458c9 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -16,7 +16,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -262,9 +261,9 @@ func TestValidator_selfSignatureValidator(t *testing.T) { // success cd.SigningRoot = utils.RandomSlice(32) - c, err := ed25519.GetIDConfig() + c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s = signatures.Sign(c, cd.SigningRoot) + s = signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() @@ -307,11 +306,11 @@ func TestValidator_signatureValidator(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() cd.SigningRoot = utils.RandomSlice(32) - c, err := ed25519.GetIDConfig() + c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s = signatures.Sign(c, cd.SigningRoot) + s = signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - pubkey, err := utils.SliceToByte32(c.PublicKey) + pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) idkey := &identity.EthereumIdentityKey{ Key: pubkey, @@ -320,9 +319,7 @@ func TestValidator_signatureValidator(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - centID, err := identity.ToCentID(c.ID) - assert.Nil(t, err) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv err = ssv.Validate(nil, model) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 0b4b7b2f9..4c2ae2e07 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -162,7 +162,7 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload return err } - collaborators := append([]string{contextHeader.Self().String()}, payload.Collaborators...) + collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) i.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index fe9b1b342..c98a0f78d 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -199,7 +199,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Equal(t, inv.Payee[:], []byte{1, 2, 3, 3, 4, 5}) assert.Equal(t, inv.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, inv.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - id := contextHeader.Self() + id := contextHeader.Self().ID assert.Equal(t, inv.CoreDocument.Collaborators, [][]byte{id[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 2dd3047be..b0fefa17b 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -15,7 +15,6 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - centED25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/signatures" @@ -318,7 +317,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP return nil, centerrors.New(code.Unknown, err.Error()) } - collaborators := append([]string{contextHeader.Self().String()}, payload.Collaborators...) + collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) inv.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to prepare new version: %v", err)) @@ -340,12 +339,12 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - idConfig, err := centED25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) } - sig := signatures.Sign(idConfig, doc.SigningRoot) + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index a8f455df5..efd71d06e 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -16,7 +16,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -29,9 +28,9 @@ import ( ) var ( - centID = utils.RandomSlice(identity.CentIDLength) - key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + centIDBytes = utils.RandomSlice(identity.CentIDLength) + key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) type mockAnchorRepo struct { @@ -278,7 +277,7 @@ func mockSignatureCheck(i *Invoice, invSrv Service) identity.Service { mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() srv := &testingcommons.MockIDService{} id := &testingcommons.MockID{} - centID, _ := identity.ToCentID(centID) + centID, _ := identity.ToCentID(centIDBytes) srv.On("LookupIdentityForID", centID).Return(id, nil).Once() id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() return srv @@ -400,11 +399,20 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { return nil, err } - sig := signatures.Sign(&config.IdentityConfig{ - ID: centID, + centID, err := identity.ToCentID(centIDBytes) + assert.Nil(t, err) + signKey := identity.IdentityKey{ PublicKey: key1Pub[:], PrivateKey: key1, - }, corDoc.SigningRoot) + } + idConfig := &identity.IdentityConfig{ + ID: centID, + Keys: map[int]identity.IdentityKey{ + identity.KeyPurposeSigning: signKey, + }, + } + + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) corDoc.Signatures = append(corDoc.Signatures, sig) diff --git a/documents/model.go b/documents/model.go index 2f2f682e4..da436c9c3 100644 --- a/documents/model.go +++ b/documents/model.go @@ -6,7 +6,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" ) // Model is an interface to abstract away model specificness like invoice or purchaseOrder @@ -36,25 +35,20 @@ type Model interface { // Placeholder to pass custom request objects down the pipeline type ContextHeader struct { - self identity.CentID + self *identity.IdentityConfig } // NewContextHeader creates new instance of the request headers needed func NewContextHeader() (*ContextHeader, error) { - idConfig, err := ed25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { return nil, fmt.Errorf("failed to get id config: %v", err) } - self, err := identity.ToCentID(idConfig.ID) - if err != nil { - return nil, fmt.Errorf("failed to convert self to centID: %v", err) - } - - return &ContextHeader{self: self}, nil + return &ContextHeader{self: idConfig}, nil } // Self returns Self CentID -func (h *ContextHeader) Self() identity.CentID { +func (h *ContextHeader) Self() *identity.IdentityConfig { return h.self } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 55ab77986..ad057e6e2 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -159,7 +159,7 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu return err } - collaborators := append([]string{contextHeader.Self().String()}, payload.Collaborators...) + collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) p.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { return fmt.Errorf("failed to init core document: %v", err) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 9b10513c6..ee4ccd3f4 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -173,7 +173,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { assert.Equal(t, poModel.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - id := contextHeader.Self() + id := contextHeader.Self().ID assert.Equal(t, poModel.CoreDocument.Collaborators, [][]byte{id[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 9fcd56d6b..4b699d75e 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -15,7 +15,6 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - centED25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/signatures" @@ -187,7 +186,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdate return nil, centerrors.New(code.Unknown, err.Error()) } - collaborators := append([]string{ctxH.Self().String()}, payload.Collaborators...) + collaborators := append([]string{ctxH.Self().ID.String()}, payload.Collaborators...) po.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to prepare new version: %v", err)) @@ -338,12 +337,12 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp srvLog.Infof("coredoc received %x with signing root %x", cd.DocumentIdentifier, cd.SigningRoot) - idConfig, err := centED25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) } - sig := signatures.Sign(idConfig, cd.SigningRoot) + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 6cd20f594..aa2baed94 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -26,9 +25,9 @@ import ( ) var ( - centID = utils.RandomSlice(identity.CentIDLength) - key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + centIDBytes = utils.RandomSlice(identity.CentIDLength) + key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) type mockAnchorRepo struct { @@ -319,11 +318,20 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er return nil, err } - sig := signatures.Sign(&config.IdentityConfig{ - ID: centID, + centID, err := identity.ToCentID(centIDBytes) + assert.Nil(t, err) + signKey := identity.IdentityKey{ PublicKey: key1Pub[:], PrivateKey: key1, - }, corDoc.SigningRoot) + } + idConfig := &identity.IdentityConfig{ + ID: centID, + Keys: map[int]identity.IdentityKey{ + identity.KeyPurposeSigning: signKey, + }, + } + + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) corDoc.Signatures = append(corDoc.Signatures, sig) @@ -359,7 +367,7 @@ func mockSignatureCheck(i *PurchaseOrder, poSrv Service) identity.Service { mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() srv := &testingcommons.MockIDService{} id := &testingcommons.MockID{} - centID, _ := identity.ToCentID(centID) + centID, _ := identity.ToCentID(centIDBytes) srv.On("LookupIdentityForID", centID).Return(id, nil).Once() id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() return srv diff --git a/identity/identity.go b/identity/identity.go index a5a076e6b..8253a3ae1 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -31,6 +31,52 @@ var IDService Service type CentID [CentIDLength]byte +// IdentityConfig holds information about the identity +type IdentityConfig struct { + ID CentID + Keys map[int]IdentityKey +} + +// IdentityKey represents a key pair +type IdentityKey struct { + PublicKey []byte + PrivateKey []byte +} + +// GetIdentityConfig returns the identity and keys associated with the node +func GetIdentityConfig() (*IdentityConfig, error) { + centIDBytes, err := config.Config.GetIdentityID() + if err != nil { + return nil, err + } + centID, err := ToCentID(centIDBytes) + if err != nil { + return nil, err + } + + //ed25519 keys + keys := map[int]IdentityKey{} + pk, sk, err := ed25519.GetSigningKeyPairFromConfig() + if err != nil { + return nil, err + } + keys[KeyPurposeP2p] = IdentityKey{PublicKey: pk, PrivateKey: sk} + keys[KeyPurposeSigning] = IdentityKey{PublicKey: pk, PrivateKey: sk} + + //secp256k1 keys + pk, sk, err = secp256k1.GetEthAuthKeyFromConfig() + if err != nil { + return nil, err + } + pubKey, err := hexutil.Decode(secp256k1.GetAddress(pk)) + if err != nil { + return nil, err + } + keys[KeyPurposeEthMsgAuth] = IdentityKey{PublicKey: pubKey, PrivateKey: sk} + + return &IdentityConfig{ID: centID, Keys: keys}, nil +} + // ToCentID takes bytes and return CentID // errors out if bytes are empty, nil, or len(bytes) > CentIDLength func ToCentID(bytes []byte) (centID CentID, err error) { @@ -230,37 +276,19 @@ func ValidateKey(centrifugeId CentID, key []byte, purpose int) error { // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file func AddKeyFromConfig(purpose int) error { - var identityConfig *config.IdentityConfig - var err error - - switch purpose { - case KeyPurposeP2p: - identityConfig, err = ed25519.GetIDConfig() - case KeyPurposeSigning: - identityConfig, err = ed25519.GetIDConfig() - case KeyPurposeEthMsgAuth: - identityConfig, err = secp256k1.GetIDConfig() - default: - err = errors.New("option not supported") - } - - if err != nil { - return err - } - - centId, err := ToCentID(identityConfig.ID) + identityConfig, err := GetIdentityConfig() if err != nil { return err } - id, err := IDService.LookupIdentityForID(centId) + id, err := IDService.LookupIdentityForID(identityConfig.ID) if err != nil { return err } ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() defer cancel() - confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.PublicKey) + confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) if err != nil { return err } diff --git a/identity/identity_test.go b/identity/identity_test.go index 984af649d..8bda98118 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -6,14 +6,31 @@ import ( "context" "fmt" "math/big" + "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &config.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, nil) + config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + // mockID implements Identity type mockID struct { mock.Mock @@ -96,6 +113,55 @@ func (srv *mockIDService) CheckIdentityExists(centID CentID) (exists bool, err e return args.Bool(0), args.Error(1) } +func TestGetIdentityConfig_Success(t *testing.T) { + idConfig, err := GetIdentityConfig() + assert.Nil(t, err) + assert.NotNil(t, idConfig) + configId, err := config.Config.GetIdentityID() + assert.Nil(t, err) + idBytes, _ := idConfig.ID.MarshalBinary() + assert.Equal(t, idBytes, configId) + assert.Equal(t, 3, len(idConfig.Keys)) +} + +func TestGetIdentityConfig_Error(t *testing.T) { + //Wrong Hex + currentId := config.Config.V.GetString("identityId") + config.Config.V.Set("identityId", "ABCD") + idConfig, err := GetIdentityConfig() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "hex string without 0x prefix") + assert.Nil(t, idConfig) + config.Config.V.Set("identityId", currentId) + + //Wrong length + currentId = config.Config.V.GetString("identityId") + config.Config.V.Set("identityId", "0x0101010101") + idConfig, err = GetIdentityConfig() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") + assert.Nil(t, idConfig) + config.Config.V.Set("identityId", currentId) + + //Wrong public signing key path + currentKeyPath, _ := config.Config.GetSigningKeyPair() + config.Config.V.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + idConfig, err = GetIdentityConfig() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "no such file or directory") + assert.Nil(t, idConfig) + config.Config.V.Set("keys.signing.publicKey", currentKeyPath) + + //Wrong public ethauth key path + currentKeyPath, _ = config.Config.GetEthAuthKeyPair() + config.Config.V.Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") + idConfig, err = GetIdentityConfig() + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "no such file or directory") + assert.Nil(t, idConfig) + config.Config.V.Set("keys.ethauth.publicKey", currentKeyPath) +} + func TestToCentId(t *testing.T) { tests := []struct { name string @@ -379,11 +445,6 @@ func TestValidateKey_success(t *testing.T) { assert.Nil(t, err, "must be nil") } -func TestAddKeyFromConfig_OptionNotSupported(t *testing.T) { - err := AddKeyFromConfig(4) - assert.NotNil(t, err, "it should error out") -} - func TestCentIDFromString(t *testing.T) { tests := []struct { id string diff --git a/keytools/ed25519/ed25519.go b/keytools/ed25519/ed25519.go index 40a76a737..9a00b4eff 100644 --- a/keytools/ed25519/ed25519.go +++ b/keytools/ed25519/ed25519.go @@ -71,23 +71,3 @@ func PublicKeyToP2PKey(publicKey [32]byte) (p2pId peer.ID, err error) { } return } - -// GetIDConfig reads the keys and ID from the config and returns a the Identity config -func GetIDConfig() (identityConfig *config.IdentityConfig, err error) { - pk, pvk, err := GetSigningKeyPairFromConfig() - if err != nil { - return nil, fmt.Errorf("failed to get signing keys: %v", err) - } - - centID, err := config.Config.GetIdentityID() - if err != nil { - return nil, err - } - - identityConfig = &config.IdentityConfig{ - ID: centID, - PublicKey: pk, - PrivateKey: pvk, - } - return -} diff --git a/keytools/ed25519/ed25519_test.go b/keytools/ed25519/ed25519_test.go index c3c4d7b3e..50cc6af67 100644 --- a/keytools/ed25519/ed25519_test.go +++ b/keytools/ed25519/ed25519_test.go @@ -61,32 +61,3 @@ func TestGetSigningKeyPairFromConfig(t *testing.T) { assert.NotNil(t, pubK) assert.NotNil(t, priK) } - -func TestGetIDConfig(t *testing.T) { - pub := config.Config.V.Get("keys.signing.publicKey") - - // failed keys - config.Config.V.Set("keys.signing.publicKey", "bad path") - id, err := GetIDConfig() - assert.Error(t, err) - assert.Nil(t, id) - assert.Contains(t, err.Error(), "failed to get signing keys") - config.Config.V.Set("keys.signing.publicKey", pub) - - // failed identity - gID := config.Config.V.Get("identityId") - config.Config.V.Set("identityId", "bad id") - id, err = GetIDConfig() - assert.Error(t, err) - assert.Nil(t, id) - assert.Contains(t, err.Error(), "can't read identityId from config") - config.Config.V.Set("identityId", gID) - - // success - id, err = GetIDConfig() - assert.Nil(t, err) - assert.NotNil(t, id) - nID, err := config.Config.GetIdentityID() - assert.Nil(t, err) - assert.Equal(t, id.ID, nID) -} diff --git a/keytools/secp256k1/secp256k1.go b/keytools/secp256k1/secp256k1.go index b50db3678..2d07d504a 100644 --- a/keytools/secp256k1/secp256k1.go +++ b/keytools/secp256k1/secp256k1.go @@ -115,31 +115,6 @@ func VerifySignature(publicKey, message, signature []byte) bool { } -// GetIDConfig reads the keys and ID from the config and returns a the Identity config -func GetIDConfig() (identityConfig *config.IdentityConfig, err error) { - pub, pvk, err := GetEthAuthKeyFromConfig() - if err != nil { - return nil, fmt.Errorf("failed to get eth keys: %v", err) - } - - centId, err := config.Config.GetIdentityID() - if err != nil { - return nil, err - } - - pubKey, err := hexutil.Decode(GetAddress(pub)) - if err != nil { - return nil, err - } - identityConfig = &config.IdentityConfig{ - ID: centId, - PublicKey: pubKey, - PrivateKey: pvk, - } - - return -} - // GetEthAuthKeyFromConfig returns the public and private keys as byte array func GetEthAuthKeyFromConfig() (public, private []byte, err error) { pub, priv := config.Config.GetEthAuthKeyPair() diff --git a/keytools/secp256k1/secp256k1_test.go b/keytools/secp256k1/secp256k1_test.go index fe567e052..71a90febb 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/keytools/secp256k1/secp256k1_test.go @@ -230,32 +230,3 @@ func TestGetEthAuthKeyFromConfig(t *testing.T) { assert.NotNil(t, pubK) assert.NotNil(t, priK) } - -func TestGetIDConfig(t *testing.T) { - pub := config.Config.V.Get("keys.ethauth.publicKey") - - // failed keys - config.Config.V.Set("keys.ethauth.publicKey", "bad path") - id, err := GetIDConfig() - assert.Error(t, err) - assert.Nil(t, id) - assert.Contains(t, err.Error(), "failed to get eth keys") - config.Config.V.Set("keys.ethauth.publicKey", pub) - - // failed identity - gID := config.Config.V.Get("identityId") - config.Config.V.Set("identityId", "bad id") - id, err = GetIDConfig() - assert.Error(t, err) - assert.Nil(t, id) - assert.Contains(t, err.Error(), "can't read identityId from config") - config.Config.V.Set("identityId", gID) - - // success - id, err = GetIDConfig() - assert.Nil(t, err) - assert.NotNil(t, id) - nID, err := config.Config.GetIdentityID() - assert.Nil(t, err) - assert.Equal(t, id.ID, nID) -} diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index a54f296e0..4b3360a6e 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -17,7 +17,6 @@ import ( cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/identity" - cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/notification" "github.com/centrifuge/go-centrifuge/p2p" @@ -58,10 +57,9 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { savedService := identity.IDService - idConfig, err := cented25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() assert.Nil(t, err) - centID, _ := identity.ToCentID(idConfig.ID) - pubKey := idConfig.PublicKey + pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey b32Key, _ := utils.SliceToByte32(pubKey) idkey := &identity.EthereumIdentityKey{ Key: b32Key, @@ -70,7 +68,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() id.On("FetchKey", pubKey).Return(idkey, nil).Once() identity.IDService = srv @@ -84,7 +82,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { id = &testingcommons.MockID{} srv = &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() id.On("FetchKey", pubKey).Return(idkey, nil).Once() identity.IDService = srv @@ -100,10 +98,9 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { savedService := identity.IDService - idConfig, err := cented25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() assert.Nil(t, err) - centID, _ := identity.ToCentID(idConfig.ID) - pubKey := idConfig.PublicKey + pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey b32Key, _ := utils.SliceToByte32(pubKey) idkey := &identity.EthereumIdentityKey{ Key: b32Key, @@ -112,7 +109,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() id.On("FetchKey", pubKey).Return(idkey, nil).Once() identity.IDService = srv @@ -132,7 +129,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { assert.Nil(t, err) id = &testingcommons.MockID{} srv = &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() id.On("FetchKey", pubKey).Return(idkey, nil).Once() identity.IDService = srv @@ -152,10 +149,9 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { func TestHandler_RequestDocumentSignature(t *testing.T) { savedService := identity.IDService - idConfig, err := cented25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() assert.Nil(t, err) - centID, _ := identity.ToCentID(idConfig.ID) - pubKey := idConfig.PublicKey + pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey b32Key, _ := utils.SliceToByte32(pubKey) idkey := &identity.EthereumIdentityKey{ Key: b32Key, @@ -164,7 +160,7 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { } id := &testingcommons.MockID{} srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() id.On("FetchKey", pubKey).Return(idkey, nil).Once() identity.IDService = srv @@ -188,11 +184,11 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) // Anchor document - secpIDConfig, err := secp256k1.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() anchorIDTyped, _ := anchors.NewAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.NewDocRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, secpIDConfig.PrivateKey) + signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) @@ -230,11 +226,11 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { doc.DocumentRoot = tree.RootHash() // Anchor document - secpIDConfig, err := secp256k1.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() anchorIDTyped, _ := anchors.NewAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.NewDocRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, secpIDConfig.PrivateKey) + signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) @@ -259,17 +255,16 @@ func createIdentity(t *testing.T) identity.CentID { assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + idConfig, err := identity.GetIdentityConfig() // Add Keys - idConfig, err := cented25519.GetIDConfig() - pubKey := idConfig.PublicKey + pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeSigning, pubKey) assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") watchReceivedIdentity := <-confirmations assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") - secpIDConfig, err := secp256k1.GetIDConfig() - secPubKey := secpIDConfig.PublicKey + secPubKey := idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, secPubKey) assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") @@ -280,18 +275,14 @@ func createIdentity(t *testing.T) identity.CentID { } func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument) *coredocumentpb.CoreDocument { - idConfig, err := cented25519.GetIDConfig() + idConfig, err := identity.GetIdentityConfig() assert.Nil(t, err) if doc == nil { doc = testingutils.GenerateCoreDocument() } tree, _ := coredocument.GetDocumentSigningTree(doc) doc.SigningRoot = tree.RootHash() - sig := signatures.Sign(&config.IdentityConfig{ - ID: idConfig.ID, - PublicKey: idConfig.PublicKey, - PrivateKey: idConfig.PrivateKey, - }, doc.SigningRoot) + sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) tree, _ = coredocument.GetDocumentRootTree(doc) doc.DocumentRoot = tree.RootHash() diff --git a/signatures/signatures.go b/signatures/signatures.go index 3248a8c21..b46ac6221 100644 --- a/signatures/signatures.go +++ b/signatures/signatures.go @@ -6,7 +6,6 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "golang.org/x/crypto/ed25519" @@ -53,11 +52,12 @@ func verifySignature(pubKey, message, signature []byte) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated -func Sign(idConfig *config.IdentityConfig, payload []byte) *coredocumentpb.Signature { +func Sign(idConfig *identity.IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { + centIDBytes, _ := idConfig.ID.MarshalBinary() return &coredocumentpb.Signature{ - EntityId: idConfig.ID, - PublicKey: idConfig.PublicKey, - Signature: ed25519.Sign(idConfig.PrivateKey, payload), + EntityId: centIDBytes, + PublicKey: idConfig.Keys[purpose].PublicKey, + Signature: ed25519.Sign(idConfig.Keys[purpose].PrivateKey, payload), Timestamp: utils.ToTimestamp(time.Now().UTC()), } } diff --git a/signatures/signatures_test.go b/signatures/signatures_test.go index 43efe70e9..ca87b4b8b 100644 --- a/signatures/signatures_test.go +++ b/signatures/signatures_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -25,13 +24,19 @@ var ( func TestSign(t *testing.T) { coreDoc := testingutils.GenerateCoreDocument() coreDoc.SigningRoot = key1Pub - idConfig := config.IdentityConfig{ - ID: id1, + centID, err := identity.ToCentID(id1) + assert.Nil(t, err) + signKey := identity.IdentityKey{ PublicKey: key1Pub, PrivateKey: key1, } - - sig := Sign(&idConfig, coreDoc.SigningRoot) + idConfig := &identity.IdentityConfig{ + ID: centID, + Keys: map[int]identity.IdentityKey{ + identity.KeyPurposeSigning: signKey, + }, + } + sig := Sign(idConfig, identity.KeyPurposeSigning, coreDoc.SigningRoot) assert.NotNil(t, sig) assert.Equal(t, sig.PublicKey, []byte(key1Pub)) assert.Equal(t, sig.EntityId, id1) diff --git a/testingutils/utils.go b/testingutils/utils.go index 2e902fb58..7b587bb5b 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -12,8 +12,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/ptypes/any" @@ -118,16 +116,14 @@ func (m *MockSubscription) Err() <-chan error { func (*MockSubscription) Unsubscribe() {} func CreateIdentityWithKeys() identity.CentID { - idConfigEth, _ := secp256k1.GetIDConfig() - idConfig, _ := ed25519.GetIDConfig() - centIdTyped, _ := identity.ToCentID(idConfigEth.ID) + idConfig, _ := identity.GetIdentityConfig() // only create identity if it doesn't exist - id, err := identity.IDService.LookupIdentityForID(centIdTyped) + id, err := identity.IDService.LookupIdentityForID(idConfig.ID) if err != nil { - _, confirmations, _ := identity.IDService.CreateIdentity(centIdTyped) + _, confirmations, _ := identity.IDService.CreateIdentity(idConfig.ID) <-confirmations // LookupIdentityForId - id, _ = identity.IDService.LookupIdentityForID(centIdTyped) + id, _ = identity.IDService.LookupIdentityForID(idConfig.ID) } // only add key if it doesn't exist @@ -135,16 +131,16 @@ func CreateIdentityWithKeys() identity.CentID { ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() defer cancel() if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfigEth.PublicKey) + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) <-confirmations } _, err = id.GetLastKeyForPurpose(identity.KeyPurposeSigning) ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext() defer cancel() if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.PublicKey) + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) <-confirmations } - return centIdTyped + return idConfig.ID } From 706f711911f25f0777e80456dc9a4a1d3310ac70 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 1 Nov 2018 12:30:13 +0100 Subject: [PATCH 010/220] clean up anchors (#398) 1. Better comments 2. renamed `NewAnchorID` -> `ToAnchorID` since this is conversion but not a creation 3. renamed `NewDocRoot` -> `ToDocumentRoot` since this is conversion 4. renamed `NewRandomDocRoot` -> `RandomDocumentRoot` 5. Unexported `anchorCommittedWatcher`, `anchorConfirmationTask` --- anchors/anchor.go | 102 ++++++++++-------- anchors/anchor_confirmation_task.go | 46 ++++---- anchors/anchor_confirmation_task_test.go | 16 +-- anchors/anchor_repository.go | 10 +- anchors/anchor_repository_integration_test.go | 8 +- anchors/anchor_test.go | 8 +- anchors/bootstrapper.go | 12 ++- anchors/ethereum_anchor_repository.go | 9 +- anchors/ethereum_anchor_repository_test.go | 10 +- coredocument/processor.go | 4 +- coredocument/processor_test.go | 8 +- coredocument/validator.go | 4 +- coredocument/validator_test.go | 8 +- documents/invoice/service_test.go | 8 +- documents/purchaseorder/service_test.go | 8 +- nft/ethereum_payment_obligation.go | 4 +- p2p/handler_integration_test.go | 8 +- 17 files changed, 145 insertions(+), 128 deletions(-) diff --git a/anchors/anchor.go b/anchors/anchor.go index ece433530..ef90198b8 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -10,94 +10,112 @@ import ( ) const ( - AnchorIDLength = 32 - RootLength = 32 + // AnchorIDLength is the length in bytes of the AnchorID + AnchorIDLength = 32 + + // DocumentRootLength is the length in bytes of the DocumentRoot + DocumentRootLength = 32 + + // DocumentProofLength is the length in bytes of a single proof DocumentProofLength = 32 + + //Supported anchor schema version as stored on public repository + AnchorSchemaVersion uint = 1 ) +// AnchorID type is byte array of length AnchorIDLength type AnchorID [AnchorIDLength]byte -func NewAnchorID(anchorBytes []byte) (AnchorID, error) { - var anchorBytesFixed [AnchorIDLength]byte - if !utils.IsValidByteSliceForLength(anchorBytes, AnchorIDLength) { - return anchorBytesFixed, errors.New("invalid length byte slice provided for anchorID") +// ToAnchorID convert the bytes into AnchorID type +// returns an error if the bytes length != AnchorIDLength +func ToAnchorID(bytes []byte) (AnchorID, error) { + var id [AnchorIDLength]byte + if !utils.IsValidByteSliceForLength(bytes, AnchorIDLength) { + return id, errors.New("invalid length byte slice provided for anchorID") } - copy(anchorBytesFixed[:], anchorBytes[:AnchorIDLength]) - return anchorBytesFixed, nil + + copy(id[:], bytes[:AnchorIDLength]) + return id, nil } +// BigInt returns anchorID in bigInt form func (a *AnchorID) BigInt() *big.Int { return utils.ByteSliceToBigInt(a[:]) } -type DocRoot [RootLength]byte +// DocumentRoot type is byte array of length DocumentRootLength +type DocumentRoot [DocumentRootLength]byte -func NewDocRoot(docRootBytes []byte) (DocRoot, error) { - var rootBytes [RootLength]byte - if !utils.IsValidByteSliceForLength(docRootBytes, RootLength) { - return rootBytes, errors.New("invalid length byte slice provided for docRoot") +// ToDocumentRoot converts bytes to DocumentRoot +// returns error if the bytes length != DocumentRootLength +func ToDocumentRoot(bytes []byte) (DocumentRoot, error) { + var root [DocumentRootLength]byte + if !utils.IsValidByteSliceForLength(bytes, DocumentRootLength) { + return root, errors.New("invalid length byte slice provided for docRoot") } - copy(rootBytes[:], docRootBytes[:RootLength]) - return rootBytes, nil -} -func NewRandomDocRoot() DocRoot { - root, _ := NewDocRoot(utils.RandomSlice(RootLength)) - return root + copy(root[:], bytes[:DocumentRootLength]) + return root, nil } -func (a DocRoot) Fixed() [RootLength]byte { - return a +// RandomDocumentRoot returns a randomly generated DocumentRoot +func RandomDocumentRoot() DocumentRoot { + root, _ := ToDocumentRoot(utils.RandomSlice(DocumentRootLength)) + return root } +// PreCommitData holds required document details for pre-commit type PreCommitData struct { AnchorID AnchorID - SigningRoot DocRoot + SigningRoot DocumentRoot CentrifugeID identity.CentID Signature []byte ExpirationBlock *big.Int SchemaVersion uint } +// CommitData holds required document details for anchoring type CommitData struct { BlockHeight uint64 AnchorID AnchorID - DocumentRoot DocRoot + DocumentRoot DocumentRoot CentrifugeID identity.CentID DocumentProofs [][DocumentProofLength]byte Signature []byte SchemaVersion uint } +// WatchCommit holds the commit data received from ethereum event type WatchCommit struct { CommitData *CommitData Error error } +// WatchPreCommit holds the pre commit data received from ethereum event type WatchPreCommit struct { PreCommit *PreCommitData Error error } -//Supported anchor schema version as stored on public repository -const AnchorSchemaVersion uint = 1 - -func SupportedSchemaVersion() uint { +// supportedSchemaVersion returns the current AnchorSchemaVersion +func supportedSchemaVersion() uint { return AnchorSchemaVersion } -func NewPreCommitData(anchorID AnchorID, signingRoot DocRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (preCommitData *PreCommitData) { - preCommitData = &PreCommitData{} - preCommitData.AnchorID = anchorID - preCommitData.SigningRoot = signingRoot - preCommitData.CentrifugeID = centrifugeID - preCommitData.Signature = signature - preCommitData.ExpirationBlock = expirationBlock - preCommitData.SchemaVersion = SupportedSchemaVersion() - return preCommitData +// newPreCommitData returns a PreCommitData with passed in details +func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (preCommitData *PreCommitData) { + return &PreCommitData{ + AnchorID: anchorID, + SigningRoot: signingRoot, + CentrifugeID: centrifugeID, + Signature: signature, + ExpirationBlock: expirationBlock, + SchemaVersion: supportedSchemaVersion(), + } } -func NewCommitData(blockHeight uint64, anchorID AnchorID, documentRoot DocRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (commitData *CommitData) { +// NewCommitData returns a CommitData with passed in details +func NewCommitData(blockHeight uint64, anchorID AnchorID, documentRoot DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (commitData *CommitData) { return &CommitData{ BlockHeight: blockHeight, AnchorID: anchorID, @@ -108,9 +126,9 @@ func NewCommitData(blockHeight uint64, anchorID AnchorID, documentRoot DocRoot, } } -func GenerateCommitHash(anchorID AnchorID, centrifugeID identity.CentID, documentRoot DocRoot) []byte { - message := append(anchorID[:], documentRoot[:]...) - message = append(message, centrifugeID[:]...) - messageToSign := crypto.Keccak256(message) - return messageToSign +// GenerateCommitHash generates Keccak256 message from AnchorID, CentID, DocumentRoot +func GenerateCommitHash(anchorID AnchorID, centrifugeID identity.CentID, documentRoot DocumentRoot) []byte { + msg := append(anchorID[:], documentRoot[:]...) + msg = append(msg, centrifugeID[:]...) + return crypto.Keccak256(msg) } diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index 1593ce074..af16048d6 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -24,7 +24,7 @@ const ( AddressParam string = "AddressParam" ) -type AnchorCommittedWatcher interface { +type anchorCommittedWatcher interface { FilterAnchorCommitted( opts *bind.FilterOpts, from []common.Address, @@ -32,9 +32,9 @@ type AnchorCommittedWatcher interface { centrifugeId []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) } -// AnchoringConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumAnchoryRepositoryContract. +// anchorConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumAnchoryRepositoryContract. // To see how it gets registered see bootstrapper.go and to see how it gets used see setUpRegistrationEventListener method -type AnchoringConfirmationTask struct { +type anchorConfirmationTask struct { // task parameters From common.Address AnchorID AnchorID @@ -44,30 +44,23 @@ type AnchoringConfirmationTask struct { // state EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) EthContext context.Context - AnchorCommittedFilterer AnchorCommittedWatcher + AnchorCommittedFilterer anchorCommittedWatcher } -func NewAnchoringConfirmationTask( - anchorCommittedWatcher AnchorCommittedWatcher, - ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), -) *AnchoringConfirmationTask { - return &AnchoringConfirmationTask{ - AnchorCommittedFilterer: anchorCommittedWatcher, - EthContextInitializer: ethContextInitializer, - } -} - -func (act *AnchoringConfirmationTask) Name() string { +// Name returns AnchorRepositoryConfirmationTaskName +func (act *anchorConfirmationTask) Name() string { return AnchorRepositoryConfirmationTaskName } -func (act *AnchoringConfirmationTask) Init() error { +// Init registers the task to the queue +func (act *anchorConfirmationTask) Init() error { queue.Queue.Register(act.Name(), act) return nil } -func (act *AnchoringConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &AnchoringConfirmationTask{ +// Copy returns a new instance of anchorConfirmationTask +func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { + return &anchorConfirmationTask{ act.From, act.AnchorID, act.CentrifugeID, @@ -78,15 +71,14 @@ func (act *AnchoringConfirmationTask) Copy() (gocelery.CeleryTask, error) { }, nil } -// ParseKwargs - define a method to parse AnchorID, Address and RootHash -func (act *AnchoringConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { +// ParseKwargs parses args to anchorConfirmationTask +func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { anchorID, ok := kwargs[AnchorIDParam] if !ok { return fmt.Errorf("undefined kwarg " + AnchorIDParam) } anchorIDBytes, err := getBytesAnchorID(anchorID) - if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", AnchorIDParam, err.Error()) } @@ -94,27 +86,29 @@ func (act *AnchoringConfirmationTask) ParseKwargs(kwargs map[string]interface{}) act.AnchorID = anchorIDBytes //parse the centrifuge id - centrifugeId, ok := kwargs[CentrifugeIDParam] + centID, ok := kwargs[CentrifugeIDParam] if !ok { return fmt.Errorf("undefined kwarg " + CentrifugeIDParam) } - centrifugeIdBytes, err := getBytesCentrifugeID(centrifugeId) + centIDBytes, err := getBytesCentrifugeID(centID) if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", CentrifugeIDParam, err.Error()) } - act.CentrifugeID = centrifugeIdBytes + act.CentrifugeID = centIDBytes // parse the address address, ok := kwargs[AddressParam] if !ok { return fmt.Errorf("undefined kwarg " + AddressParam) } + addressStr, ok := address.(string) if !ok { return fmt.Errorf("param is not hex string " + AddressParam) } + addressTyped, err := getAddressFromHexString(addressStr) if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", AddressParam, err.Error()) @@ -131,8 +125,8 @@ func (act *AnchoringConfirmationTask) ParseKwargs(kwargs map[string]interface{}) return nil } -// RunTask calls listens to events from geth related to AnchoringConfirmationTask#AnchorID and records result. -func (act *AnchoringConfirmationTask) RunTask() (interface{}, error) { +// RunTask calls listens to events from geth related to anchorConfirmationTask#AnchorID and records result. +func (act *anchorConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the anchorID [%x]", act.AnchorID) if act.EthContext == nil { act.EthContext, _ = act.EthContextInitializer() diff --git a/anchors/anchor_confirmation_task_test.go b/anchors/anchor_confirmation_task_test.go index 306fd05d0..8c711b23c 100644 --- a/anchors/anchor_confirmation_task_test.go +++ b/anchors/anchor_confirmation_task_test.go @@ -32,8 +32,8 @@ func (m *MockAnchorCommittedFilter) FilterAnchorCommitted( } func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { - act := AnchoringConfirmationTask{} - anchorID, _ := NewAnchorID(utils.RandomSlice(AnchorIDLength)) + act := anchorConfirmationTask{} + anchorID, _ := ToAnchorID(utils.RandomSlice(AnchorIDLength)) address := common.BytesToAddress([]byte{1, 2, 3, 4}) centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) @@ -56,7 +56,7 @@ func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { } func TestAnchoringConfirmationTask_ParseKwargsAnchorNotPassed(t *testing.T) { - act := AnchoringConfirmationTask{} + act := anchorConfirmationTask{} address := common.BytesToAddress([]byte{1, 2, 3, 4}) var centrifugeIdBytes [6]byte @@ -69,7 +69,7 @@ func TestAnchoringConfirmationTask_ParseKwargsAnchorNotPassed(t *testing.T) { } func TestAnchoringConfirmationTask_ParseKwargsInvalidAnchor(t *testing.T) { - act := AnchoringConfirmationTask{} + act := anchorConfirmationTask{} anchorID := 123 address := common.BytesToAddress([]byte{1, 2, 3, 4}) kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ @@ -81,7 +81,7 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAnchor(t *testing.T) { } func TestAnchoringConfirmationTask_ParseKwargsAddressNotPassed(t *testing.T) { - act := AnchoringConfirmationTask{} + act := anchorConfirmationTask{} anchorID := [32]byte{1, 2, 3} kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ AnchorIDParam: anchorID, @@ -91,7 +91,7 @@ func TestAnchoringConfirmationTask_ParseKwargsAddressNotPassed(t *testing.T) { } func TestAnchoringConfirmationTask_ParseKwargsInvalidAddress(t *testing.T) { - act := AnchoringConfirmationTask{} + act := anchorConfirmationTask{} anchorID := [32]byte{1, 2, 3} address := 123 kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ @@ -105,7 +105,7 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAddress(t *testing.T) { func TestAnchoringConfirmationTask_RunTaskIterError(t *testing.T) { anchorID := [32]byte{1, 2, 3} address := common.BytesToAddress([]byte{1, 2, 3, 4}) - act := AnchoringConfirmationTask{ + act := anchorConfirmationTask{ AnchorID: anchorID, From: address, AnchorCommittedFilterer: &MockAnchorCommittedFilter{err: fmt.Errorf("failed iterator")}, @@ -122,7 +122,7 @@ func TestAnchoringConfirmationTask_RunTaskWatchError(t *testing.T) { ctx, _ := context.WithDeadline(context.Background(), toBeDone) anchorID := [32]byte{1, 2, 3} address := common.BytesToAddress([]byte{1, 2, 3, 4}) - act := AnchoringConfirmationTask{ + act := anchorConfirmationTask{ AnchorID: anchorID, From: address, AnchorCommittedFilterer: &MockAnchorCommittedFilter{iter: &EthereumAnchorRepositoryContractAnchorCommittedIterator{ diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index 594a80fd4..c0e07182a 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -12,14 +12,14 @@ var log = logging.Logger("anchorRepository") // AnchorRepository defines a set of functions that can be // implemented by any type that stores and retrieves the anchoring, and pre anchoring details type AnchorRepository interface { - PreCommitAnchor(anchorID AnchorID, signingRoot DocRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) - CommitAnchor(anchorID AnchorID, documentRoot DocRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) - GetDocumentRootOf(anchorID AnchorID) (DocRoot, error) + PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) + CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) + GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) } // PreCommitAnchor initiates the PreCommit call on the smart contract // with passed in variables and returns a channel for transaction confirmation -func PreCommitAnchor(anchorID AnchorID, signingRoot DocRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) { +func PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) { anchorRepository, _ := getConfiguredRepository() confirmations, err := anchorRepository.PreCommitAnchor(anchorID, signingRoot, centrifugeId, signature, expirationBlock) @@ -31,7 +31,7 @@ func PreCommitAnchor(anchorID AnchorID, signingRoot DocRoot, centrifugeId identi // CommitAnchor initiates the Commit call on smart contract // with passed in variables and returns a channel for transaction confirmation -func CommitAnchor(anchorID AnchorID, documentRoot DocRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) { +func CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) { anchorRepository, _ := getConfiguredRepository() confirmations, err := anchorRepository.CommitAnchor(anchorID, documentRoot, centrifugeID, documentProofs, signature) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 9bd2167e4..2181db5c2 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -62,9 +62,9 @@ func TestCommitAnchor_Integration(t *testing.T) { centrifugeId := utils.RandomSlice(identity.CentIDLength) createIdentityWithKeys(t, centrifugeId) testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") - anchorIDTyped, _ := anchors.NewAnchorID(anchorID) + anchorIDTyped, _ := anchors.ToAnchorID(anchorID) centIdTyped, _ := identity.ToCentID(centrifugeId) - docRootTyped, _ := anchors.NewDocRoot(documentRoot) + docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) commitAnchor(t, anchorID, centrifugeId, documentRoot, signature, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) @@ -74,8 +74,8 @@ func TestCommitAnchor_Integration(t *testing.T) { } func commitAnchor(t *testing.T, anchorID, centrifugeId, documentRoot, signature []byte, documentProofs [][32]byte) { - anchorIDTyped, _ := anchors.NewAnchorID(anchorID) - docRootTyped, _ := anchors.NewDocRoot(documentRoot) + anchorIDTyped, _ := anchors.ToAnchorID(anchorID) + docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) centIdFixed, _ := identity.ToCentID(centrifugeId) confirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) diff --git a/anchors/anchor_test.go b/anchors/anchor_test.go index 9c0253453..b1f0ed076 100644 --- a/anchors/anchor_test.go +++ b/anchors/anchor_test.go @@ -46,7 +46,7 @@ func TestNewAnchorId(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - _, err := NewAnchorID(test.slice) + _, err := ToAnchorID(test.slice) assert.Equal(t, test.err, err.Error()) }) } @@ -60,12 +60,12 @@ func TestNewDocRoot(t *testing.T) { }{ { "smallerSlice", - utils.RandomSlice(RootLength - 1), + utils.RandomSlice(DocumentRootLength - 1), "invalid length byte slice provided for docRoot", }, { "largerSlice", - utils.RandomSlice(RootLength + 1), + utils.RandomSlice(DocumentRootLength + 1), "invalid length byte slice provided for docRoot", }, { @@ -76,7 +76,7 @@ func TestNewDocRoot(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - _, err := NewDocRoot(test.slice) + _, err := ToDocumentRoot(test.slice) assert.Equal(t, test.err, err.Error()) }) } diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 5463c86e1..766a7660c 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -12,8 +12,8 @@ import ( type Bootstrapper struct { } -// Bootstrap initializes the AnchorRepositoryContract as well as the AnchoringConfirmationTask that depends on it. -// the AnchoringConfirmationTask is added to be registered on the Queue at queue.Bootstrapper +// Bootstrap initializes the AnchorRepositoryContract as well as the anchorConfirmationTask that depends on it. +// the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") @@ -33,5 +33,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } - return queue.InstallQueuedTask(context, NewAnchoringConfirmationTask(&repositoryContract.EthereumAnchorRepositoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) + + task := &anchorConfirmationTask{ + AnchorCommittedFilterer: &repositoryContract.EthereumAnchorRepositoryContractFilterer, + EthContextInitializer: ethereum.DefaultWaitForTransactionMiningContext, + } + + return queue.InstallQueuedTask(context, task) } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index c126ca798..81fc4a565 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -20,7 +20,6 @@ type Config interface { } type AnchorRepositoryContract interface { - //transactions PreCommit(opts *bind.TransactOpts, anchorID *big.Int, signingRoot [32]byte, centrifugeId *big.Int, signature []byte, expirationBlock *big.Int) (*types.Transaction, error) Commit(opts *bind.TransactOpts, _anchorID *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) @@ -47,20 +46,20 @@ func NewEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorR } // Commits takes an anchorID and returns the corresponding documentRoot from the chain -func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocRoot, err error) { +func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := ethereum.GetGethCallOpts() return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) } //PreCommitAnchor will call the transaction PreCommit on the smart contract -func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { +func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { ethRepositoryContract := ethRepository.anchorRepositoryContract opts, err := ethereum.GetConnection().GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { return } - preCommitData := NewPreCommitData(anchorID, signingRoot, centrifugeId, signature, expirationBlock) + preCommitData := newPreCommitData(anchorID, signingRoot, centrifugeId, signature, expirationBlock) if err != nil { return } @@ -76,7 +75,7 @@ func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID } // CommitAnchor will send a commit transaction to ethereum -func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { +func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { conn := ethereum.GetConnection() opts, err := conn.GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 78e40ece5..1b1f1c9b2 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -35,9 +35,9 @@ func TestCorrectCommitSignatureGen(t *testing.T) { correctCommitToSign := "0x15f9cb57608a7ef31428fd6b1cb7ea2002ab032211d882b920c1474334004d6b" correctCommitSignature := "0xb4051d6d03c3bf39f4ec4ba949a91a358b0cacb4804b82ed2ba978d338f5e747770c00b63c8e50c1a7aa5ba629870b54c2068a56f8b43460aa47891c6635d36d01" testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") - anchorIDTyped, _ := NewAnchorID(anchorID) + anchorIDTyped, _ := ToAnchorID(anchorID) centIdTyped, _ := identity.ToCentID(centrifugeId) - docRootTyped, _ := NewDocRoot(documentRoot) + docRootTyped, _ := ToDocumentRoot(documentRoot) messageToSign := GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) assert.Equal(t, correctCommitToSign, hexutil.Encode(messageToSign), "messageToSign not calculated correctly") signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) @@ -62,8 +62,8 @@ func TestGenerateAnchor(t *testing.T) { commitData := NewCommitData(0, currentAnchorID, documentRoot32Bytes, centIdTyped, documentProofs, signature) - anchorID, _ := NewAnchorID(currentAnchorID[:]) - docRoot, _ := NewDocRoot(documentRoot32Bytes[:]) + anchorID, _ := ToAnchorID(currentAnchorID[:]) + docRoot, _ := ToDocumentRoot(documentRoot32Bytes[:]) assert.Equal(t, commitData.AnchorID, anchorID, "Anchor should have the passed ID") assert.Equal(t, commitData.DocumentRoot, docRoot, "Anchor should have the passed document root") @@ -74,7 +74,7 @@ func TestGenerateAnchor(t *testing.T) { func TestGetDocumentRootOf(t *testing.T) { repo := &mockAnchorRepo{} - anchorID, err := NewAnchorID(utils.RandomSlice(32)) + anchorID, err := ToAnchorID(utils.RandomSlice(32)) assert.Nil(t, err) ethRepo := NewEthereumAnchorRepository(config.Config, repo) diff --git a/coredocument/processor.go b/coredocument/processor.go index 8a908a7b2..e34e01e9b 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -203,7 +203,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("pre anchor validation failed: %v", err) } - rootHash, err := anchors.NewDocRoot(cd.DocumentRoot) + rootHash, err := anchors.ToDocumentRoot(cd.DocumentRoot) if err != nil { return fmt.Errorf("failed to get document root: %v", err) } @@ -224,7 +224,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to get eth keys: %v", err) } - anchorID, err := anchors.NewAnchorID(cd.CurrentVersion) + anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { return fmt.Errorf("failed to get anchor ID: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 06ec431a8..f79b003af 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -256,15 +256,15 @@ type mockRepo struct { anchors.AnchorRepository } -func (m mockRepo) CommitAnchor(anchorID anchors.AnchorID, documentRoot anchors.DocRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *anchors.WatchCommit, error) { +func (m mockRepo) CommitAnchor(anchorID anchors.AnchorID, documentRoot anchors.DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *anchors.WatchCommit, error) { args := m.Called(anchorID, documentRoot, centrifugeID, documentProofs, signature) c, _ := args.Get(0).(chan *anchors.WatchCommit) return c, args.Error(1) } -func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocRoot, error) { +func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { args := m.Called(anchorID) - docRoot, _ := args.Get(0).(anchors.DocRoot) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) return docRoot, args.Error(1) } @@ -439,7 +439,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv - docRoot, err := anchors.NewDocRoot(cd.DocumentRoot) + docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) assert.Nil(t, err) repo := mockRepo{} repo.On("GetDocumentRootOf", mock.Anything).Return(docRoot, nil).Once() diff --git a/coredocument/validator.go b/coredocument/validator.go index 5e65f3858..b8fd95713 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -271,12 +271,12 @@ func anchoredValidator(repo anchors.AnchorRepository) documents.Validator { return fmt.Errorf("failed to get core document: %v", err) } - anchorID, err := anchors.NewAnchorID(cd.CurrentVersion) + anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { return fmt.Errorf("failed to get anchorID: %v", err) } - docRoot, err := anchors.NewDocRoot(cd.DocumentRoot) + docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) if err != nil { return fmt.Errorf("failed to get document root: %v", err) } diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 38a9458c9..6cb41640e 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -339,9 +339,9 @@ type repo struct { anchors.AnchorRepository } -func (r repo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocRoot, error) { +func (r repo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { args := r.Called(anchorID) - docRoot, _ := args.Get(0).(anchors.DocRoot) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) return docRoot, args.Error(1) } @@ -372,7 +372,7 @@ func TestValidator_anchoredValidator(t *testing.T) { assert.Contains(t, err.Error(), "failed to get document root") // failed to get docRoot from chain - anchorID, err := anchors.NewAnchorID(utils.RandomSlice(32)) + anchorID, err := anchors.ToAnchorID(utils.RandomSlice(32)) assert.Nil(t, err) r := &repo{} av = anchoredValidator(r) @@ -388,7 +388,7 @@ func TestValidator_anchoredValidator(t *testing.T) { assert.Contains(t, err.Error(), "failed to get document root from chain") // mismatched doc roots - docRoot := anchors.NewRandomDocRoot() + docRoot := anchors.RandomDocumentRoot() r = &repo{} av = anchoredValidator(r) r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index efd71d06e..5a866f440 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -38,9 +38,9 @@ type mockAnchorRepo struct { anchors.AnchorRepository } -func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocRoot, error) { +func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { args := r.Called(anchorID) - docRoot, _ := args.Get(0).(anchors.DocRoot) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) return docRoot, args.Error(1) } @@ -271,8 +271,8 @@ func mockSignatureCheck(i *Invoice, invSrv Service) identity.Service { Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), } - anchorID, _ := anchors.NewAnchorID(i.CoreDocument.DocumentIdentifier) - docRoot, _ := anchors.NewDocRoot(i.CoreDocument.DocumentRoot) + anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) + docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) mockRepo := invSrv.(service).anchorRepository.(*mockAnchorRepo) mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() srv := &testingcommons.MockIDService{} diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index aa2baed94..4125d244c 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -35,9 +35,9 @@ type mockAnchorRepo struct { anchors.AnchorRepository } -func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocRoot, error) { +func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { args := r.Called(anchorID) - docRoot, _ := args.Get(0).(anchors.DocRoot) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) return docRoot, args.Error(1) } @@ -361,8 +361,8 @@ func mockSignatureCheck(i *PurchaseOrder, poSrv Service) identity.Service { Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), } - anchorID, _ := anchors.NewAnchorID(i.CoreDocument.DocumentIdentifier) - docRoot, _ := anchors.NewDocRoot(i.CoreDocument.DocumentRoot) + anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) + docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) mockRepo := poSrv.(service).anchorRepository.(*mockAnchorRepo) mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() srv := &testingcommons.MockIDService{} diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index fec23cf71..5d788d6a7 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -81,12 +81,12 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registry return "", nil } - anchorID, err := anchors.NewAnchorID(corDoc.CurrentVersion) + anchorID, err := anchors.ToAnchorID(corDoc.CurrentVersion) if err != nil { return "", nil } - rootHash, err := anchors.NewDocRoot(corDoc.DocumentRoot) + rootHash, err := anchors.ToDocumentRoot(corDoc.DocumentRoot) if err != nil { return "", nil } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 4b3360a6e..82846a24f 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -185,8 +185,8 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { // Anchor document idConfig, err := identity.GetIdentityConfig() - anchorIDTyped, _ := anchors.NewAnchorID(doc.CurrentVersion) - docRootTyped, _ := anchors.NewDocRoot(doc.DocumentRoot) + anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) + docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) @@ -227,8 +227,8 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { // Anchor document idConfig, err := identity.GetIdentityConfig() - anchorIDTyped, _ := anchors.NewAnchorID(doc.CurrentVersion) - docRootTyped, _ := anchors.NewDocRoot(doc.DocumentRoot) + anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) + docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) From 56dffbee419be24522005df338efbfdc11751b44 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 1 Nov 2018 15:40:45 +0100 Subject: [PATCH 011/220] refactor identity (#399) 1. Unexported constants 2. Unexported Worker Task 3. unexported `ethereumIdentity` --- anchors/anchor_confirmation_task.go | 2 +- cmd/create_config.go | 6 +- cmd/manage_identities.go | 8 +- coredocument/processor.go | 4 +- identity/bootstrapper.go | 8 +- identity/ethereum_identity.go | 120 ++++++++-------- .../ethereum_identity_integration_test.go | 18 +-- identity/id_registration_confirmation_task.go | 89 ++++++------ .../id_registration_confirmation_task_test.go | 29 ++-- identity/identity.go | 60 ++++---- identity/identity_test.go | 23 ++- .../key_registration_confirmation_task.go | 131 +++++++++--------- ...key_registration_confirmation_task_test.go | 39 +++--- identity/util.go | 10 +- p2p/handler_integration_test.go | 6 +- signatures/signatures.go | 2 +- testingutils/commons/mock_identity.go | 13 +- testingutils/utils.go | 4 +- 18 files changed, 281 insertions(+), 291 deletions(-) diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index af16048d6..0a5272cf6 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -150,7 +150,7 @@ func (act *anchorConfirmationTask) RunTask() (interface{}, error) { err = utils.LookForEvent(iter) if err == nil { - log.Infof("Received filtered event Anchor Confirmation for AnchorID [%x] and CentrifugeId [%s]\n", act.AnchorID.BigInt(), act.CentrifugeID.String()) + log.Infof("Received filtered event Anchor Confirmation for AnchorID [%x] and CentrifugeID [%s]\n", act.AnchorID.BigInt(), act.CentrifugeID.String()) return iter.Event, nil } diff --git a/cmd/create_config.go b/cmd/create_config.go index 3120c1fa6..0cb319bf0 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -20,7 +20,7 @@ var p2pPort int64 var bootstraps []string func createIdentity() (identity.CentID, error) { - centrifugeId := identity.NewRandomCentID() + centrifugeId := identity.RandomCentID() _, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) if err != nil { return [identity.CentIDLength]byte{}, err @@ -39,7 +39,7 @@ func generateKeys() { } func addKeys() error { - err := identity.AddKeyFromConfig(identity.KeyPurposeP2p) + err := identity.AddKeyFromConfig(identity.KeyPurposeP2P) if err != nil { panic(err) } @@ -99,7 +99,7 @@ func init() { } config.Config.V.Set("identityId", id.String()) - log.Infof("Identity created [%s] [%x]", id.String(), id.ByteArray()) + log.Infof("Identity created [%s] [%x]", id.String(), id) err = addKeys() if err != nil { diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 117ab8fb8..38350ce4a 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -22,7 +22,7 @@ var createIdentityCmd = &cobra.Command{ var centrifugeId identity.CentID var err error if centrifugeIdString == "" { - centrifugeId = identity.NewRandomCentID() + centrifugeId = identity.RandomCentID() } else { centrifugeId, err = identity.CentIDFromString(centrifugeIdString) if err != nil { @@ -34,7 +34,7 @@ var createIdentityCmd = &cobra.Command{ panic(err) } watchIdentity := <-confirmations - log.Infof("Identity created [%s]", watchIdentity.Identity.GetCentrifugeID().String()) + log.Infof("Identity created [%s]", watchIdentity.Identity.CentID().String()) // We need a way to return the identity created so it can be read by an automated process as well // when id autogenerated id := []byte("{\"id\": \"" + centrifugeId.String() + "\"}") @@ -42,7 +42,7 @@ var createIdentityCmd = &cobra.Command{ if err != nil { panic(err) } - log.Infof("Identity created [%s]", watchIdentity.Identity.GetCentrifugeID()) + log.Infof("Identity created [%s]", watchIdentity.Identity.CentID()) }, } @@ -61,7 +61,7 @@ var addKeyCmd = &cobra.Command{ switch purpose { case "p2p": - purposeInt = identity.KeyPurposeP2p + purposeInt = identity.KeyPurposeP2P case "sign": purposeInt = identity.KeyPurposeSigning case "ethauth": diff --git a/coredocument/processor.go b/coredocument/processor.go index e34e01e9b..84549feb4 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -69,7 +69,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp return err } - lastB58Key, err := id.GetCurrentP2PKey() + lastB58Key, err := id.CurrentP2PKey() if err != nil { err = centerrors.Wrap(err, "error fetching p2p key") log.Error(err) @@ -92,7 +92,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp return err } - centIDBytes, _ := idConfig.ID.MarshalBinary() + centIDBytes := idConfig.ID[:] header := &p2ppb.CentrifugeHeader{ SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 132657bd1..936d754d6 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -12,8 +12,8 @@ import ( type Bootstrapper struct { } -// Bootstrap initializes the IdentityFactoryContract as well as the IdRegistrationConfirmationTask that depends on it. -// the IdRegistrationConfirmationTask is added to be registered on the Queue at queue.Bootstrapper +// Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. +// the idRegistrationConfirmationTask is added to be registered on the Queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") @@ -40,13 +40,13 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } err = queue.InstallQueuedTask(context, - NewIdRegistrationConfirmationTask(&identityContract.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) + newIdRegistrationConfirmationTask(&identityContract.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) if err != nil { return err } err = queue.InstallQueuedTask(context, - NewKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, config.Config)) + newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, config.Config)) if err != nil { return err } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index 2cb32235f..ca9ebe767 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -19,11 +19,11 @@ import ( var log = logging.Logger("identity") -type IdentityFactory interface { +type factory interface { CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) } -type IdentityContract interface { +type contract interface { AddKey(opts *bind.TransactOpts, _key [32]byte, _kPurpose *big.Int) (*types.Transaction, error) } @@ -31,72 +31,76 @@ type Config interface { GetEthereumDefaultAccountName() string } +// EthereumIdentityKey holds the identity related details type EthereumIdentityKey struct { Key [32]byte Purposes []*big.Int RevokedAt *big.Int } +// GetKey returns the public key func (idk *EthereumIdentityKey) GetKey() [32]byte { return idk.Key } +// GetPurposes returns the purposes intended for the key func (idk *EthereumIdentityKey) GetPurposes() []*big.Int { return idk.Purposes } +// GetRevokedAt returns the block at which the identity is revoked func (idk *EthereumIdentityKey) GetRevokedAt() *big.Int { return idk.RevokedAt } +// String prints the peerID extracted from the key func (idk *EthereumIdentityKey) String() string { peerID, _ := ed25519.PublicKeyToP2PKey(idk.Key) return fmt.Sprintf("%s", peerID.Pretty()) } -type EthereumIdentity struct { - CentrifugeId CentID - Contract *EthereumIdentityContract - RegistryContract *EthereumIdentityRegistryContract - Config Config -} - -func NewEthereumIdentity(id CentID, registryContract *EthereumIdentityRegistryContract, config Config) *EthereumIdentity { - return &EthereumIdentity{CentrifugeId: id, RegistryContract: registryContract, Config: config} +type ethereumIdentity struct { + centID CentID + contract *EthereumIdentityContract + registryContract *EthereumIdentityRegistryContract + config Config } -func (id *EthereumIdentity) CentrifugeID(cenId CentID) { - id.CentrifugeId = cenId +func newEthereumIdentity(id CentID, registryContract *EthereumIdentityRegistryContract, config Config) *ethereumIdentity { + return ðereumIdentity{centID: id, registryContract: registryContract, config: config} } -func (id *EthereumIdentity) CentrifugeIDBytes() CentID { - var idBytes [CentIDLength]byte - copy(idBytes[:], id.CentrifugeId[:CentIDLength]) - return idBytes +// CentrifugeID sets the CentID to the Identity +func (id *ethereumIdentity) SetCentrifugeID(centID CentID) { + id.centID = centID } -func (id *EthereumIdentity) String() string { - return fmt.Sprintf("CentrifugeID [%s]", id.CentrifugeId) +// String returns CentrifugeID +func (id *ethereumIdentity) String() string { + return fmt.Sprintf("CentrifugeID [%s]", id.centID) } -func (id *EthereumIdentity) GetCentrifugeID() CentID { - return id.CentrifugeId +// CentrifugeID returns the CentrifugeID +func (id *ethereumIdentity) CentID() CentID { + return id.centID } -func (id *EthereumIdentity) GetLastKeyForPurpose(keyPurpose int) (key []byte, err error) { +// LastKeyForPurpose returns the latest key for given purpose +func (id *ethereumIdentity) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { idKeys, err := id.fetchKeysByPurpose(keyPurpose) if err != nil { return []byte{}, err } if len(idKeys) == 0 { - return []byte{}, fmt.Errorf("no key found for type [%d] in ID [%s]", keyPurpose, id.CentrifugeId) + return []byte{}, fmt.Errorf("no key found for type [%d] in ID [%s]", keyPurpose, id.centID) } return idKeys[len(idKeys)-1].Key[:32], nil } -func (id *EthereumIdentity) FetchKey(key []byte) (Key, error) { +// FetchKey fetches the Key from the chain +func (id *ethereumIdentity) FetchKey(key []byte) (Key, error) { contract, err := id.getContract() if err != nil { return nil, err @@ -117,8 +121,9 @@ func (id *EthereumIdentity) FetchKey(key []byte) (Key, error) { } -func (id *EthereumIdentity) GetCurrentP2PKey() (ret string, err error) { - key, err := id.GetLastKeyForPurpose(KeyPurposeP2p) +// CurrentP2PKey returns the latest P2P key +func (id *ethereumIdentity) CurrentP2PKey() (ret string, err error) { + key, err := id.LastKeyForPurpose(KeyPurposeP2P) if err != nil { return } @@ -131,14 +136,14 @@ func (id *EthereumIdentity) GetCurrentP2PKey() (ret string, err error) { return } -func (id *EthereumIdentity) findContract() (exists bool, err error) { - if id.Contract != nil { +func (id *ethereumIdentity) findContract() (exists bool, err error) { + if id.contract != nil { return true, nil } // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := ethereum.GetGethCallOpts() - idAddress, err := id.RegistryContract.GetIdentityByCentrifugeId(opts, id.CentrifugeId.BigInt()) + idAddress, err := id.registryContract.GetIdentityByCentrifugeId(opts, id.centID.BigInt()) if err != nil { return false, err } @@ -155,27 +160,28 @@ func (id *EthereumIdentity) findContract() (exists bool, err error) { log.Errorf("Failed to instantiate the identity contract: %v", err) return false, err } - id.Contract = idContract + id.contract = idContract return true, nil } -func (id *EthereumIdentity) getContract() (contract *EthereumIdentityContract, err error) { - if id.Contract == nil { +func (id *ethereumIdentity) getContract() (contract *EthereumIdentityContract, err error) { + if id.contract == nil { _, err := id.findContract() if err != nil { return nil, err } - return id.Contract, nil + return id.contract, nil } - return id.Contract, nil + return id.contract, nil } // CheckIdentityExists checks if the identity represented by id actually exists on ethereum -func (id *EthereumIdentity) CheckIdentityExists() (exists bool, err error) { +func (id *ethereumIdentity) CheckIdentityExists() (exists bool, err error) { return id.findContract() } -func (id *EthereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) { +// AddKeyToIdentity adds key to the purpose on chain +func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) { if utils.IsEmptyByteSlice(key) || len(key) > 32 { log.Errorf("Can't add key to identity: empty or invalid length(>32) key for [id: %s]: %x", id, key) return confirmations, errors.New("Can't add key to identity: Invalid key") @@ -188,7 +194,7 @@ func (id *EthereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int } conn := ethereum.GetConnection() - opts, err := ethereum.GetConnection().GetTxOpts(id.Config.GetEthereumDefaultAccountName()) + opts, err := ethereum.GetConnection().GetTxOpts(id.config.GetEthereumDefaultAccountName()) if err != nil { return confirmations, err } @@ -216,7 +222,8 @@ func (id *EthereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int return confirmations, nil } -func (id *EthereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdentityKey, error) { +// fetchKeysByPurpose fetches keys from chain matching purpose +func (id *ethereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdentityKey, error) { contract, err := id.getContract() if err != nil { return nil, err @@ -239,7 +246,7 @@ func (id *EthereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdenti } // sendRegistrationTransaction sends the actual transaction to add a Key on Ethereum registry contract -func sendKeyRegistrationTransaction(identityContract IdentityContract, opts *bind.TransactOpts, identity *EthereumIdentity, keyPurpose int, key []byte) (err error) { +func sendKeyRegistrationTransaction(identityContract contract, opts *bind.TransactOpts, identity *ethereumIdentity, keyPurpose int, key []byte) (err error) { //preparation of data in specific types for the call to Ethereum bigInt := big.NewInt(int64(keyPurpose)) @@ -250,7 +257,7 @@ func sendKeyRegistrationTransaction(identityContract IdentityContract, opts *bin tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(identityContract.AddKey, opts, bKey, bigInt) if err != nil { - log.Infof("Failed to send key [%v:%x] to add to CentrifugeID [%x]: %v", keyPurpose, bKey, identity.CentrifugeId, err) + log.Infof("Failed to send key [%v:%x] to add to CentrifugeID [%x]: %v", keyPurpose, bKey, identity.CentID, err) return err } @@ -259,9 +266,9 @@ func sendKeyRegistrationTransaction(identityContract IdentityContract, opts *bin } // sendIdentityCreationTransaction sends the actual transaction to create identity on Ethereum registry contract -func sendIdentityCreationTransaction(identityFactory IdentityFactory, opts *bind.TransactOpts, identityToBeCreated Identity) (err error) { +func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated Identity) (err error) { //preparation of data in specific types for the call to Ethereum - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.GetCentrifugeID().BigInt()) + tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) if err != nil { log.Infof("Failed to send identity for creation [CentrifugeID: %s] : %v", identityToBeCreated, err) @@ -275,18 +282,19 @@ func sendIdentityCreationTransaction(identityFactory IdentityFactory, opts *bind return } -func setUpKeyRegisteredEventListener(identity Identity, keyPurpose int, key [32]byte, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { +// setUpKeyRegisteredEventListener listens for Identity creation +func setUpKeyRegisteredEventListener(identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) - centId := identity.GetCentrifugeID() + centId := identity.CentID() if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(KeyRegistrationConfirmationTaskName, + asyncRes, err := queue.Queue.DelayKwargs(keyRegistrationConfirmationTaskName, map[string]interface{}{ - CentIdParam: centId, - KeyParam: key, - KeyPurposeParam: keyPurpose, - BlockHeight: blockHeight, + centIDParam: centId, + keyParam: key, + keyPurposeParam: keyPurpose, + blockHeightParam: bh, }) if err != nil { return nil, err @@ -299,11 +307,11 @@ func setUpKeyRegisteredEventListener(identity Identity, keyPurpose int, key [32] // of the identity. func setUpRegistrationEventListener(identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) - bCentId := identityToBeCreated.GetCentrifugeID() + bCentId := identityToBeCreated.CentID() if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(IdRegistrationConfirmationTaskName, map[string]interface{}{CentIdParam: bCentId, BlockHeight: blockHeight}) + asyncRes, err := queue.Queue.DelayKwargs(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, blockHeightParam: blockHeight}) if err != nil { return nil, err } @@ -337,15 +345,15 @@ func NewEthereumIdentityService(config Config, factoryContract *EthereumIdentity // CheckIdentityExists checks if the identity represented by id actually exists on ethereum func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (exists bool, err error) { - id := NewEthereumIdentity(centrifugeID, ids.registryContract, ids.config) + id := newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) exists, err = id.CheckIdentityExists() return } // CreateIdentity creates an identity representing the id on ethereum func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) { - log.Infof("Creating Identity [%x]", centrifugeID.ByteArray()) - id = NewEthereumIdentity(centrifugeID, ids.registryContract, ids.config) + log.Infof("Creating Identity [%x]", centrifugeID) + id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) conn := ethereum.GetConnection() opts, err := conn.GetTxOpts(ids.config.GetEthereumDefaultAccountName()) if err != nil { @@ -390,10 +398,10 @@ func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Ad // LookupIdentityForID looks up if the identity for given CentID exists on ethereum func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Identity, error) { - id := NewEthereumIdentity(centrifugeID, ids.registryContract, ids.config) + id := newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) exists, err := id.CheckIdentityExists() if !exists { - return id, fmt.Errorf("identity [%s] does not exist with err [%v]", id.CentrifugeId, err) + return id, fmt.Errorf("identity [%s] does not exist with err [%v]", id.centID, err) } if err != nil { diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index d7d826bce..9d49d9795 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -46,12 +46,12 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") // LookupIdentityForID id, err = identityService.LookupIdentityForID(centrifugeId) assert.Nil(t, err, "should not error out when resolving identity") - assert.Equal(t, centrifugeId, id.GetCentrifugeID(), "CentrifugeID Should match provided one") + assert.Equal(t, centrifugeId, id.CentID(), "CentrifugeID Should match provided one") _, err = identityService.LookupIdentityForID(wrongCentrifugeIdTyped) assert.NotNil(t, err, "should error out when resolving wrong identity") @@ -66,13 +66,13 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") watchReceivedIdentity := <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - recKey, err := id.GetLastKeyForPurpose(1) + recKey, err := id.LastKeyForPurpose(1) assert.Nil(t, err) assert.Equal(t, key, recKey) - _, err = id.GetLastKeyForPurpose(2) + _, err = id.LastKeyForPurpose(2) assert.NotNil(t, err) } @@ -88,7 +88,7 @@ func TestAddKeyFromConfig(t *testing.T) { watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") err = identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") @@ -122,9 +122,9 @@ func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { for ix := 0; ix < 5; ix++ { watchSingleIdentity := <-identityConfirmations[ix] - id, err := identityService.LookupIdentityForID(watchSingleIdentity.Identity.GetCentrifugeID()) + id, err := identityService.LookupIdentityForID(watchSingleIdentity.Identity.CentID()) assert.Nil(t, err, "should not error out upon identity resolution") - assert.Equal(t, centIds[ix], id.GetCentrifugeID(), "Should have the ID that was passed into create function [%v]", id.GetCentrifugeID()) + assert.Equal(t, centIds[ix], id.CentID(), "Should have the ID that was passed into create function [%v]", id.CentID()) } } @@ -139,6 +139,6 @@ func TestEthereumIdentityService_GetIdentityAddress(t *testing.T) { } func TestEthereumIdentityService_GetIdentityAddressNonExistingID(t *testing.T) { - _, err := identityService.GetIdentityAddress(identity.NewRandomCentID()) + _, err := identityService.GetIdentityAddress(identity.RandomCentID()) assert.NotNil(t, err) } diff --git a/identity/id_registration_confirmation_task.go b/identity/id_registration_confirmation_task.go index dcfe9be67..887a790fd 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/id_registration_confirmation_task.go @@ -14,86 +14,89 @@ import ( ) const ( - IdRegistrationConfirmationTaskName string = "IdRegistrationConfirmationTaskName" + idRegistrationConfirmationTaskName string = "idRegistrationConfirmationTaskName" ) -type IdentitiesCreatedFilterer interface { +type identitiesCreatedFilterer interface { FilterIdentityCreated(opts *bind.FilterOpts, centrifugeId []*big.Int) (*EthereumIdentityFactoryContractIdentityCreatedIterator, error) } -// IdRegistrationConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumIdentityFactoryContract. +// idRegistrationConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumIdentityFactoryContract. // To see how it gets registered see bootstrapper.go and to see how it gets used see setUpRegistrationEventListener method -type IdRegistrationConfirmationTask struct { - CentID CentID - BlockHeight uint64 - EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) - EthContext context.Context - IdentityCreatedWatcher IdentitiesCreatedFilterer +type idRegistrationConfirmationTask struct { + centID CentID + blockHeight uint64 + contextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + ctx context.Context + filterer identitiesCreatedFilterer } -func NewIdRegistrationConfirmationTask( - identityCreatedWatcher IdentitiesCreatedFilterer, +func newIdRegistrationConfirmationTask( + identityCreatedWatcher identitiesCreatedFilterer, ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), -) *IdRegistrationConfirmationTask { - return &IdRegistrationConfirmationTask{ - IdentityCreatedWatcher: identityCreatedWatcher, - EthContextInitializer: ethContextInitializer, +) *idRegistrationConfirmationTask { + return &idRegistrationConfirmationTask{ + filterer: identityCreatedWatcher, + contextInitializer: ethContextInitializer, } } -func (rct *IdRegistrationConfirmationTask) Name() string { - return IdRegistrationConfirmationTaskName +// Name returns the name of the task +func (rct *idRegistrationConfirmationTask) Name() string { + return idRegistrationConfirmationTaskName } -func (rct *IdRegistrationConfirmationTask) Init() error { - queue.Queue.Register(IdRegistrationConfirmationTaskName, rct) +// Init registers the task to queue +func (rct *idRegistrationConfirmationTask) Init() error { + queue.Queue.Register(idRegistrationConfirmationTaskName, rct) return nil } -func (rct *IdRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &IdRegistrationConfirmationTask{ - rct.CentID, - rct.BlockHeight, - rct.EthContextInitializer, - rct.EthContext, - rct.IdentityCreatedWatcher}, nil +// Copy returns a new copy of the the task +func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { + return &idRegistrationConfirmationTask{ + rct.centID, + rct.blockHeight, + rct.contextInitializer, + rct.ctx, + rct.filterer}, nil } -// ParseKwargs - define a method to parse CentID -func (rct *IdRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - centId, ok := kwargs[CentIdParam] +// ParseKwargs parses the kwargs into the task +func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { + centId, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + CentIdParam) + return fmt.Errorf("undefined kwarg " + centIDParam) } centIdTyped, err := getCentID(centId) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", CentIdParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } - rct.CentID = centIdTyped + rct.centID = centIdTyped - rct.BlockHeight, err = parseBlockHeight(kwargs) + rct.blockHeight, err = parseBlockHeight(kwargs) if err != nil { return err } return nil } -// RunTask calls listens to events from geth related to IdRegistrationConfirmationTask#CentID and records result. -func (rct *IdRegistrationConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the ID [%x]", rct.CentID.ByteArray()) - if rct.EthContext == nil { - rct.EthContext, _ = rct.EthContextInitializer() +// RunTask calls listens to events from geth related to idRegistrationConfirmationTask#CentID and records result. +func (rct *idRegistrationConfirmationTask) RunTask() (interface{}, error) { + log.Infof("Waiting for confirmation for the ID [%x]", rct.centID) + if rct.ctx == nil { + rct.ctx, _ = rct.contextInitializer() } fOpts := &bind.FilterOpts{ - Context: rct.EthContext, - Start: rct.BlockHeight, + Context: rct.ctx, + Start: rct.blockHeight, } for { - iter, err := rct.IdentityCreatedWatcher.FilterIdentityCreated( + iter, err := rct.filterer.FilterIdentityCreated( fOpts, - []*big.Int{rct.CentID.BigInt()}, + []*big.Int{rct.centID.BigInt()}, ) if err != nil { return nil, centerrors.Wrap(err, "failed to start filtering identity event logs") @@ -101,7 +104,7 @@ func (rct *IdRegistrationConfirmationTask) RunTask() (interface{}, error) { err = utils.LookForEvent(iter) if err == nil { - log.Infof("Received filtered event Id Registration Confirmation for CentrifugeId [%s]\n", rct.CentID.String()) + log.Infof("Received filtered event Id Registration Confirmation for CentrifugeID [%s]\n", rct.centID.String()) return iter.Event, nil } diff --git a/identity/id_registration_confirmation_task_test.go b/identity/id_registration_confirmation_task_test.go index b590f59e8..a8c2a394a 100644 --- a/identity/id_registration_confirmation_task_test.go +++ b/identity/id_registration_confirmation_task_test.go @@ -1,43 +1,42 @@ // +build unit -package identity_test +package identity import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { - rct := identity.IdRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) + rct := idRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) blockHeight := uint64(3132) - idBytes, _ := identity.ToCentID(id) + idBytes, _ := ToCentID(id) kwargs := map[string]interface{}{ - identity.CentIdParam: idBytes, - identity.BlockHeight: blockHeight, + centIDParam: idBytes, + blockHeightParam: blockHeight, } decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) if err != nil { - t.Errorf("Could not parse %s for [%x]", identity.CentIdParam, id) + t.Errorf("Could not parse %s for [%x]", centIDParam, id) } - assert.Equal(t, idBytes, rct.CentID, "Resulting mockID should have the same ID as the input") - assert.Equal(t, blockHeight, rct.BlockHeight, "Resulting blockheight should be same as the input") + assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") + assert.Equal(t, blockHeight, rct.blockHeight, "Resulting blockheight should be same as the input") } func TestRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { - rct := identity.IdRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) + rct := idRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) err := rct.ParseKwargs(map[string]interface{}{"notId": id}) assert.NotNil(t, err, "Should not allow parsing without centId") } func TestRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { - rct := identity.IdRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{identity.CentIdParam: id}) + rct := idRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) + err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) assert.NotNil(t, err, "Should not parse without the correct type of centId") } diff --git a/identity/identity.go b/identity/identity.go index 8253a3ae1..372460aa3 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -18,17 +18,23 @@ import ( ) const ( - CentIDLength = 6 - ActionCreate = "create" - ActionAddKey = "addkey" - KeyPurposeP2p = 1 - KeyPurposeSigning = 2 + // CentIDLength is the length in bytes of the CentrifugeID + CentIDLength = 6 + + // KeyPurposeP2P represents a key used for p2p txns + KeyPurposeP2P = 1 + + // KeyPurposeSigning represents a key used for signing + KeyPurposeSigning = 2 + + // KeyPurposeEthMsgAuth represents a key used for ethereum txns KeyPurposeEthMsgAuth = 3 ) // IDService is a default implementation of the Service var IDService Service +// CentID represents a CentIDLength identity of an entity type CentID [CentIDLength]byte // IdentityConfig holds information about the identity @@ -60,7 +66,7 @@ func GetIdentityConfig() (*IdentityConfig, error) { if err != nil { return nil, err } - keys[KeyPurposeP2p] = IdentityKey{PublicKey: pk, PrivateKey: sk} + keys[KeyPurposeP2P] = IdentityKey{PublicKey: pk, PrivateKey: sk} keys[KeyPurposeSigning] = IdentityKey{PublicKey: pk, PrivateKey: sk} //secp256k1 keys @@ -117,11 +123,13 @@ func CentIDsFromStrings(ids []string) ([]CentID, error) { return cids, nil } -func NewRandomCentID() CentID { +// RandomCentID returns a randomly generated CentID +func RandomCentID() CentID { ID, _ := ToCentID(utils.RandomSlice(CentIDLength)) return ID } +// Equal checks if c == other func (c CentID) Equal(other CentID) bool { for i := range c { if c[i] != other[i] { @@ -132,44 +140,23 @@ func (c CentID) Equal(other CentID) bool { return true } +// String returns the hex format of CentID func (c CentID) String() string { return hexutil.Encode(c[:]) } -func (c CentID) MarshalBinary() (data []byte, err error) { - return c[:], nil -} - +// BigInt returns CentID in bigInt func (c CentID) BigInt() *big.Int { return utils.ByteSliceToBigInt(c[:]) } -func (c CentID) ByteArray() [CentIDLength]byte { - var idBytes [CentIDLength]byte - copy(idBytes[:], c[:CentIDLength]) - return idBytes -} - -func ParseCentIDs(centIDByteArray [][]byte) (errs []error, centIDs []CentID) { - for _, element := range centIDByteArray { - centID, err := ToCentID(element) - if err != nil { - err = centerrors.Wrap(err, "error parsing receiver centId") - errs = append(errs, err) - continue - } - centIDs = append(centIDs, centID) - } - return errs, centIDs -} - // Identity defines an Identity on chain type Identity interface { fmt.Stringer - GetCentrifugeID() CentID - CentrifugeID(cenId CentID) - GetCurrentP2PKey() (ret string, err error) - GetLastKeyForPurpose(keyPurpose int) (key []byte, err error) + CentID() CentID + SetCentrifugeID(centID CentID) + CurrentP2PKey() (ret string, err error) + LastKeyForPurpose(keyPurpose int) (key []byte, err error) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) FetchKey(key []byte) (Key, error) } @@ -181,6 +168,7 @@ type Key interface { GetRevokedAt() *big.Int } +// WatchIdentity holds the identity received form chain event type WatchIdentity struct { Identity Identity Error error @@ -209,7 +197,7 @@ func GetClientP2PURL(centID CentID) (url string, err error) { return url, centerrors.Wrap(err, "error fetching receiver identity") } - p2pKey, err := target.GetCurrentP2PKey() + p2pKey, err := target.CurrentP2PKey() if err != nil { return url, centerrors.Wrap(err, "error fetching p2p key") } @@ -294,7 +282,7 @@ func AddKeyFromConfig(purpose int) error { } watchAddedToIdentity := <-confirmations - lastKey, errLocal := watchAddedToIdentity.Identity.GetLastKeyForPurpose(purpose) + lastKey, errLocal := watchAddedToIdentity.Identity.LastKeyForPurpose(purpose) if errLocal != nil { return err } diff --git a/identity/identity_test.go b/identity/identity_test.go index 8bda98118..87320b8c3 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -41,21 +41,21 @@ func (i *mockID) String() string { return args.String(0) } -func (i *mockID) GetCentrifugeID() CentID { +func (i *mockID) CentID() CentID { args := i.Called() return args.Get(0).(CentID) } -func (i *mockID) CentrifugeID(centId CentID) { +func (i *mockID) SetCentrifugeID(centId CentID) { i.Called(centId) } -func (i *mockID) GetCurrentP2PKey() (ret string, err error) { +func (i *mockID) CurrentP2PKey() (ret string, err error) { args := i.Called() return args.String(0), args.Error(1) } -func (i *mockID) GetLastKeyForPurpose(keyPurpose int) (key []byte, err error) { +func (i *mockID) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { args := i.Called(keyPurpose) return args.Get(0).([]byte), args.Error(1) } @@ -65,11 +65,6 @@ func (i *mockID) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byt return args.Get(0).(chan *WatchIdentity), args.Error(1) } -func (i *mockID) CheckIdentityExists() (exists bool, err error) { - args := i.Called() - return args.Bool(0), args.Error(1) -} - func (i *mockID) FetchKey(key []byte) (Key, error) { args := i.Called(key) idKey := args.Get(0) @@ -119,7 +114,7 @@ func TestGetIdentityConfig_Success(t *testing.T) { assert.NotNil(t, idConfig) configId, err := config.Config.GetIdentityID() assert.Nil(t, err) - idBytes, _ := idConfig.ID.MarshalBinary() + idBytes := idConfig.ID[:] assert.Equal(t, idBytes, configId) assert.Equal(t, 3, len(idConfig.Keys)) } @@ -222,7 +217,7 @@ func TestGetClientP2PURL_fail_identity(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) srv := &mockIDService{} id := &mockID{} - id.On("GetCurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() + id.On("CurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() srv.On("LookupIdentityForID", centID).Return(id, nil).Once() IDService = srv p2p, err := GetClientP2PURL(centID) @@ -237,7 +232,7 @@ func TestGetClientP2PURL_Success(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) srv := &mockIDService{} id := &mockID{} - id.On("GetCurrentP2PKey").Return("target", nil).Once() + id.On("CurrentP2PKey").Return("target", nil).Once() srv.On("LookupIdentityForID", centID).Return(id, nil).Once() IDService = srv p2p, err := GetClientP2PURL(centID) @@ -252,7 +247,7 @@ func TestGetClientsP2PURLs_fail(t *testing.T) { centIDs := []CentID{centID} srv := &mockIDService{} id := &mockID{} - id.On("GetCurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() + id.On("CurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() srv.On("LookupIdentityForID", centIDs[0]).Return(id, nil).Once() IDService = srv p2pURLs, err := GetClientsP2PURLs(centIDs) @@ -267,7 +262,7 @@ func TestGetClientsP2PURLs_success(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) centIDs := []CentID{centID} id := &mockID{} - id.On("GetCurrentP2PKey").Return("target", nil).Once() + id.On("CurrentP2PKey").Return("target", nil).Once() srv := &mockIDService{} srv.On("LookupIdentityForID", centIDs[0]).Return(id, nil).Once() IDService = srv diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index ad5469b82..da1afd076 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -14,130 +14,133 @@ import ( ) const ( - KeyRegistrationConfirmationTaskName string = "KeyRegistrationConfirmationTaskName" - KeyParam string = "KeyParam" - KeyPurposeParam = "KeyPurposeParam" + keyRegistrationConfirmationTaskName = "keyRegistrationConfirmationTaskName" + keyParam = "keyParam" + keyPurposeParam = "keyPurposeParam" ) -type KeyRegisteredFilterer interface { +type keyRegisteredFilterer interface { FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) } -// KeyRegistrationConfirmationTask is a queued task to filter key registration events on Ethereum using EthereumIdentityContract. +// keyRegistrationConfirmationTask is a queued task to filter key registration events on Ethereum using EthereumIdentityContract. // To see how it gets registered see bootstrapper.go and to see how it gets used see setUpKeyRegisteredEventListener method -type KeyRegistrationConfirmationTask struct { - CentID CentID - Key [32]byte - KeyPurpose int - BlockHeight uint64 - EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) - EthContext context.Context - KeyRegisteredWatcher KeyRegisteredFilterer - RegistryContract *EthereumIdentityRegistryContract - Config Config +type keyRegistrationConfirmationTask struct { + centID CentID + key [32]byte + keyPurpose int + blockHeight uint64 + contextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + ctx context.Context + filterer keyRegisteredFilterer + contract *EthereumIdentityRegistryContract + config Config } -func NewKeyRegistrationConfirmationTask( +func newKeyRegistrationConfirmationTask( ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), registryContract *EthereumIdentityRegistryContract, config Config, -) *KeyRegistrationConfirmationTask { - return &KeyRegistrationConfirmationTask{ - EthContextInitializer: ethContextInitializer, - RegistryContract: registryContract, - Config: config, +) *keyRegistrationConfirmationTask { + return &keyRegistrationConfirmationTask{ + contextInitializer: ethContextInitializer, + contract: registryContract, + config: config, } } -func (krct *KeyRegistrationConfirmationTask) Name() string { - return KeyRegistrationConfirmationTaskName +// Name returns keyRegistrationConfirmationTaskName +func (krct *keyRegistrationConfirmationTask) Name() string { + return keyRegistrationConfirmationTaskName } -func (krct *KeyRegistrationConfirmationTask) Init() error { - queue.Queue.Register(KeyRegistrationConfirmationTaskName, krct) +// Init registers task with the queue +func (krct *keyRegistrationConfirmationTask) Init() error { + queue.Queue.Register(keyRegistrationConfirmationTaskName, krct) return nil } -func (krct *KeyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &KeyRegistrationConfirmationTask{ - krct.CentID, - krct.Key, - krct.KeyPurpose, - krct.BlockHeight, - krct.EthContextInitializer, - krct.EthContext, - krct.KeyRegisteredWatcher, - krct.RegistryContract, - krct.Config}, nil +// Copy returns a new copy of the task +func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { + return &keyRegistrationConfirmationTask{ + krct.centID, + krct.key, + krct.keyPurpose, + krct.blockHeight, + krct.contextInitializer, + krct.ctx, + krct.filterer, + krct.contract, + krct.config}, nil } -// ParseKwargs - define a method to parse params -func (krct *KeyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - centId, ok := kwargs[CentIdParam] +// ParseKwargs parses the args into the task +func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { + centId, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + CentIdParam) + return fmt.Errorf("undefined kwarg " + centIDParam) } centIdTyped, err := getCentID(centId) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", CentIdParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } - krct.CentID = centIdTyped + krct.centID = centIdTyped // key parsing - key, ok := kwargs[KeyParam] + key, ok := kwargs[keyParam] if !ok { - return fmt.Errorf("undefined kwarg " + KeyParam) + return fmt.Errorf("undefined kwarg " + keyParam) } keyTyped, err := getBytes32(key) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", KeyParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", keyParam, err.Error()) } - krct.Key = keyTyped + krct.key = keyTyped // key purpose parsing - keyPurpose, ok := kwargs[KeyPurposeParam] + keyPurpose, ok := kwargs[keyPurposeParam] if !ok { - return fmt.Errorf("undefined kwarg " + KeyPurposeParam) + return fmt.Errorf("undefined kwarg " + keyPurposeParam) } keyPurposeF, ok := keyPurpose.(float64) if ok { - krct.KeyPurpose = int(keyPurposeF) + krct.keyPurpose = int(keyPurposeF) } else { - return fmt.Errorf("can not parse " + KeyPurposeParam) + return fmt.Errorf("can not parse " + keyPurposeParam) } // block height parsing - krct.BlockHeight, err = parseBlockHeight(kwargs) + krct.blockHeight, err = parseBlockHeight(kwargs) if err != nil { return err } return nil } -// RunTask calls listens to events from geth related to KeyRegistrationConfirmationTask#Key and records result. -func (krct *KeyRegistrationConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the Key [%x]", krct.Key) - if krct.EthContext == nil { - krct.EthContext, _ = krct.EthContextInitializer() +// RunTask calls listens to events from geth related to keyRegistrationConfirmationTask#Key and records result. +func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { + log.Infof("Waiting for confirmation for the Key [%x]", krct.key) + if krct.ctx == nil { + krct.ctx, _ = krct.contextInitializer() } - id := EthereumIdentity{CentrifugeId: krct.CentID, RegistryContract: krct.RegistryContract, Config: krct.Config} + id := ethereumIdentity{centID: krct.centID, registryContract: krct.contract, config: krct.config} contract, err := id.getContract() if err != nil { return nil, err } - krct.KeyRegisteredWatcher = contract + krct.filterer = contract fOpts := &bind.FilterOpts{ - Context: krct.EthContext, - Start: krct.BlockHeight, + Context: krct.ctx, + Start: krct.blockHeight, } for { - iter, err := krct.KeyRegisteredWatcher.FilterKeyAdded( + iter, err := krct.filterer.FilterKeyAdded( fOpts, - [][32]byte{krct.Key}, - []*big.Int{big.NewInt(int64(krct.KeyPurpose))}, + [][32]byte{krct.key}, + []*big.Int{big.NewInt(int64(krct.keyPurpose))}, ) if err != nil { return nil, centerrors.Wrap(err, "failed to start filtering key event logs") @@ -145,7 +148,7 @@ func (krct *KeyRegistrationConfirmationTask) RunTask() (interface{}, error) { err = utils.LookForEvent(iter) if err == nil { - log.Infof("Received filtered event Key Registration Confirmation for CentrifugeId [%s] and key [%x] with purpose [%d]\n", krct.CentID.String(), krct.Key, krct.KeyPurpose) + log.Infof("Received filtered event Key Registration Confirmation for CentrifugeID [%s] and key [%x] with purpose [%d]\n", krct.centID.String(), krct.key, krct.keyPurpose) return iter.Event, nil } diff --git a/identity/key_registration_confirmation_task_test.go b/identity/key_registration_confirmation_task_test.go index f433e444f..6932c314b 100644 --- a/identity/key_registration_confirmation_task_test.go +++ b/identity/key_registration_confirmation_task_test.go @@ -1,51 +1,50 @@ // +build unit -package identity_test +package identity import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { - rct := identity.KeyRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) + rct := keyRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) key := utils.RandomSlice(32) var keyFixed [32]byte copy(keyFixed[:], key) - keyPurpose := identity.KeyPurposeSigning - blockHeight := uint64(12) - idBytes, _ := identity.ToCentID(id) + keyPurpose := KeyPurposeSigning + bh := uint64(12) + idBytes, _ := ToCentID(id) kwargs := map[string]interface{}{ - identity.CentIdParam: idBytes, - identity.KeyParam: keyFixed, - identity.KeyPurposeParam: keyPurpose, - identity.BlockHeight: blockHeight, + centIDParam: idBytes, + keyParam: keyFixed, + keyPurposeParam: keyPurpose, + blockHeightParam: bh, } decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) if err != nil { t.Errorf("parse error %s", err.Error()) } - assert.Equal(t, idBytes, rct.CentID, "Resulting mockID should have the same ID as the input") - assert.Equal(t, keyFixed, rct.Key, "Resulting key should be same as the input") - assert.Equal(t, keyPurpose, rct.KeyPurpose, "Resulting keyPurpose should be same as the input") - assert.Equal(t, blockHeight, rct.BlockHeight, "Resulting blockheight should be same as the input") + assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") + assert.Equal(t, keyFixed, rct.key, "Resulting key should be same as the input") + assert.Equal(t, keyPurpose, rct.keyPurpose, "Resulting keyPurpose should be same as the input") + assert.Equal(t, bh, rct.blockHeight, "Resulting blockheight should be same as the input") } func TestKeyRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { - rct := identity.KeyRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) + rct := keyRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) err := rct.ParseKwargs(map[string]interface{}{"notId": id}) assert.NotNil(t, err, "Should not allow parsing without centId") } func TestKeyRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { - rct := identity.KeyRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{identity.CentIdParam: id}) + rct := keyRegistrationConfirmationTask{} + id := utils.RandomSlice(CentIDLength) + err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) assert.NotNil(t, err, "Should not parse without the correct type of centId") } diff --git a/identity/util.go b/identity/util.go index 2a0fb2f33..c45b6f643 100644 --- a/identity/util.go +++ b/identity/util.go @@ -3,15 +3,15 @@ package identity import "errors" const ( - CentIdParam string = "CentID" - BlockHeight string = "BlockHeight" + centIDParam string = "CentID" + blockHeightParam string = "BlockHeight" ) func getBytes32(key interface{}) ([32]byte, error) { var fixed [32]byte b, ok := key.([]interface{}) if !ok { - return fixed, errors.New("Could not parse interface to []byte") + return fixed, errors.New("could not parse interface to []byte") } // convert and copy b byte values for i, v := range b { @@ -25,7 +25,7 @@ func getCentID(key interface{}) (CentID, error) { var fixed [CentIDLength]byte b, ok := key.([]interface{}) if !ok { - return fixed, errors.New("Could not parse interface to []byte") + return fixed, errors.New("could not parse interface to []byte") } // convert and copy b byte values for i, v := range b { @@ -36,7 +36,7 @@ func getCentID(key interface{}) (CentID, error) { } func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[BlockHeight]; ok { + if bhi, ok := valMap[blockHeightParam]; ok { bhf, ok := bhi.(float64) if ok { return uint64(bhf), nil diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 82846a24f..25c08faf0 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -253,7 +253,7 @@ func createIdentity(t *testing.T) identity.CentID { assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") idConfig, err := identity.GetIdentityConfig() // Add Keys @@ -262,14 +262,14 @@ func createIdentity(t *testing.T) identity.CentID { assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") watchReceivedIdentity := <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") secPubKey := idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, secPubKey) assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") watchReceivedIdentity = <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.GetCentrifugeID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") return centrifugeId } diff --git a/signatures/signatures.go b/signatures/signatures.go index b46ac6221..31ccdb559 100644 --- a/signatures/signatures.go +++ b/signatures/signatures.go @@ -53,7 +53,7 @@ func verifySignature(pubKey, message, signature []byte) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated func Sign(idConfig *identity.IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { - centIDBytes, _ := idConfig.ID.MarshalBinary() + centIDBytes := idConfig.ID[:] return &coredocumentpb.Signature{ EntityId: centIDBytes, PublicKey: idConfig.Keys[purpose].PublicKey, diff --git a/testingutils/commons/mock_identity.go b/testingutils/commons/mock_identity.go index 0cbb325cb..520fb90da 100644 --- a/testingutils/commons/mock_identity.go +++ b/testingutils/commons/mock_identity.go @@ -54,21 +54,21 @@ func (i *MockID) String() string { return args.String(0) } -func (i *MockID) GetCentrifugeID() identity.CentID { +func (i *MockID) CentID() identity.CentID { args := i.Called() return args.Get(0).(identity.CentID) } -func (i *MockID) CentrifugeID(centId identity.CentID) { +func (i *MockID) SetCentrifugeID(centId identity.CentID) { i.Called(centId) } -func (i *MockID) GetCurrentP2PKey() (ret string, err error) { +func (i *MockID) CurrentP2PKey() (ret string, err error) { args := i.Called() return args.String(0), args.Error(1) } -func (i *MockID) GetLastKeyForPurpose(keyPurpose int) (key []byte, err error) { +func (i *MockID) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { args := i.Called(keyPurpose) return args.Get(0).([]byte), args.Error(1) } @@ -78,11 +78,6 @@ func (i *MockID) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byt return args.Get(0).(chan *identity.WatchIdentity), args.Error(1) } -func (i *MockID) CheckIdentityExists() (exists bool, err error) { - args := i.Called() - return args.Bool(0), args.Error(1) -} - func (i *MockID) FetchKey(key []byte) (identity.Key, error) { args := i.Called(key) idKey, _ := args.Get(0).(identity.Key) diff --git a/testingutils/utils.go b/testingutils/utils.go index 7b587bb5b..62c5ccf17 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -127,14 +127,14 @@ func CreateIdentityWithKeys() identity.CentID { } // only add key if it doesn't exist - _, err = id.GetLastKeyForPurpose(identity.KeyPurposeEthMsgAuth) + _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() defer cancel() if err != nil { confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) <-confirmations } - _, err = id.GetLastKeyForPurpose(identity.KeyPurposeSigning) + _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext() defer cancel() if err != nil { From 82192499dcf6e4abb6a564bfd24e6c95c18c3c3c Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 1 Nov 2018 16:22:42 +0100 Subject: [PATCH 012/220] Refactor geth (#397) 1. Minor changes to how we increment nonce and added more tests for the nonce increment 2. Mutex for accounts for read and write 3. Unported `GethClient` 4. Removed definitions that are not used in the interface --- anchors/anchor_repository_integration_test.go | 7 +- anchors/bootstrapper.go | 4 +- anchors/ethereum_anchor_repository.go | 10 +- coredocument/coredocument_test.go | 4 +- coredocument/processor.go | 23 +- documents/anchor_test.go | 14 +- documents/invoice/service_test.go | 17 +- documents/purchaseorder/service_test.go | 10 +- documents/registry_test.go | 20 +- ethereum/bootstrapper.go | 4 +- ethereum/geth_client.go | 339 ++++++++++-------- ethereum/geth_client_integration_test.go | 13 +- ethereum/geth_client_test.go | 157 +++++--- identity/bootstrapper.go | 8 +- identity/ethereum_identity.go | 19 +- nft/bootstrapper.go | 6 +- nft/ethereum_payment_obligation.go | 4 +- nft/payment_obligation_integration_test.go | 4 +- notification/notification_test.go | 3 +- p2p/client_test.go | 8 +- p2p/handler_integration_test.go | 4 +- p2p/handler_test.go | 4 +- signatures/signatures_test.go | 20 +- testingutils/commons/mock_ethclient.go | 10 +- testingutils/coredocument/coredocument.go | 89 +++++ testingutils/identity/identity.go | 38 ++ testingutils/utils.go | 121 ------- 27 files changed, 517 insertions(+), 443 deletions(-) create mode 100644 testingutils/coredocument/coredocument.go create mode 100644 testingutils/identity/identity.go diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 2181db5c2..64ebaa954 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -19,10 +19,6 @@ import ( var identityService identity.Service -// Add Key -var testAddress string -var testPrivateKey string - func TestMain(m *testing.M) { cc.TestFunctionalEthereumBootstrap() identityService = identity.IDService @@ -44,7 +40,6 @@ func createIdentityWithKeys(t *testing.T, centrifugeId []byte) []byte { id, err = identityService.LookupIdentityForID(centIdTyped) assert.Nil(t, err, "should not error out when resolving identity") - testPrivateKey = "0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5" pubKey, _ := hexutil.Decode("0xc8dd3d66e112fae5c88fe6a677be24013e53c33e") confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, pubKey) @@ -103,7 +98,7 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { messageToSign := anchors.GenerateCommitHash(currentAnchorId, centIdFixed, currentDocumentRoot) signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) documentProofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - h, err := ethereum.GetConnection().GetClient().HeaderByNumber(context.Background(), nil) + h, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) assert.Nil(t, err, " error must be nil") commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) confirmationList[ix], err = anchors.CommitAnchor(currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 766a7660c..10dc84884 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -22,8 +22,8 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.New("ethereum client hasn't been initialized") } - client := ethereum.GetConnection() - repositoryContract, err := NewEthereumAnchorRepositoryContract(config.Config.GetContractAddress("anchorRepository"), client.GetClient()) + client := ethereum.GetClient() + repositoryContract, err := NewEthereumAnchorRepositoryContract(config.Config.GetContractAddress("anchorRepository"), client.GetEthClient()) if err != nil { return err } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 81fc4a565..74b060536 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -55,7 +55,7 @@ func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID Anchor //PreCommitAnchor will call the transaction PreCommit on the smart contract func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { ethRepositoryContract := ethRepository.anchorRepositoryContract - opts, err := ethereum.GetConnection().GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) + opts, err := ethereum.GetClient().GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { return } @@ -76,13 +76,13 @@ func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID // CommitAnchor will send a commit transaction to ethereum func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { - conn := ethereum.GetConnection() + conn := ethereum.GetClient() opts, err := conn.GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { return nil, err } - h, err := conn.GetClient().HeaderByNumber(context.Background(), nil) + h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) if err != nil { return nil, err } @@ -112,7 +112,7 @@ func sendPreCommitTransaction(contract AnchorRepositoryContract, opts *bind.Tran //preparation of data in specific types for the call to Ethereum schemaVersion := big.NewInt(int64(preCommitData.SchemaVersion)) - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(contract.PreCommit, opts, preCommitData.AnchorID, preCommitData.SigningRoot, + tx, err := ethereum.GetClient().SubmitTransactionWithRetries(contract.PreCommit, opts, preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.CentrifugeID, preCommitData.Signature, preCommitData.ExpirationBlock, schemaVersion) if err != nil { @@ -128,7 +128,7 @@ func sendPreCommitTransaction(contract AnchorRepositoryContract, opts *bind.Tran // sendCommitTransaction sends the actual transaction to register the Anchor on Ethereum registry contract func sendCommitTransaction(contract AnchorRepositoryContract, opts *bind.TransactOpts, commitData *CommitData) (err error) { - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(contract.Commit, opts, commitData.AnchorID.BigInt(), commitData.DocumentRoot, + tx, err := ethereum.GetClient().SubmitTransactionWithRetries(contract.Commit, opts, commitData.AnchorID.BigInt(), commitData.DocumentRoot, commitData.CentrifugeID.BigInt(), commitData.DocumentProofs, commitData.Signature) if err != nil { diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 2b6774cad..da0bc18a8 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -9,7 +9,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/ethereum/go-ethereum/common/hexutil" @@ -123,7 +123,7 @@ func TestGetDocumentRootTree(t *testing.T) { } func TestGetTypeUrl(t *testing.T) { - coreDocument := testingutils.GenerateCoreDocument() + coreDocument := testingcoredocument.GenerateCoreDocument() documentType, err := GetTypeURL(coreDocument) assert.Nil(t, err, "should not throw an error because coreDocument has a type") diff --git a/coredocument/processor.go b/coredocument/processor.go index 84549feb4..f44b74775 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -61,19 +61,14 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) - id, err := dp.IdentityService.LookupIdentityForID(recipient) if err != nil { - err = centerrors.Wrap(err, "error fetching receiver identity") - log.Error(err) - return err + return centerrors.Wrap(err, "error fetching receiver identity") } lastB58Key, err := id.CurrentP2PKey() if err != nil { - err = centerrors.Wrap(err, "error fetching p2p key") - log.Error(err) - return err + return centerrors.Wrap(err, "error fetching p2p key") } log.Infof("Sending Document to CentID [%v] with Key [%v]\n", recipient, lastB58Key) @@ -84,12 +79,9 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } log.Infof("Done opening connection against [%s]\n", lastB58Key) - idConfig, err := identity.GetIdentityConfig() if err != nil { - err = centerrors.Wrap(err, "failed to extract bytes") - log.Error(err) - return err + return centerrors.Wrap(err, "failed to get IDConfig") } centIDBytes := idConfig.ID[:] @@ -98,11 +90,10 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config.GetNetworkID(), } - _, err = client.SendAnchoredDocument(context.Background(), &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: header}) - if err != nil { - err = centerrors.Wrap(err, "failed to post to the node") - log.Error(err) - return err + + resp, err := client.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: header}) + if err != nil || !resp.Accepted { + return centerrors.Wrap(err, "failed to send document to the node") } return nil diff --git a/documents/anchor_test.go b/documents/anchor_test.go index 35d5c071f..630adf0d9 100644 --- a/documents/anchor_test.go +++ b/documents/anchor_test.go @@ -9,7 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" ) @@ -33,7 +33,7 @@ func TestAnchorDocument(t *testing.T) { m = &testingdocuments.MockModel{} cd := coredocument.New() m.On("PackCoreDocument").Return(cd, nil).Once() - proc := &testingutils.MockCoreDocumentProcessor{} + proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(fmt.Errorf("error")).Once() model, err = documents.AnchorDocument(ctx, m, proc, updater) m.AssertExpectations(t) @@ -45,7 +45,7 @@ func TestAnchorDocument(t *testing.T) { // request signatures failed m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctx, m).Return(fmt.Errorf("error")).Once() model, err = documents.AnchorDocument(ctx, m, proc, updater) @@ -58,7 +58,7 @@ func TestAnchorDocument(t *testing.T) { // prepare for anchoring fails m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctx, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(fmt.Errorf("error")).Once() @@ -72,7 +72,7 @@ func TestAnchorDocument(t *testing.T) { // anchor fails m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctx, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() @@ -87,7 +87,7 @@ func TestAnchorDocument(t *testing.T) { // send failed m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctx, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() @@ -103,7 +103,7 @@ func TestAnchorDocument(t *testing.T) { // success m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctx, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 5a866f440..489a061d9 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -9,10 +9,6 @@ import ( "strconv" "testing" - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/code" @@ -21,6 +17,9 @@ import ( "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/signatures" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" @@ -45,12 +44,12 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(getRepository(), &testingutils.MockCoreDocumentProcessor{}, nil) + srv := DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() Service { - return DefaultService(getRepository(), &testingutils.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + return DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) } func createMockDocument() (*Invoice, error) { @@ -198,7 +197,7 @@ func TestService_Create(t *testing.T) { // anchor fails po, err := invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) assert.Nil(t, err) - proc := &testingutils.MockCoreDocumentProcessor{} + proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() invSrv.coreDocProcessor = proc m, err = invSrv.Create(ctx, po) @@ -210,7 +209,7 @@ func TestService_Create(t *testing.T) { // success po, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) assert.Nil(t, err) - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() proc.On("RequestSignatures", ctx, po).Return(nil).Once() proc.On("PrepareForAnchoring", po).Return(nil).Once() @@ -602,7 +601,7 @@ func TestService_Update(t *testing.T) { newData, err := invSrv.DeriveInvoiceData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - proc := &testingutils.MockCoreDocumentProcessor{} + proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() proc.On("RequestSignatures", ctx, newInv).Return(nil).Once() proc.On("PrepareForAnchoring", newInv).Return(nil).Once() diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 4125d244c..44e6e26c5 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -15,8 +15,8 @@ import ( "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/signatures" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -42,7 +42,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func getServiceWithMockedLayers() Service { - return DefaultService(getRepository(), &testingutils.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + return DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) } func TestService_Update(t *testing.T) { @@ -101,7 +101,7 @@ func TestService_Update(t *testing.T) { newData, err := poSrv.DerivePurchaseOrderData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - proc := &testingutils.MockCoreDocumentProcessor{} + proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() proc.On("RequestSignatures", ctx, newInv).Return(nil).Once() proc.On("PrepareForAnchoring", newInv).Return(nil).Once() @@ -263,7 +263,7 @@ func TestService_Create(t *testing.T) { // anchor fails po, err := poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) assert.Nil(t, err) - proc := &testingutils.MockCoreDocumentProcessor{} + proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() poSrv.coreDocProcessor = proc m, err = poSrv.Create(ctx, po) @@ -275,7 +275,7 @@ func TestService_Create(t *testing.T) { // success po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) assert.Nil(t, err) - proc = &testingutils.MockCoreDocumentProcessor{} + proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() proc.On("RequestSignatures", ctx, po).Return(nil).Once() proc.On("PrepareForAnchoring", po).Return(nil).Once() diff --git a/documents/registry_test.go b/documents/registry_test.go index 474b14ee6..9eb713b15 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -7,47 +7,38 @@ import ( cd "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" ) func TestRegistry_GetRegistryInstance(t *testing.T) { - registryFirst := documents.GetRegistryInstance() registrySecond := documents.GetRegistryInstance() - assert.Equal(t, ®istryFirst, ®istrySecond, "only one instance of registry should exist") } func TestRegistry_Register_LocateService_successful(t *testing.T) { - registry := documents.GetRegistryInstance() - a := &testingdocuments.MockService{} - coreDocument := testingutils.GenerateCoreDocument() + coreDocument := testingcoredocument.GenerateCoreDocument() documentType, err := cd.GetTypeURL(coreDocument) assert.Nil(t, err, "should not throw an error because core document contains a type") err = registry.Register(documentType, a) - assert.Nil(t, err, "register didn't work with unused id") b, err := registry.LocateService(documentType) assert.Nil(t, err, "service hasn't been registered properly") - assert.Equal(t, a, b, "locateService should return the same service ") - } func TestRegistry_Register_invalidId(t *testing.T) { - registry := documents.GetRegistryInstance() - a := &testingdocuments.MockService{} - coreDocument := testingutils.GenerateCoreDocument() + coreDocument := testingcoredocument.GenerateCoreDocument() coreDocument.EmbeddedData.TypeUrl = "testID_1" err := registry.Register(coreDocument.EmbeddedData.TypeUrl, a) @@ -58,18 +49,15 @@ func TestRegistry_Register_invalidId(t *testing.T) { err = registry.Register("testId", a) assert.Nil(t, err, "register didn't work with unused id") - } func TestRegistry_LocateService_invalid(t *testing.T) { - registry := documents.GetRegistryInstance() - coreDocument := testingutils.GenerateCoreDocument() + coreDocument := testingcoredocument.GenerateCoreDocument() coreDocument.EmbeddedData.TypeUrl = "testID_2" documentType, err := cd.GetTypeURL(coreDocument) assert.Nil(t, err, "should not throw an error because core document contains a type") _, err = registry.LocateService(documentType) assert.Error(t, err, "should throw an error because no services is registered") - } diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index e884e59cc..0b925b1ab 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -14,11 +14,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - client, err := NewClientConnection(config.Config) + client, err := NewGethClient(config.Config) if err != nil { return err } - SetConnection(client) + SetClient(client) context[bootstrap.BootstrappedEthereumClient] = client return nil } diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index b20c8f5a8..b5cf2f51b 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -2,6 +2,7 @@ package ethereum import ( "context" + "fmt" "math/big" "net/url" "reflect" @@ -13,42 +14,40 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" - "github.com/go-errors/errors" logging "github.com/ipfs/go-log" ) -const TransactionUnderpriced = "replacement transaction underpriced" -const NonceTooLow = "nonce too low" +const ( + transactionUnderpriced = "replacement transaction underpriced" + nonceTooLow = "nonce too low" +) var log = logging.Logger("geth-client") -var gc EthereumClient -var gcInit sync.Once +var gc Client +var gcMu sync.RWMutex // GetDefaultContextTimeout retrieves the default duration before an Ethereum write call context should time out func GetDefaultContextTimeout() time.Duration { return config.Config.GetEthereumContextWaitTimeout() } -// GetDefaultReadContextTimeout retrieves the default duration before an Ethereum read call context should time out -func GetDefaultReadContextTimeout() time.Duration { - return config.Config.GetEthereumContextReadWaitTimeout() -} - -// DefaultWaitForReadContext returns context with timeout for read operations -func DefaultWaitForReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { - toBeDone := time.Now().Add(GetDefaultReadContextTimeout()) +// defaultReadContext returns context with timeout for read operations +func defaultReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { + toBeDone := time.Now().Add(config.Config.GetEthereumContextReadWaitTimeout()) return context.WithDeadline(context.Background(), toBeDone) } // DefaultWaitForTransactionMiningContext returns context with timeout for write operations func DefaultWaitForTransactionMiningContext() (ctx context.Context, cancelFunc context.CancelFunc) { toBeDone := time.Now().Add(GetDefaultContextTimeout()) - return context.WithDeadline(context.TODO(), toBeDone) + return context.WithDeadline(context.Background(), toBeDone) } +// Config defines functions to get ethereum details type Config interface { GetEthereumGasPrice() *big.Int GetEthereumGasLimit() uint64 @@ -59,217 +58,251 @@ type Config interface { GetTxPoolAccessEnabled() bool } -// Abstract the "ethereum client" out so we can more easily support other clients -// besides Geth (e.g. quorum) -// Also make it easier to mock tests -type EthereumClient interface { - GetClient() *ethclient.Client - GetRpcClient() *rpc.Client - GetHost() *url.URL +// Client can be implemented by any chain client +type Client interface { + GetEthClient() *ethclient.Client + GetNodeURL() *url.URL GetTxOpts(accountName string) (*bind.TransactOpts, error) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) } -type GethClient struct { - Client *ethclient.Client - RpcClient *rpc.Client - Host *url.URL - Accounts map[string]*bind.TransactOpts - nonceMutex sync.Mutex - config Config +// gethClient implements Client for Ethereum +type gethClient struct { + client *ethclient.Client + rpcClient *rpc.Client + host *url.URL + accounts map[string]*bind.TransactOpts + accMu sync.Mutex // accMu to protect accounts + config Config + + // txMu to ensure one transaction at a time per client + txMu sync.Mutex } -func NewGethClient(config Config) *GethClient { - return &GethClient{ - nil, nil, nil, make(map[string]*bind.TransactOpts), sync.Mutex{}, config, +// NewGethClient returns an gethClient which implements Client +func NewGethClient(config Config) (Client, error) { + log.Info("Opening connection to Ethereum:", config.GetEthereumNodeURL()) + u, err := url.Parse(config.GetEthereumNodeURL()) + if err != nil { + return nil, fmt.Errorf("failed to parse ethereum node URL: %v", err) } -} -func (gethClient *GethClient) GetTxOpts(accountName string) (*bind.TransactOpts, error) { - if _, ok := gethClient.Accounts[accountName]; !ok { - txOpts, err := gethClient.getGethTxOpts(accountName) - if err != nil { - return nil, err - } - gethClient.Accounts[accountName] = txOpts + c, err := rpc.Dial(u.String()) + if err != nil { + return nil, fmt.Errorf("failed to connect to ethereum node: %v", err) } - gethClient.Accounts[accountName].Nonce = nil // Important to nil the nonce on the cached txopts, otherwise with high concurrency will be outdated - return gethClient.Accounts[accountName], nil -} -func (gethClient *GethClient) GetClient() *ethclient.Client { - return gethClient.Client + return &gethClient{ + client: ethclient.NewClient(c), + rpcClient: c, + host: u, + accounts: make(map[string]*bind.TransactOpts), + txMu: sync.Mutex{}, + accMu: sync.Mutex{}, + config: config, + }, nil } -func (gethClient *GethClient) GetRpcClient() *rpc.Client { - return gethClient.RpcClient +// SetClient sets the Client +// Note that this is a singleton and is the same connection for the whole application. +func SetClient(client Client) { + gcMu.Lock() + defer gcMu.Unlock() + gc = client } -func (gethClient *GethClient) GetHost() *url.URL { - return gethClient.Host +// GetClient returns the current Client +func GetClient() Client { + gcMu.RLock() + defer gcMu.RUnlock() + return gc } -func NewClientConnection(config Config) (*GethClient, error) { - log.Info("Opening connection to Ethereum:", config.GetEthereumNodeURL()) - u, err := url.Parse(config.GetEthereumNodeURL()) - if err != nil { - log.Errorf("Failed to connect to parse ethereum.gethSocket URL: %v", err) - return &GethClient{}, err - } - c, err := rpc.Dial(u.String()) - if err != nil { - log.Errorf("Failed to connect to the Ethereum client [%s]: %v", u.String(), err) - return &GethClient{}, err +// GetTxOpts returns a cached options if available else creates and returns new options +func (gc *gethClient) GetTxOpts(accountName string) (*bind.TransactOpts, error) { + gc.accMu.Lock() + defer gc.accMu.Unlock() + + if opts, ok := gc.accounts[accountName]; ok { + return opts, nil } - client := ethclient.NewClient(c) + + txOpts, err := gc.getGethTxOpts(accountName) if err != nil { - log.Errorf("Failed to connect to the Ethereum client [%s]: %v", u.String(), err) - return &GethClient{}, err + return nil, err } - gethClient := NewGethClient(config) - gethClient.Client = client - gethClient.RpcClient = c - gethClient.Host = u - - return gethClient, nil + gc.accounts[accountName] = txOpts + return txOpts, nil } -// Note that this is a singleton and is the same connection for the whole application. -func SetConnection(conn EthereumClient) { - gcInit.Do(func() { - gc = conn - }) - return +// GetEthClient returns the ethereum client +func (gc *gethClient) GetEthClient() *ethclient.Client { + return gc.client } -// GetConnection returns the connection to the configured `ethereum.gethSocket`. -func GetConnection() EthereumClient { - return gc +// GetNodeURL returns the node url +func (gc *gethClient) GetNodeURL() *url.URL { + return gc.host } // getGethTxOpts retrieves the geth transaction options for the given account name. The account name influences which configuration // is used. -func (gethClient *GethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, error) { - account, err := gethClient.config.GetEthereumAccount(accountName) +func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, error) { + account, err := gc.config.GetEthereumAccount(accountName) if err != nil { - err = errors.Errorf("could not find configured ethereum key for account [%v]. please check your configuration.\n", accountName) - log.Error(err.Error()) - return nil, err + return nil, fmt.Errorf("failed to get ethereum account: %v", err) } - authedTransactionOpts, err := bind.NewTransactor(strings.NewReader(account.Key), account.Password) + opts, err := bind.NewTransactor(strings.NewReader(account.Key), account.Password) if err != nil { - err = errors.Errorf("Failed to load key with error: %v", err) - log.Error(err.Error()) - return nil, err - } else { - authedTransactionOpts.GasPrice = gethClient.config.GetEthereumGasPrice() - authedTransactionOpts.GasLimit = gethClient.config.GetEthereumGasLimit() - authedTransactionOpts.Context = context.Background() - return authedTransactionOpts, nil + return nil, fmt.Errorf("failed to create new transaction opts: %v", err) } + + opts.GasPrice = gc.config.GetEthereumGasPrice() + opts.GasLimit = gc.config.GetEthereumGasLimit() + opts.Context = context.Background() + return opts, nil } /** -Blocking Function that sends transaction using reflection wrapped in a retrial block. It is based on the TransactionUnderpriced error, +SubmitTransactionWithRetries submits transaction to the ethereum chain +Blocking Function that sends transaction using reflection wrapped in a retrial block. It is based on the transactionUnderpriced error, meaning that a transaction is being attempted to run twice, and the logic is to override the existing one. As we have constant gas prices that means that a concurrent transaction race condition event has happened. - contractMethod: Contract Method that implements GenericEthereumAsset (usually autogenerated binding from abi) - params: Arbitrary number of parameters that are passed to the function fname call +Note: contractMethod must always return "*types.Transaction, error" */ -func (gethClient *GethClient) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) { - done := false - maxTries := gethClient.config.GetEthereumMaxRetries() - current := 0 - var f reflect.Value - var in []reflect.Value - var result []reflect.Value - f = reflect.ValueOf(contractMethod) - - gethClient.nonceMutex.Lock() - defer gethClient.nonceMutex.Unlock() - - for !done { +func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*types.Transaction, error) { + var current int + f := reflect.ValueOf(contractMethod) + maxTries := gc.config.GetEthereumMaxRetries() + + gc.txMu.Lock() + defer gc.txMu.Unlock() + + var err error + for { + if current >= maxTries { - log.Error("Max Concurrent transaction tries reached") - break + return nil, fmt.Errorf("max concurrent transaction tries reached: %v", err) } - current += 1 - err = gethClient.incrementNonce(opts) + current++ + err = incrementNonce(opts, gc.config.GetTxPoolAccessEnabled(), gc.client, gc.rpcClient) if err != nil { - return + return nil, fmt.Errorf("failed to increment nonce: %v", err) + } + + if opts.Nonce != nil { + log.Infof("Incrementing Nonce to [%v]\n", opts.Nonce.String()) } - in = make([]reflect.Value, len(params)+1) - val := reflect.ValueOf(opts) - in[0] = val - for k, param := range params { - in[k+1] = reflect.ValueOf(param) + + var in []reflect.Value + in = append(in, reflect.ValueOf(opts)) + for _, p := range params { + in = append(in, reflect.ValueOf(p)) + } + + result := f.Call(in) + var tx *types.Transaction + if !result[0].IsNil() { + tx = result[0].Interface().(*types.Transaction) } - result = f.Call(in) - tx = result[0].Interface().(*types.Transaction) - err = nil - if result[1].Interface() != nil { + + if !result[1].IsNil() { err = result[1].Interface().(error) } - if err != nil { - if (err.Error() == TransactionUnderpriced) || (err.Error() == NonceTooLow) { - log.Warningf("Concurrent transaction identified, trying again [%d/%d]\n", current, maxTries) - time.Sleep(gethClient.config.GetEthereumIntervalRetry()) - } else { - done = true - } - } else { - done = true + if err == nil { + return tx, nil + } + + if (err.Error() == transactionUnderpriced) || (err.Error() == nonceTooLow) { + log.Warningf("Concurrent transaction identified, trying again [%d/%d]\n", current, maxTries) + time.Sleep(gc.config.GetEthereumIntervalRetry()) + continue } + + return nil, err } - return } -func (gethClient *GethClient) incrementNonce(opts *bind.TransactOpts) (err error) { - if !gethClient.config.GetTxPoolAccessEnabled() { - log.Warningf("Ethereum Client doesn't support txpool API, may cause concurrency issues.") - return +// noncer defines functions to get the next nonce +type noncer interface { + PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) +} + +// callContexter defines functions to get CallContext +type callContexter interface { + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error +} + +// incrementNonce updates the opts.Nonce to next valid nonce +// We pick the current nonce by getting latest transactions included in the blocks including pending blocks +// then we check the txpool to see if there any new transactions from the address that are not included in any block +// If there are no pending transactions in txpool, we use the current nonce + 1 +// else we increment the greater of current nonce or the nonce derived from txpool +func incrementNonce(opts *bind.TransactOpts, txpoolAccessEnabled bool, noncer noncer, cc callContexter) error { + // check if the txpool access is enabled + if !txpoolAccessEnabled { + log.Warningf("Ethereum Client doesn't support txpool API, may cause transactions failures") + opts.Nonce = nil + return nil } - var res map[string]map[string]map[string][]string - // Important to not create a DeadLock if network latency - txctx, _ := context.WithTimeout(context.Background(), GetDefaultContextTimeout()) - gc.GetRpcClient().CallContext(txctx, &res, "txpool_inspect") + ctx, cancel := context.WithTimeout(context.Background(), GetDefaultContextTimeout()) + defer cancel() - if len(res["pending"][opts.From.Hex()]) > 0 { - chainNonce, err := gc.GetClient().PendingNonceAt(txctx, opts.From) - if err != nil { - log.Errorf("Error found when getting the Account Chain Nonce [%v]\n", err) - return err - } - CalculateIncrement(chainNonce, res, opts) + // get current nonce + n, err := noncer.PendingNonceAt(ctx, opts.From) + if err != nil { + return fmt.Errorf("failed to get chain nonce for %s: %v", opts.From.String(), err) } - return -} + // set the nonce + opts.Nonce = new(big.Int).SetUint64(n) + + // check for any transactions in txpool + res := make(map[string]map[string]map[string]string) + err = cc.CallContext(ctx, &res, "txpool_inspect") + if err != nil { + return fmt.Errorf("failed to get txpool data: %v", err) + } -func CalculateIncrement(chainNonce uint64, res map[string]map[string]map[string][]string, opts *bind.TransactOpts) { - keys := make([]int, 0, len(res["pending"][opts.From.Hex()])) + // no pending transaction from this account in tx pool + if len(res["pending"][opts.From.Hex()]) < 1 { + return nil + } + + var keys []int for k, _ := range res["pending"][opts.From.Hex()] { - ki, _ := strconv.Atoi(k) + ki, err := strconv.Atoi(k) + if err != nil { + return fmt.Errorf("failed to convert nonce: %v", err) + } + keys = append(keys, ki) } + + // there are some pending transactions in txpool, check their nonce + // pick the largest one and increment it sort.Ints(keys) lastPoolNonce := keys[len(keys)-1] - if uint64(lastPoolNonce) >= chainNonce { + if uint64(lastPoolNonce) >= n { opts.Nonce = new(big.Int).Add(big.NewInt(int64(lastPoolNonce)), big.NewInt(1)) - log.Infof("Incrementing Nonce to [%v]\n", opts.Nonce.String()) } + + return nil } +// GetGethCallOpts returns the Call options with default func GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { // Assuring that pending transactions are taken into account by go-ethereum when asking for things like // specific transactions and client's nonce // with timeout context, in case eth node is not in sync - ctx, cancelFunc := DefaultWaitForReadContext() - return &bind.CallOpts{Pending: true, Context: ctx}, cancelFunc + ctx, cancel := defaultReadContext() + return &bind.CallOpts{Pending: true, Context: ctx}, cancel } diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index bdc99ca79..5055a4b36 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -6,6 +6,7 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/stretchr/testify/assert" @@ -20,14 +21,20 @@ func TestMain(m *testing.M) { func TestGetConnection_returnsSameConnection(t *testing.T) { howMany := 5 - confChannel := make(chan ethereum.EthereumClient, howMany) + confChannel := make(chan ethereum.Client, howMany) for ix := 0; ix < howMany; ix++ { go func() { - confChannel <- ethereum.GetConnection() + confChannel <- ethereum.GetClient() }() } for ix := 0; ix < howMany; ix++ { multiThreadCreatedCon := <-confChannel - assert.Equal(t, multiThreadCreatedCon, ethereum.GetConnection(), "Should only return a single ethereum client") + assert.Equal(t, multiThreadCreatedCon, ethereum.GetClient(), "Should only return a single ethereum client") } } + +func TestNewGethClient(t *testing.T) { + gc, err := ethereum.NewGethClient(config.Config) + assert.Nil(t, err) + assert.NotNil(t, gc) +} diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index be2d1fe1d..cbfba9ba8 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -1,35 +1,31 @@ // +build unit -package ethereum_test +package ethereum import ( - "math/big" + "context" + "fmt" "os" + "sync" "testing" "time" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/documents/purchaseorder" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/go-errors/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, - &invoice.Bootstrapper{}, - &purchaseorder.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, nil) config.Config.V.Set("ethereum.txPoolAccessEnabled", false) @@ -39,10 +35,6 @@ func TestMain(m *testing.M) { os.Exit(result) } -type MockTransactionInterface interface { - RegisterTransaction(opts *bind.TransactOpts, someVar string, anotherVar string) (tx *types.Transaction, err error) -} - type MockTransactionRequest struct { count int } @@ -52,10 +44,10 @@ func (transactionRequest *MockTransactionRequest) RegisterTransaction(opts *bind if transactionName == "otherError" { err = errors.Wrap("Some other error", 1) } else if transactionName == "optimisticLockingTimeout" { - err = errors.Wrap(ethereum.TransactionUnderpriced, 1) + err = errors.Wrap(transactionUnderpriced, 1) } else if transactionName == "optimisticLockingEventualSuccess" { if transactionRequest.count < 3 { - err = errors.Wrap(ethereum.TransactionUnderpriced, 1) + err = errors.Wrap(transactionUnderpriced, 1) } } tx = types.NewTransaction(1, common.Address{}, nil, 0, nil, nil) @@ -65,17 +57,23 @@ func (transactionRequest *MockTransactionRequest) RegisterTransaction(opts *bind func TestInitTransactionWithRetries(t *testing.T) { mockRequest := &MockTransactionRequest{} - gc := ethereum.NewGethClient(config.Config) - ethereum.SetConnection(gc) + gc := &gethClient{ + accounts: make(map[string]*bind.TransactOpts), + accMu: sync.Mutex{}, + txMu: sync.Mutex{}, + config: config.Config, + } + + SetClient(gc) // Success at first - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "var1", "var2") + tx, err := gc.SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "var1", "var2") assert.Nil(t, err, "Should not error out") assert.EqualValues(t, 1, tx.Nonce(), "Nonce should equal to the one provided") assert.EqualValues(t, 1, mockRequest.count, "Transaction Run flag should be true") // Failure with non-locking error - tx, err = ethereum.GetConnection().SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "otherError", "var2") + tx, err = gc.SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "otherError", "var2") assert.EqualError(t, err, "Some other error", "Should error out") mockRetries := testingutils.MockConfigOption("ethereum.maxRetries", 10) @@ -83,41 +81,112 @@ func TestInitTransactionWithRetries(t *testing.T) { mockRequest.count = 0 // Failure and timeout with locking error - tx, err = ethereum.GetConnection().SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "optimisticLockingTimeout", "var2") - assert.EqualError(t, err, ethereum.TransactionUnderpriced, "Should error out") + tx, err = gc.SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "optimisticLockingTimeout", "var2") + assert.Contains(t, err.Error(), transactionUnderpriced, "Should error out") assert.EqualValues(t, 10, mockRequest.count, "Retries should be equal") mockRequest.count = 0 // Success after locking race condition overcome - tx, err = ethereum.GetConnection().SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "optimisticLockingEventualSuccess", "var2") + tx, err = gc.SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "optimisticLockingEventualSuccess", "var2") assert.Nil(t, err, "Should not error out") assert.EqualValues(t, 3, mockRequest.count, "Retries should be equal") } -func TestCalculateIncrement(t *testing.T) { - strAddress := "0x45B9c4798999FFa52e1ff1eFce9d3e45819E4158" - var input = map[string]map[string]map[string][]string{ +func TestGetGethCallOpts(t *testing.T) { + opts, cancel := GetGethCallOpts() + assert.NotNil(t, opts) + assert.True(t, opts.Pending) + assert.NotNil(t, cancel) + cancel() +} + +type mockNoncer struct { + mock.Mock +} + +func (m *mockNoncer) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + args := m.Called(ctx, account) + n, _ := args.Get(0).(uint64) + return n, args.Error(1) +} + +func (m *mockNoncer) CallContext(ctx context.Context, result interface{}, method string, a ...interface{}) error { + args := m.Called(ctx, result, method, a) + if args.Get(0) != nil { + res := result.(*map[string]map[string]map[string]string) + *res = args.Get(0).(map[string]map[string]map[string]string) + } + + return args.Error(1) +} + +func Test_incrementNonce(t *testing.T) { + opts := &bind.TransactOpts{From: common.HexToAddress("0x45B9c4798999FFa52e1ff1eFce9d3e45819E4158")} + + // txpool access disabled + err := incrementNonce(opts, false, nil, nil) + assert.Nil(t, err) + assert.Nil(t, opts.Nonce) + + // noncer failed + n := new(mockNoncer) + n.On("PendingNonceAt", mock.Anything, opts.From).Return(0, fmt.Errorf("error")).Once() + err = incrementNonce(opts, true, n, nil) + n.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get chain nonce") + + // rpc call failed + n = new(mockNoncer) + n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(100), nil).Once() + n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, fmt.Errorf("error")).Once() + err = incrementNonce(opts, true, n, n) + n.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get txpool data") + assert.Equal(t, "100", opts.Nonce.String()) + + // no pending txns in the tx pool + n = new(mockNoncer) + n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() + n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, nil).Once() + err = incrementNonce(opts, true, n, n) + n.AssertExpectations(t) + assert.Nil(t, err) + assert.Equal(t, "1000", opts.Nonce.String()) + + // bad result + var res = map[string]map[string]map[string]string{ "pending": { - strAddress: { - "0": {"0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas"}, - "1": {"0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas"}, - "2": {"0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas"}, - "3": {"0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas"}, + opts.From.String(): { + "abc": "0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas", }, }, } - - opts := &bind.TransactOpts{From: common.HexToAddress(strAddress)} - - // OnChain Transaction Count is behind local tx pool - chainNonce := 3 - expectedNonce := 4 - ethereum.CalculateIncrement(uint64(chainNonce), input, opts) - assert.Equal(t, big.NewInt(int64(expectedNonce)), opts.Nonce, "Nonce should match expected value") - - // OnChain Transaction Count is ahead of local tx pool, means that txs will get stuck forever (Rare case) - chainNonce = 4 - expectedNonce = 4 - ethereum.CalculateIncrement(uint64(chainNonce), input, opts) - assert.Equal(t, big.NewInt(int64(expectedNonce)), opts.Nonce, "Nonce should match expected value") + n = new(mockNoncer) + n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() + n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(res, nil).Once() + err = incrementNonce(opts, true, n, n) + n.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to convert nonce") + + // higher nonce in txpool + res = map[string]map[string]map[string]string{ + "pending": { + opts.From.String(): { + "1000": "0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas", + "1001": "0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas", + "1002": "0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas", + "1003": "0x958c1fa64b34db746925c6f8a3dd81128e40355e: 1051546810000000000 wei + 90000 × 20000000000 gas", + }, + }, + } + n = new(mockNoncer) + n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() + n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(res, nil).Once() + err = incrementNonce(opts, true, n, n) + n.AssertExpectations(t) + assert.Nil(t, err) + assert.Equal(t, "1004", opts.Nonce.String()) } diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 936d754d6..22186455c 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -54,11 +54,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } func getIdentityFactoryContract() (identityFactoryContract *EthereumIdentityFactoryContract, err error) { - client := ethereum.GetConnection() - return NewEthereumIdentityFactoryContract(config.Config.GetContractAddress("identityFactory"), client.GetClient()) + client := ethereum.GetClient() + return NewEthereumIdentityFactoryContract(config.Config.GetContractAddress("identityFactory"), client.GetEthClient()) } func getIdentityRegistryContract() (identityRegistryContract *EthereumIdentityRegistryContract, err error) { - client := ethereum.GetConnection() - return NewEthereumIdentityRegistryContract(config.Config.GetContractAddress("identityRegistry"), client.GetClient()) + client := ethereum.GetClient() + return NewEthereumIdentityRegistryContract(config.Config.GetContractAddress("identityRegistry"), client.GetEthClient()) } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index ca9ebe767..eb81c0810 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -151,8 +151,8 @@ func (id *ethereumIdentity) findContract() (exists bool, err error) { return false, errors.New("Identity not found by address provided") } - client := ethereum.GetConnection() - idContract, err := NewEthereumIdentityContract(idAddress, client.GetClient()) + client := ethereum.GetClient() + idContract, err := NewEthereumIdentityContract(idAddress, client.GetEthClient()) if err == bind.ErrNoCode { return false, err } @@ -193,13 +193,13 @@ func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int return confirmations, err } - conn := ethereum.GetConnection() - opts, err := ethereum.GetConnection().GetTxOpts(id.config.GetEthereumDefaultAccountName()) + conn := ethereum.GetClient() + opts, err := ethereum.GetClient().GetTxOpts(id.config.GetEthereumDefaultAccountName()) if err != nil { return confirmations, err } - h, err := conn.GetClient().HeaderByNumber(ctx, nil) + h, err := conn.GetEthClient().HeaderByNumber(ctx, nil) if err != nil { return confirmations, err } @@ -255,7 +255,7 @@ func sendKeyRegistrationTransaction(identityContract contract, opts *bind.Transa return err } - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(identityContract.AddKey, opts, bKey, bigInt) + tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityContract.AddKey, opts, bKey, bigInt) if err != nil { log.Infof("Failed to send key [%v:%x] to add to CentrifugeID [%x]: %v", keyPurpose, bKey, identity.CentID, err) return err @@ -268,8 +268,7 @@ func sendKeyRegistrationTransaction(identityContract contract, opts *bind.Transa // sendIdentityCreationTransaction sends the actual transaction to create identity on Ethereum registry contract func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated Identity) (err error) { //preparation of data in specific types for the call to Ethereum - tx, err := ethereum.GetConnection().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) - + tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) if err != nil { log.Infof("Failed to send identity for creation [CentrifugeID: %s] : %v", identityToBeCreated, err) return err @@ -354,13 +353,13 @@ func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (ex func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) - conn := ethereum.GetConnection() + conn := ethereum.GetClient() opts, err := conn.GetTxOpts(ids.config.GetEthereumDefaultAccountName()) if err != nil { return nil, confirmations, err } - h, err := conn.GetClient().HeaderByNumber(context.Background(), nil) + h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) if err != nil { return nil, confirmations, err } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 15104cc1a..244b18726 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -25,11 +25,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } - setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetConnection(), config.Config)) + setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config)) return nil } func getPaymentObligationContract() (*EthereumPaymentObligationContract, error) { - client := ethereum.GetConnection() - return NewEthereumPaymentObligationContract(config.Config.GetContractAddress("paymentObligation"), client.GetClient()) + client := ethereum.GetClient() + return NewEthereumPaymentObligationContract(config.Config.GetContractAddress("paymentObligation"), client.GetEthClient()) } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 5d788d6a7..4e9b4fd28 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -45,12 +45,12 @@ type ethereumPaymentObligationContract interface { type ethereumPaymentObligation struct { paymentObligation ethereumPaymentObligationContract identityService identity.Service - ethClient ethereum.EthereumClient + ethClient ethereum.Client config Config } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func NewEthereumPaymentObligation(paymentObligation ethereumPaymentObligationContract, identityService identity.Service, ethClient ethereum.EthereumClient, config Config) *ethereumPaymentObligation { +func NewEthereumPaymentObligation(paymentObligation ethereumPaymentObligationContract, identityService identity.Service, ethClient ethereum.Client, config Config) *ethereumPaymentObligation { return ðereumPaymentObligation{paymentObligation: paymentObligation, identityService: identityService, ethClient: ethClient, config: config} } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 3889721de..219436b07 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -15,7 +15,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" ) @@ -41,7 +41,7 @@ func TestMain(m *testing.M) { func TestPaymentObligationService_mint(t *testing.T) { // create identity - testingutils.CreateIdentityWithKeys() + testingidentity.CreateIdentityWithKeys() // create invoice (anchor) service, err := documents.GetRegistryInstance().LocateService(documenttypes.InvoiceDataTypeUrl) diff --git a/notification/notification_test.go b/notification/notification_test.go index c2df4e10c..3340a1868 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/ptypes" @@ -36,7 +35,7 @@ func TestMain(m *testing.M) { func TestWebhookConstructPayload(t *testing.T) { documentIdentifier := utils.RandomSlice(32) coredoc := &coredocumentpb.CoreDocument{DocumentIdentifier: documentIdentifier} - cid := testingutils.Rand32Bytes() + cid := utils.RandomSlice(32) ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") diff --git a/p2p/client_test.go b/p2p/client_test.go index 435240d2e..792a1ca7b 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -15,8 +15,8 @@ import ( "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" @@ -37,7 +37,7 @@ func TestMain(m *testing.M) { func TestGetSignatureForDocument_fail_connect(t *testing.T) { client := &testingcommons.P2PMockClient{} - coreDoc := testingutils.GenerateCoreDocument() + coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) @@ -51,7 +51,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { func TestGetSignatureForDocument_fail_version_check(t *testing.T) { client := &testingcommons.P2PMockClient{} - coreDoc := testingutils.GenerateCoreDocument() + coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} @@ -68,7 +68,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { client := &testingcommons.P2PMockClient{} - coreDoc := testingutils.GenerateCoreDocument() + coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 25c08faf0..89da3ca79 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -21,8 +21,8 @@ import ( "github.com/centrifuge/go-centrifuge/notification" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/signatures" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" "github.com/centrifuge/precise-proofs/proofs" @@ -278,7 +278,7 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument idConfig, err := identity.GetIdentityConfig() assert.Nil(t, err) if doc == nil { - doc = testingutils.GenerateCoreDocument() + doc = testingcoredocument.GenerateCoreDocument() } tree, _ := coredocument.GetDocumentSigningTree(doc) doc.SigningRoot = tree.RootHash() diff --git a/p2p/handler_test.go b/p2p/handler_test.go index f7d9ee410..028fb040b 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -17,7 +17,7 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" @@ -35,7 +35,7 @@ func (wh *MockWebhookSender) Send(notification *notificationpb.NotificationMessa return } -var coreDoc = testingutils.GenerateCoreDocument() +var coreDoc = testingcoredocument.GenerateCoreDocument() func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ diff --git a/signatures/signatures_test.go b/signatures/signatures_test.go index ca87b4b8b..486ca69eb 100644 --- a/signatures/signatures_test.go +++ b/signatures/signatures_test.go @@ -8,8 +8,8 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -22,7 +22,7 @@ var ( ) func TestSign(t *testing.T) { - coreDoc := testingutils.GenerateCoreDocument() + coreDoc := testingcoredocument.GenerateCoreDocument() coreDoc.SigningRoot = key1Pub centID, err := identity.ToCentID(id1) assert.Nil(t, err) @@ -75,22 +75,16 @@ func TestValidateSignature_success(t *testing.T) { } func TestValidateCentrifugeId(t *testing.T) { - randomBytes := utils.RandomSlice(identity.CentIDLength) - - centrifugeId, err := identity.ToCentID(randomBytes) - - assert.Nil(t, err, "centrifugeId not initialized correctly ") + centID, err := identity.ToCentID(randomBytes) + assert.Nil(t, err, "centID not initialized correctly ") sig := &coredocumentpb.Signature{EntityId: randomBytes} - - err = ValidateCentrifugeID(sig, centrifugeId) + err = ValidateCentrifugeID(sig, centID) assert.Nil(t, err, "Validate centrifuge id didn't work correctly") randomBytes = utils.RandomSlice(identity.CentIDLength) - centrifugeId, err = identity.ToCentID(randomBytes) - - err = ValidateCentrifugeID(sig, centrifugeId) + centID, err = identity.ToCentID(randomBytes) + err = ValidateCentrifugeID(sig, centID) assert.NotNil(t, err, "Validate centrifuge id didn't work correctly") - } diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index 6139c1cd0..b1f790135 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" "github.com/stretchr/testify/mock" ) @@ -16,18 +15,13 @@ type MockEthClient struct { mock.Mock } -func (m *MockEthClient) GetClient() *ethclient.Client { +func (m *MockEthClient) GetEthClient() *ethclient.Client { args := m.Called() c, _ := args.Get(0).(*ethclient.Client) return c } -func (m *MockEthClient) GetRpcClient() *rpc.Client { - args := m.Called() - return args.Get(0).(*rpc.Client) -} - -func (m *MockEthClient) GetHost() *url.URL { +func (m *MockEthClient) GetNodeURL() *url.URL { args := m.Called() return args.Get(0).(*url.URL) } diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go new file mode 100644 index 000000000..bd98c48c2 --- /dev/null +++ b/testingutils/coredocument/coredocument.go @@ -0,0 +1,89 @@ +// +build integration unit + +package testingcoredocument + +import ( + "context" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/golang/protobuf/ptypes/any" + "github.com/stretchr/testify/mock" +) + +func GenerateCoreDocument() *coredocumentpb.CoreDocument { + identifier := utils.RandomSlice(32) + salts := &coredocumentpb.CoreDocumentSalts{} + doc := &coredocumentpb.CoreDocument{ + DataRoot: utils.RandomSlice(32), + DocumentIdentifier: identifier, + CurrentVersion: identifier, + NextVersion: utils.RandomSlice(32), + CoredocumentSalts: salts, + EmbeddedData: &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + }, + EmbeddedDataSalts: &any.Any{ + TypeUrl: documenttypes.InvoiceSaltsTypeUrl, + }, + } + proofs.FillSalts(doc, salts) + return doc +} + +type MockCoreDocumentProcessor struct { + mock.Mock +} + +func (m *MockCoreDocumentProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { + args := m.Called(coreDocument, ctx, recipient) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) Anchor( + ctx context.Context, + coreDocument *coredocumentpb.CoreDocument, + saveState func(*coredocumentpb.CoreDocument) error) (err error) { + args := m.Called(ctx, coreDocument, saveState) + if saveState != nil { + err := saveState(coreDocument) + if err != nil { + return err + } + } + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { + args := m.Called(ctx, model) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) AnchorDocument(model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) SendDocument(ctx context.Context, model documents.Model) error { + args := m.Called(ctx, model) + return args.Error(0) +} + +func (m *MockCoreDocumentProcessor) GetDataProofHashes(coreDocument *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { + args := m.Called(coreDocument) + return args.Get(0).([][]byte), args.Error(1) +} diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go new file mode 100644 index 000000000..55e71dd2c --- /dev/null +++ b/testingutils/identity/identity.go @@ -0,0 +1,38 @@ +// +build integration unit + +package testingidentity + +import ( + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" +) + +func CreateIdentityWithKeys() identity.CentID { + idConfig, _ := identity.GetIdentityConfig() + // only create identity if it doesn't exist + id, err := identity.IDService.LookupIdentityForID(idConfig.ID) + if err != nil { + _, confirmations, _ := identity.IDService.CreateIdentity(idConfig.ID) + <-confirmations + // LookupIdentityForId + id, _ = identity.IDService.LookupIdentityForID(idConfig.ID) + } + + // only add key if it doesn't exist + _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() + defer cancel() + if err != nil { + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) + <-confirmations + } + _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) + ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext() + defer cancel() + if err != nil { + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) + <-confirmations + } + + return idConfig.ID +} diff --git a/testingutils/utils.go b/testingutils/utils.go index 62c5ccf17..9fefd8254 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -3,19 +3,7 @@ package testingutils import ( - "context" - "crypto/rand" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/mock" ) func MockConfigOption(key string, value interface{}) func() { @@ -26,85 +14,6 @@ func MockConfigOption(key string, value interface{}) func() { } } -func Rand32Bytes() []byte { - bytes := make([]byte, 32) - rand.Read(bytes) - return bytes -} - -func GenerateCoreDocument() *coredocumentpb.CoreDocument { - identifier := Rand32Bytes() - salts := &coredocumentpb.CoreDocumentSalts{} - doc := &coredocumentpb.CoreDocument{ - DataRoot: utils.RandomSlice(32), - DocumentIdentifier: identifier, - CurrentVersion: identifier, - NextVersion: Rand32Bytes(), - CoredocumentSalts: salts, - EmbeddedData: &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - }, - EmbeddedDataSalts: &any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - }, - } - proofs.FillSalts(doc, salts) - return doc -} - -type MockCoreDocumentProcessor struct { - mock.Mock -} - -func (m *MockCoreDocumentProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { - args := m.Called(coreDocument, ctx, recipient) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) Anchor( - ctx context.Context, - coreDocument *coredocumentpb.CoreDocument, - saveState func(*coredocumentpb.CoreDocument) error) (err error) { - args := m.Called(ctx, coreDocument, saveState) - if saveState != nil { - err := saveState(coreDocument) - if err != nil { - return err - } - } - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { - args := m.Called(ctx, model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) AnchorDocument(model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) SendDocument(ctx context.Context, model documents.Model) error { - args := m.Called(ctx, model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) GetDataProofHashes(coreDocument *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { - args := m.Called(coreDocument) - return args.Get(0).([][]byte), args.Error(1) -} - type MockSubscription struct { ErrChan chan error } @@ -114,33 +23,3 @@ func (m *MockSubscription) Err() <-chan error { } func (*MockSubscription) Unsubscribe() {} - -func CreateIdentityWithKeys() identity.CentID { - idConfig, _ := identity.GetIdentityConfig() - // only create identity if it doesn't exist - id, err := identity.IDService.LookupIdentityForID(idConfig.ID) - if err != nil { - _, confirmations, _ := identity.IDService.CreateIdentity(idConfig.ID) - <-confirmations - // LookupIdentityForId - id, _ = identity.IDService.LookupIdentityForID(idConfig.ID) - } - - // only add key if it doesn't exist - _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() - defer cancel() - if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) - <-confirmations - } - _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) - ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext() - defer cancel() - if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) - <-confirmations - } - - return idConfig.ID -} From b27a4da870956b8c5bc73c72895ff010361141e9 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 2 Nov 2018 15:45:37 +0100 Subject: [PATCH 013/220] fix the race condition with config (#401) Fixes #389 Fixes #362 Turns out both the issues were due to `config.Config` variable being accessed at the same time. #389, it is accessed in `notification.Send` and in #362 it is accessed to set Config to nil in `config/test_bootstrapper.go`. All the tests share a global namespace and since they are run in parallel and each time the `config/test_boostrapper` is run in each test, which is updating `config.Config`, the race condition happens. Added a functions to set and get config with mutex. --- anchors/bootstrapper.go | 4 +- anchors/ethereum_anchor_repository_test.go | 2 +- cmd/create_config.go | 6 +- config/bootstrapper.go | 7 +- config/configuration.go | 171 ++++++++++++------ config/test_bootstrapper.go | 9 +- coredocument/coredocument_test.go | 6 +- coredocument/processor.go | 4 +- coredocument/processor_test.go | 20 +- coredocument/validator_test.go | 8 +- ethereum/bootstrapper.go | 2 +- ethereum/geth_client.go | 4 +- ethereum/geth_client_integration_test.go | 2 +- ethereum/geth_client_test.go | 6 +- healthcheck/handler.go | 2 +- healthcheck/handler_test.go | 2 +- identity/bootstrapper.go | 8 +- .../ethereum_identity_integration_test.go | 24 +-- identity/identity.go | 2 +- identity/identity_test.go | 34 ++-- keytools/ed25519/ed25519.go | 2 +- keytools/ed25519/ed25519_test.go | 12 +- keytools/secp256k1/secp256k1.go | 2 +- keytools/secp256k1/secp256k1_test.go | 12 +- nft/bootstrapper.go | 4 +- nft/payment_obligation_integration_test.go | 24 +-- node/bootstrapper.go | 10 +- notification/notification.go | 2 +- p2p/client.go | 6 +- p2p/handler_integration_test.go | 14 +- p2p/handler_test.go | 18 +- p2p/server.go | 2 +- p2p/server_test.go | 4 +- p2p/validator.go | 4 +- p2p/validator_test.go | 6 +- queue/queue.go | 4 +- storage/bootstrapper.go | 2 +- storage/test_bootstrapper.go | 8 +- testingutils/utils.go | 6 +- 39 files changed, 264 insertions(+), 201 deletions(-) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 10dc84884..09fe3d58f 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -23,12 +23,12 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } client := ethereum.GetClient() - repositoryContract, err := NewEthereumAnchorRepositoryContract(config.Config.GetContractAddress("anchorRepository"), client.GetEthClient()) + repositoryContract, err := NewEthereumAnchorRepositoryContract(config.Config().GetContractAddress("anchorRepository"), client.GetEthClient()) if err != nil { return err } - anchorRepo := NewEthereumAnchorRepository(config.Config, repositoryContract) + anchorRepo := NewEthereumAnchorRepository(config.Config(), repositoryContract) setAnchorRepository(anchorRepo) if err != nil { return err diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 1b1f1c9b2..a71fa9f58 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -77,7 +77,7 @@ func TestGetDocumentRootOf(t *testing.T) { anchorID, err := ToAnchorID(utils.RandomSlice(32)) assert.Nil(t, err) - ethRepo := NewEthereumAnchorRepository(config.Config, repo) + ethRepo := NewEthereumAnchorRepository(config.Config(), repo) docRoot := utils.RandomByte32() repo.On("Commits", mock.Anything, mock.Anything).Return(docRoot, nil) gotRoot, err := ethRepo.GetDocumentRootOf(anchorID) diff --git a/cmd/create_config.go b/cmd/create_config.go index 0cb319bf0..91eccc3f8 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -31,8 +31,8 @@ func createIdentity() (identity.CentID, error) { } func generateKeys() { - p2pPub, p2pPvt := config.Config.GetSigningKeyPair() - ethAuthPub, ethAuthPvt := config.Config.GetEthAuthKeyPair() + p2pPub, p2pPvt := config.Config().GetSigningKeyPair() + ethAuthPub, ethAuthPvt := config.Config().GetEthAuthKeyPair() keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") @@ -97,7 +97,7 @@ func init() { if err != nil { log.Fatalf("error: %v", err) } - config.Config.V.Set("identityId", id.String()) + config.Config().Set("identityId", id.String()) log.Infof("Identity created [%s] [%x]", id.String(), id) diff --git a/config/bootstrapper.go b/config/bootstrapper.go index a83160468..c8566617e 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -4,11 +4,10 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" ) -type Bootstrapper struct { -} +type Bootstrapper struct{} func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - Config.InitializeViper() - context[bootstrap.BootstrappedConfig] = Config + Config().InitializeViper() + context[bootstrap.BootstrappedConfig] = Config() return nil } diff --git a/config/configuration.go b/config/configuration.go index 2ebe27341..a0e5c0c27 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -13,6 +13,7 @@ import ( "math/big" "os" "strings" + "sync" "time" "github.com/centrifuge/go-centrifuge/centerrors" @@ -20,48 +21,117 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" + "github.com/spf13/cast" "github.com/spf13/viper" ) var log = logging.Logger("config") -var Config *Configuration +// configMu protects the config from read/write +var configMu sync.RWMutex + +// config holds the current node config +var config *Configuration + +// Config returns the current loaded config +func Config() *Configuration { + configMu.RLock() + defer configMu.RUnlock() + return config +} + +// SetConfig sets the config +func SetConfig(c *Configuration) { + configMu.Lock() + defer configMu.Unlock() + config = c +} + +// Configuration holds the configuration details for the node type Configuration struct { + mu sync.RWMutex configFile string - V *viper.Viper + v *viper.Viper } +// AccountConfig holds the account details type AccountConfig struct { Address string Key string Password string } +// IsSet check if the key is set in the config +func (c *Configuration) IsSet(key string) bool { + c.mu.RLock() + defer c.mu.RUnlock() + return c.v.IsSet(key) +} + +// Set update the key and the value it holds in the configuration +func (c *Configuration) Set(key string, value interface{}) { + c.mu.Lock() + defer c.mu.Unlock() + c.v.Set(key, value) +} + +func (c *Configuration) SetDefault(key string, value interface{}) { + c.mu.Lock() + defer c.mu.Unlock() + c.v.SetDefault(key, value) +} + +// Get returns associated value for the key +func (c *Configuration) Get(key string) interface{} { + return c.get(key) +} + +// GetString returns value string associated with key +func (c *Configuration) GetString(key string) string { + return cast.ToString(c.get(key)) +} + +// GetInt returns value int associated with key +func (c *Configuration) GetInt(key string) int { + return cast.ToInt(c.get(key)) +} + +// GetDuration returns value duration associated with key +func (c *Configuration) GetDuration(key string) time.Duration { + return cast.ToDuration(c.get(key)) +} + +func (c *Configuration) get(key string) interface{} { + c.mu.RLock() + defer c.mu.RUnlock() + return c.v.Get(key) +} + // GetStoragePath returns the data storage backend func (c *Configuration) GetStoragePath() string { - return c.V.GetString("storage.Path") + return c.GetString("storage.Path") } // GetP2PPort returns P2P Port func (c *Configuration) GetP2PPort() int { - return c.V.GetInt("p2p.port") + return c.GetInt("p2p.port") } // GetP2PExternalIP returns P2P External IP func (c *Configuration) GetP2PExternalIP() string { - return c.V.GetString("p2p.externalIP") + return c.GetString("p2p.externalIP") } // GetP2PConnectionTimeout returns P2P Connect Timeout func (c *Configuration) GetP2PConnectionTimeout() time.Duration { - return c.V.GetDuration("p2p.connectTimeout") + return c.GetDuration("p2p.connectTimeout") } //////////////////////////////////////////////////////////////////////////////// // Notifications //////////////////////////////////////////////////////////////////////////////// func (c *Configuration) GetReceiveEventNotificationEndpoint() string { - return c.V.GetString("notifications.endpoint") + return c.GetString("notifications.endpoint") } //////////////////////////////////////////////////////////////////////////////// @@ -69,11 +139,11 @@ func (c *Configuration) GetReceiveEventNotificationEndpoint() string { //////////////////////////////////////////////////////////////////////////////// func (c *Configuration) GetServerPort() int { - return c.V.GetInt("nodePort") + return c.GetInt("nodePort") } func (c *Configuration) GetServerAddress() string { - return fmt.Sprintf("%s:%s", c.V.GetString("nodeHostname"), c.V.GetString("nodePort")) + return fmt.Sprintf("%s:%s", c.GetString("nodeHostname"), c.GetString("nodePort")) } //////////////////////////////////////////////////////////////////////////////// @@ -81,60 +151,60 @@ func (c *Configuration) GetServerAddress() string { //////////////////////////////////////////////////////////////////////////////// func (c *Configuration) GetNumWorkers() int { - return c.V.GetInt("queue.numWorkers") + return c.GetInt("queue.numWorkers") } func (c *Configuration) GetWorkerWaitTimeMS() int { - return c.V.GetInt("queue.workerWaitTimeMS") + return c.GetInt("queue.workerWaitTimeMS") } //////////////////////////////////////////////////////////////////////////////// // Ethereum //////////////////////////////////////////////////////////////////////////////// func (c *Configuration) GetEthereumNodeURL() string { - return c.V.GetString("ethereum.nodeURL") + return c.GetString("ethereum.nodeURL") } func (c *Configuration) GetEthereumContextReadWaitTimeout() time.Duration { - return c.V.GetDuration("ethereum.contextReadWaitTimeout") + return c.GetDuration("ethereum.contextReadWaitTimeout") } func (c *Configuration) GetEthereumContextWaitTimeout() time.Duration { - return c.V.GetDuration("ethereum.contextWaitTimeout") + return c.GetDuration("ethereum.contextWaitTimeout") } func (c *Configuration) GetEthereumIntervalRetry() time.Duration { - return c.V.GetDuration("ethereum.intervalRetry") + return c.GetDuration("ethereum.intervalRetry") } func (c *Configuration) GetEthereumMaxRetries() int { - return c.V.GetInt("ethereum.maxRetries") + return c.GetInt("ethereum.maxRetries") } func (c *Configuration) GetEthereumGasPrice() *big.Int { - return big.NewInt(c.V.GetInt64("ethereum.gasPrice")) + return big.NewInt(cast.ToInt64(c.get("ethereum.gasPrice"))) } func (c *Configuration) GetEthereumGasLimit() uint64 { - return uint64(c.V.GetInt64("ethereum.gasLimit")) + return cast.ToUint64(c.get("ethereum.gasLimit")) } func (c *Configuration) GetEthereumDefaultAccountName() string { - return c.V.GetString("ethereum.defaultAccountName") + return c.GetString("ethereum.defaultAccountName") } func (c *Configuration) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { k := fmt.Sprintf("ethereum.accounts.%s", accountName) - if !c.V.IsSet(k) { + if !c.IsSet(k) { return nil, fmt.Errorf("no account found with account name %s", accountName) } // Workaround for bug https://github.com/spf13/viper/issues/309 && https://github.com/spf13/viper/issues/513 account = &AccountConfig{ - Address: c.V.GetString(fmt.Sprintf("%s.address", k)), - Key: c.V.GetString(fmt.Sprintf("%s.key", k)), - Password: c.V.GetString(fmt.Sprintf("%s.password", k)), + Address: c.GetString(fmt.Sprintf("%s.address", k)), + Key: c.GetString(fmt.Sprintf("%s.key", k)), + Password: c.GetString(fmt.Sprintf("%s.password", k)), } return account, nil @@ -142,14 +212,14 @@ func (c *Configuration) GetEthereumAccount(accountName string) (account *Account // Important flag for concurrency handling. Disable if Ethereum client doesn't support txpool API (INFURA) func (c *Configuration) GetTxPoolAccessEnabled() bool { - return c.V.GetBool("ethereum.txPoolAccessEnabled") + return cast.ToBool(c.get("ethereum.txPoolAccessEnabled")) } //////////////////////////////////////////////////////////////////////////////// // Network Configuration //////////////////////////////////////////////////////////////////////////////// func (c *Configuration) GetNetworkString() string { - return c.V.GetString("centrifugeNetwork") + return c.GetString("centrifugeNetwork") } func (c *Configuration) GetNetworkKey(k string) string { @@ -158,7 +228,7 @@ func (c *Configuration) GetNetworkKey(k string) string { // GetContractAddressString returns the deployed contract address for a given contract. func (c *Configuration) GetContractAddressString(contract string) (address string) { - return c.V.GetString(c.GetNetworkKey(fmt.Sprintf("contractAddresses.%s", contract))) + return c.GetString(c.GetNetworkKey(fmt.Sprintf("contractAddresses.%s", contract))) } // GetContractAddress returns the deployed contract address for a given contract. @@ -168,17 +238,17 @@ func (c *Configuration) GetContractAddress(contract string) (address common.Addr // GetBootstrapPeers returns the list of configured bootstrap nodes for the given network. func (c *Configuration) GetBootstrapPeers() []string { - return c.V.GetStringSlice(c.GetNetworkKey("bootstrapPeers")) + return cast.ToStringSlice(c.get(c.GetNetworkKey("bootstrapPeers"))) } // GetNetworkID returns the numerical network id. func (c *Configuration) GetNetworkID() uint32 { - return uint32(c.V.GetInt(c.GetNetworkKey("id"))) + return uint32(c.GetInt(c.GetNetworkKey("id"))) } // GetIdentityID returns the self centID func (c *Configuration) GetIdentityID() ([]byte, error) { - id, err := hexutil.Decode(c.V.GetString("identityId")) + id, err := hexutil.Decode(c.GetString("identityId")) if err != nil { return nil, centerrors.Wrap(err, "can't read identityId from config") } @@ -186,45 +256,37 @@ func (c *Configuration) GetIdentityID() ([]byte, error) { } func (c *Configuration) GetSigningKeyPair() (pub, priv string) { - return c.V.GetString("keys.signing.publicKey"), c.V.GetString("keys.signing.privateKey") + return c.GetString("keys.signing.publicKey"), c.GetString("keys.signing.privateKey") } func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { - return c.V.GetString("keys.ethauth.publicKey"), c.V.GetString("keys.ethauth.privateKey") + return c.GetString("keys.ethauth.publicKey"), c.GetString("keys.ethauth.privateKey") } // Configuration Implementation func NewConfiguration(configFile string) *Configuration { - c := Configuration{configFile: configFile} - return &c -} - -// SetConfigFile returns an error if viper was already initialized. -func (c *Configuration) SetConfigFile(path string) error { - if c.V != nil { - return errors.New("viper already initialized. Can't set config file") - } - c.configFile = path - return nil + return &Configuration{configFile: configFile, mu: sync.RWMutex{}} } -func (c *Configuration) ReadConfigFile(path string) error { +func (c *Configuration) readConfigFile(path string) error { + c.mu.Lock() + defer c.mu.Unlock() file, err := os.Open(path) if err != nil { return err } - err = c.V.MergeConfig(file) + err = c.v.MergeConfig(file) return err } func (c *Configuration) InitializeViper() { // This method should not have any effects if Viper is already initialized. - if c.V != nil { + if c.v != nil { return } - c.V = viper.New() - c.V.SetConfigType("yaml") + c.v = viper.New() + c.v.SetConfigType("yaml") // Load defaults data, err := resources.Asset("go-centrifuge/build/configs/default_config.yaml") @@ -232,28 +294,29 @@ func (c *Configuration) InitializeViper() { log.Panicf("failed to load (go-centrifuge/build/configs/default_config.yaml): %s", err) } - err = c.V.ReadConfig(bytes.NewReader(data)) + err = c.v.ReadConfig(bytes.NewReader(data)) if err != nil { log.Panicf("Error reading from default configuration (go-centrifuge/build/configs/default_config.yaml): %s", err) } // Load user specified config if c.configFile != "" { log.Infof("Loading user specified config from %s", c.configFile) - err = c.ReadConfigFile(c.configFile) + err = c.readConfigFile(c.configFile) if err != nil { log.Panicf("Error reading config %s, %s", c.configFile, err) } } else { log.Info("No user config specified") } - c.V.AutomaticEnv() - c.V.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - c.V.SetEnvPrefix("CENT") + c.v.AutomaticEnv() + c.v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + c.v.SetEnvPrefix("CENT") } func Bootstrap(configFile string) { - Config = NewConfiguration(configFile) - Config.InitializeViper() + c := NewConfiguration(configFile) + c.InitializeViper() + SetConfig(c) } // CreateConfigFile creates minimum config file with arguments diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 211c9a9a0..12ca4e692 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -23,13 +23,14 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { log.Fatal("Current working dir is not in `go-centrifuge`") } } - Config = NewConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) - Config.InitializeViper() - context[bootstrap.BootstrappedConfig] = Config + c := NewConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) + c.InitializeViper() + SetConfig(c) + context[bootstrap.BootstrappedConfig] = c return nil } func (b *Bootstrapper) TestTearDown() error { - Config = nil + SetConfig(nil) return nil } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index da0bc18a8..0201839b7 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -232,11 +232,11 @@ func TestGetExternalCollaborators_ErrorConfig(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - currentKeyPath, _ := config.Config.GetSigningKeyPair() + currentKeyPath, _ := config.Config().GetSigningKeyPair() //Wrong path - config.Config.V.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") collaborators, err := GetExternalCollaborators(cd) assert.NotNil(t, err) assert.Nil(t, collaborators) - config.Config.V.Set("keys.signing.publicKey", currentKeyPath) + config.Config().Set("keys.signing.publicKey", currentKeyPath) } diff --git a/coredocument/processor.go b/coredocument/processor.go index f44b74775..3d1617f95 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -88,7 +88,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp header := &p2ppb.CentrifugeHeader{ SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), } resp, err := client.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: header}) @@ -199,7 +199,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to get document root: %v", err) } - id, err := config.Config.GetIdentityID() + id, err := config.Config().GetIdentityID() if err != nil { return fmt.Errorf("failed to get self cent ID: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index f79b003af..00d6cb9dd 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -58,8 +58,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} // failed to get id - pub, _ := config.Config.GetSigningKeyPair() - config.Config.V.Set("keys.signing.publicKey", "wrong path") + pub, _ := config.Config().GetSigningKeyPair() + config.Config().Set("keys.signing.publicKey", "wrong path") cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ @@ -73,7 +73,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get keys for signing") - config.Config.V.Set("keys.signing.publicKey", pub) + config.Config().Set("keys.signing.publicKey", pub) // failed unpack model = mockModel{} @@ -314,15 +314,15 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv - oldID := config.Config.V.GetString("identityId") - config.Config.V.Set("identityId", "wrong id") + oldID := config.Config().GetString("identityId") + config.Config().Set("identityId", "wrong id") err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get self cent ID") - config.Config.V.Set("identityId", "0x0102030405060708") + config.Config().Set("identityId", "0x0102030405060708") // wrong ID model = mockModel{} @@ -336,11 +336,11 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "centID invalid") - config.Config.V.Set("identityId", oldID) + config.Config().Set("identityId", oldID) // missing eth keys - oldPth := config.Config.V.Get("keys.ethauth.publicKey") - config.Config.V.Set("keys.ethauth.publicKey", "wrong path") + oldPth := config.Config().Get("keys.ethauth.publicKey") + config.Config().Set("keys.ethauth.publicKey", "wrong path") model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() @@ -352,7 +352,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get eth keys") - config.Config.V.Set("keys.ethauth.publicKey", oldPth) + config.Config().Set("keys.ethauth.publicKey", oldPth) // failed anchor commit model = mockModel{} diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 6cb41640e..c8404d0c8 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -30,10 +30,10 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, nil) flag.Parse() - config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 0b925b1ab..c5feeaa42 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -14,7 +14,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - client, err := NewGethClient(config.Config) + client, err := NewGethClient(config.Config()) if err != nil { return err } diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index b5cf2f51b..fe88007b1 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -32,12 +32,12 @@ var gcMu sync.RWMutex // GetDefaultContextTimeout retrieves the default duration before an Ethereum write call context should time out func GetDefaultContextTimeout() time.Duration { - return config.Config.GetEthereumContextWaitTimeout() + return config.Config().GetEthereumContextWaitTimeout() } // defaultReadContext returns context with timeout for read operations func defaultReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { - toBeDone := time.Now().Add(config.Config.GetEthereumContextReadWaitTimeout()) + toBeDone := time.Now().Add(config.Config().GetEthereumContextReadWaitTimeout()) return context.WithDeadline(context.Background(), toBeDone) } diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 5055a4b36..a797caba6 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -34,7 +34,7 @@ func TestGetConnection_returnsSameConnection(t *testing.T) { } func TestNewGethClient(t *testing.T) { - gc, err := ethereum.NewGethClient(config.Config) + gc, err := ethereum.NewGethClient(config.Config()) assert.Nil(t, err) assert.NotNil(t, gc) } diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index cbfba9ba8..bca730103 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -28,8 +28,8 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, nil) - config.Config.V.Set("ethereum.txPoolAccessEnabled", false) - config.Config.V.Set("ethereum.intervalRetry", time.Millisecond*100) + config.Config().Set("ethereum.txPoolAccessEnabled", false) + config.Config().Set("ethereum.intervalRetry", time.Millisecond*100) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -61,7 +61,7 @@ func TestInitTransactionWithRetries(t *testing.T) { accounts: make(map[string]*bind.TransactOpts), accMu: sync.Mutex{}, txMu: sync.Mutex{}, - config: config.Config, + config: config.Config(), } SetClient(gc) diff --git a/healthcheck/handler.go b/healthcheck/handler.go index 5dcaefa14..268bc53e5 100644 --- a/healthcheck/handler.go +++ b/healthcheck/handler.go @@ -21,6 +21,6 @@ func GRPCHandler() healthpb.HealthCheckServiceServer { func (handler) Ping(context.Context, *empty.Empty) (pong *healthpb.Pong, err error) { return &healthpb.Pong{ Version: version.GetVersion().String(), - Network: config.Config.GetNetworkString(), + Network: config.Config().GetNetworkString(), }, nil } diff --git a/healthcheck/handler_test.go b/healthcheck/handler_test.go index 03ff12eb7..10c87969c 100644 --- a/healthcheck/handler_test.go +++ b/healthcheck/handler_test.go @@ -33,5 +33,5 @@ func TestHandler_Ping(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, pong) assert.Equal(t, pong.Version, version.GetVersion().String()) - assert.Equal(t, pong.Network, config.Config.GetNetworkString()) + assert.Equal(t, pong.Network, config.Config().GetNetworkString()) } diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 22186455c..5df617ebe 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -32,7 +32,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - IDService = NewEthereumIdentityService(config.Config, idFactory, registryContract) + IDService = NewEthereumIdentityService(config.Config(), idFactory, registryContract) identityContract, err := getIdentityFactoryContract() if err != nil { @@ -46,7 +46,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } err = queue.InstallQueuedTask(context, - newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, config.Config)) + newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, config.Config())) if err != nil { return err } @@ -55,10 +55,10 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { func getIdentityFactoryContract() (identityFactoryContract *EthereumIdentityFactoryContract, err error) { client := ethereum.GetClient() - return NewEthereumIdentityFactoryContract(config.Config.GetContractAddress("identityFactory"), client.GetEthClient()) + return NewEthereumIdentityFactoryContract(config.Config().GetContractAddress("identityFactory"), client.GetEthClient()) } func getIdentityRegistryContract() (identityRegistryContract *EthereumIdentityRegistryContract, err error) { client := ethereum.GetClient() - return NewEthereumIdentityRegistryContract(config.Config.GetContractAddress("identityRegistry"), client.GetEthClient()) + return NewEthereumIdentityRegistryContract(config.Config().GetContractAddress("identityRegistry"), client.GetEthClient()) } diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 9d49d9795..34cff58f2 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -23,8 +23,8 @@ func TestMain(m *testing.M) { time.Sleep(time.Second + 2) cc.TestFunctionalEthereumBootstrap() - config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") identityService = identity.IDService result := m.Run() @@ -79,10 +79,10 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { func TestAddKeyFromConfig(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := config.Config.V.GetString("identityId") - config.Config.V.Set("identityId", centrifugeId.String()) - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + defaultCentrifugeId := config.Config().GetString("identityId") + config.Config().Set("identityId", centrifugeId.String()) + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") _, confirmations, err := identityService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") @@ -93,20 +93,20 @@ func TestAddKeyFromConfig(t *testing.T) { err = identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") - config.Config.V.Set("identityId", defaultCentrifugeId) + config.Config().Set("identityId", defaultCentrifugeId) } func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := config.Config.V.GetString("identityId") - config.Config.V.Set("identityId", centrifugeId.String()) - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + defaultCentrifugeId := config.Config().GetString("identityId") + config.Config().Set("identityId", centrifugeId.String()) + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") err := identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.NotNil(t, err, "should error out") - config.Config.V.Set("identityId", defaultCentrifugeId) + config.Config().Set("identityId", defaultCentrifugeId) } func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { diff --git a/identity/identity.go b/identity/identity.go index 372460aa3..08322090d 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -51,7 +51,7 @@ type IdentityKey struct { // GetIdentityConfig returns the identity and keys associated with the node func GetIdentityConfig() (*IdentityConfig, error) { - centIDBytes, err := config.Config.GetIdentityID() + centIDBytes, err := config.Config().GetIdentityID() if err != nil { return nil, err } diff --git a/identity/identity_test.go b/identity/identity_test.go index 87320b8c3..4359d8f12 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -22,10 +22,10 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, nil) - config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -112,7 +112,7 @@ func TestGetIdentityConfig_Success(t *testing.T) { idConfig, err := GetIdentityConfig() assert.Nil(t, err) assert.NotNil(t, idConfig) - configId, err := config.Config.GetIdentityID() + configId, err := config.Config().GetIdentityID() assert.Nil(t, err) idBytes := idConfig.ID[:] assert.Equal(t, idBytes, configId) @@ -121,40 +121,40 @@ func TestGetIdentityConfig_Success(t *testing.T) { func TestGetIdentityConfig_Error(t *testing.T) { //Wrong Hex - currentId := config.Config.V.GetString("identityId") - config.Config.V.Set("identityId", "ABCD") + currentId := config.Config().GetString("identityId") + config.Config().Set("identityId", "ABCD") idConfig, err := GetIdentityConfig() assert.NotNil(t, err) assert.Contains(t, err.Error(), "hex string without 0x prefix") assert.Nil(t, idConfig) - config.Config.V.Set("identityId", currentId) + config.Config().Set("identityId", currentId) //Wrong length - currentId = config.Config.V.GetString("identityId") - config.Config.V.Set("identityId", "0x0101010101") + currentId = config.Config().GetString("identityId") + config.Config().Set("identityId", "0x0101010101") idConfig, err = GetIdentityConfig() assert.NotNil(t, err) assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") assert.Nil(t, idConfig) - config.Config.V.Set("identityId", currentId) + config.Config().Set("identityId", currentId) //Wrong public signing key path - currentKeyPath, _ := config.Config.GetSigningKeyPair() - config.Config.V.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + currentKeyPath, _ := config.Config().GetSigningKeyPair() + config.Config().Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") idConfig, err = GetIdentityConfig() assert.NotNil(t, err) assert.Contains(t, err.Error(), "no such file or directory") assert.Nil(t, idConfig) - config.Config.V.Set("keys.signing.publicKey", currentKeyPath) + config.Config().Set("keys.signing.publicKey", currentKeyPath) //Wrong public ethauth key path - currentKeyPath, _ = config.Config.GetEthAuthKeyPair() - config.Config.V.Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") + currentKeyPath, _ = config.Config().GetEthAuthKeyPair() + config.Config().Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") idConfig, err = GetIdentityConfig() assert.NotNil(t, err) assert.Contains(t, err.Error(), "no such file or directory") assert.Nil(t, idConfig) - config.Config.V.Set("keys.ethauth.publicKey", currentKeyPath) + config.Config().Set("keys.ethauth.publicKey", currentKeyPath) } func TestToCentId(t *testing.T) { diff --git a/keytools/ed25519/ed25519.go b/keytools/ed25519/ed25519.go index 9a00b4eff..863f2e5aa 100644 --- a/keytools/ed25519/ed25519.go +++ b/keytools/ed25519/ed25519.go @@ -35,7 +35,7 @@ func GetPrivateSigningKey(fileName string) (privateKey ed25519.PrivateKey, err e // GetSigningKeyPairFromConfig returns the public and private key pair from the config func GetSigningKeyPairFromConfig() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) { - pub, priv := config.Config.GetSigningKeyPair() + pub, priv := config.Config().GetSigningKeyPair() publicKey, err = GetPublicSigningKey(pub) if err != nil { return nil, nil, fmt.Errorf("failed to read public key: %v", err) diff --git a/keytools/ed25519/ed25519_test.go b/keytools/ed25519/ed25519_test.go index 50cc6af67..92b7b50e2 100644 --- a/keytools/ed25519/ed25519_test.go +++ b/keytools/ed25519/ed25519_test.go @@ -34,26 +34,26 @@ func TestPublicKeyToP2PKey(t *testing.T) { } func TestGetSigningKeyPairFromConfig(t *testing.T) { - pub := config.Config.V.Get("keys.signing.publicKey") - pri := config.Config.V.Get("keys.signing.privateKey") + pub := config.Config().Get("keys.signing.publicKey") + pri := config.Config().Get("keys.signing.privateKey") // bad public key path - config.Config.V.Set("keys.signing.publicKey", "bad path") + config.Config().Set("keys.signing.publicKey", "bad path") pubK, priK, err := GetSigningKeyPairFromConfig() assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read public key") - config.Config.V.Set("keys.signing.publicKey", pub) + config.Config().Set("keys.signing.publicKey", pub) // bad private key path - config.Config.V.Set("keys.signing.privateKey", "bad path") + config.Config().Set("keys.signing.privateKey", "bad path") pubK, priK, err = GetSigningKeyPairFromConfig() assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read private key") - config.Config.V.Set("keys.signing.privateKey", pri) + config.Config().Set("keys.signing.privateKey", pri) // success pubK, priK, err = GetSigningKeyPairFromConfig() diff --git a/keytools/secp256k1/secp256k1.go b/keytools/secp256k1/secp256k1.go index 2d07d504a..67f8ef838 100644 --- a/keytools/secp256k1/secp256k1.go +++ b/keytools/secp256k1/secp256k1.go @@ -117,7 +117,7 @@ func VerifySignature(publicKey, message, signature []byte) bool { // GetEthAuthKeyFromConfig returns the public and private keys as byte array func GetEthAuthKeyFromConfig() (public, private []byte, err error) { - pub, priv := config.Config.GetEthAuthKeyPair() + pub, priv := config.Config().GetEthAuthKeyPair() privateKey, err := GetPrivateEthAuthKey(priv) if err != nil { return nil, nil, fmt.Errorf("failed to read private key: %v", err) diff --git a/keytools/secp256k1/secp256k1_test.go b/keytools/secp256k1/secp256k1_test.go index 71a90febb..bae94c4fd 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/keytools/secp256k1/secp256k1_test.go @@ -203,26 +203,26 @@ func TestGetAddress(t *testing.T) { } func TestGetEthAuthKeyFromConfig(t *testing.T) { - pub := config.Config.V.Get("keys.ethauth.publicKey") - pri := config.Config.V.Get("keys.ethauth.privateKey") + pub := config.Config().Get("keys.ethauth.publicKey") + pri := config.Config().Get("keys.ethauth.privateKey") // bad public key path - config.Config.V.Set("keys.ethauth.publicKey", "bad path") + config.Config().Set("keys.ethauth.publicKey", "bad path") pubK, priK, err := GetEthAuthKeyFromConfig() assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read public key") - config.Config.V.Set("keys.ethauth.publicKey", pub) + config.Config().Set("keys.ethauth.publicKey", pub) // bad private key path - config.Config.V.Set("keys.ethauth.privateKey", "bad path") + config.Config().Set("keys.ethauth.privateKey", "bad path") pubK, priK, err = GetEthAuthKeyFromConfig() assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read private key") - config.Config.V.Set("keys.ethauth.privateKey", pri) + config.Config().Set("keys.ethauth.privateKey", pri) // success pubK, priK, err = GetEthAuthKeyFromConfig() diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 244b18726..75b25a3f9 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -25,11 +25,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } - setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config)) + setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config())) return nil } func getPaymentObligationContract() (*EthereumPaymentObligationContract, error) { client := ethereum.GetClient() - return NewEthereumPaymentObligationContract(config.Config.GetContractAddress("paymentObligation"), client.GetEthClient()) + return NewEthereumPaymentObligationContract(config.Config().GetContractAddress("paymentObligation"), client.GetEthClient()) } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 219436b07..1049354ca 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -22,19 +22,19 @@ import ( func TestMain(m *testing.M) { cc.TestFunctionalEthereumBootstrap() - prevSignPubkey := config.Config.V.Get("keys.signing.publicKey") - prevSignPrivkey := config.Config.V.Get("keys.signing.privateKey") - prevEthPubkey := config.Config.V.Get("keys.ethauth.publicKey") - prevEthPrivkey := config.Config.V.Get("keys.ethauth.privateKey") - config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + prevSignPubkey := config.Config().Get("keys.signing.publicKey") + prevSignPrivkey := config.Config().Get("keys.signing.privateKey") + prevEthPubkey := config.Config().Get("keys.ethauth.publicKey") + prevEthPrivkey := config.Config().Get("keys.ethauth.privateKey") + config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() - config.Config.V.Set("keys.signing.publicKey", prevSignPubkey) - config.Config.V.Set("keys.signing.privateKey", prevSignPrivkey) - config.Config.V.Set("keys.ethauth.publicKey", prevEthPubkey) - config.Config.V.Set("keys.ethauth.privateKey", prevEthPrivkey) + config.Config().Set("keys.signing.publicKey", prevSignPubkey) + config.Config().Set("keys.signing.privateKey", prevSignPrivkey) + config.Config().Set("keys.ethauth.publicKey", prevEthPubkey) + config.Config().Set("keys.ethauth.privateKey", prevEthPrivkey) cc.TestFunctionalEthereumTearDown() os.Exit(result) } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 432b70aad..913b022ef 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -55,13 +55,13 @@ func defaultServerList() ([]Server, error) { return []Server{ api.NewCentAPIServer( - config.Config.GetServerAddress(), - config.Config.GetServerPort(), - config.Config.GetNetworkString(), + config.Config().GetServerAddress(), + config.Config().GetServerPort(), + config.Config().GetNetworkString(), ), p2p.NewCentP2PServer( - config.Config.GetP2PPort(), - config.Config.GetBootstrapPeers(), + config.Config().GetP2PPort(), + config.Config().GetBootstrapPeers(), publicKey, privateKey, ), }, nil diff --git a/notification/notification.go b/notification/notification.go index eaf8eb61c..05d182d65 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -27,7 +27,7 @@ type Sender interface { type WebhookSender struct{} func (wh *WebhookSender) Send(notification *notificationpb.NotificationMessage) (Status, error) { - url := config.Config.GetReceiveEventNotificationEndpoint() + url := config.Config().GetReceiveEventNotificationEndpoint() if url == "" { log.Warningf("Webhook URL not defined, manually fetch received document") return Success, nil diff --git a/p2p/client.go b/p2p/client.go index 78dd65231..f468f4877 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -62,7 +62,7 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error // make a new stream from host B to host A with timeout // Retrial is handled internally, connection request will be cancelled by the connection timeout context - ctx, _ := context.WithTimeout(context.Background(), config.Config.GetP2PConnectionTimeout()) + ctx, _ := context.WithTimeout(context.Background(), config.Config().GetP2PConnectionTimeout()) g, err := grpcProtoInstance.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) @@ -73,13 +73,13 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error // getSignatureForDocument requests the target node to sign the document func getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { - senderId, err := config.Config.GetIdentityID() + senderId, err := config.Config().GetIdentityID() if err != nil { return nil, err } header := p2ppb.CentrifugeHeader{ - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), CentNodeVersion: version.GetVersion().String(), SenderCentrifugeId: senderId, } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 89da3ca79..94dd4836a 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -36,10 +36,10 @@ var handler = p2p.Handler{Notifier: ¬ification.WebhookSender{}} func TestMain(m *testing.M) { cc.TestFunctionalEthereumBootstrap() flag.Parse() - config.Config.V.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config.V.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config.V.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config.V.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -248,7 +248,7 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { func createIdentity(t *testing.T) identity.CentID { // Create Identity centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - config.Config.V.Set("identityId", centrifugeId.String()) + config.Config().Set("identityId", centrifugeId.String()) id, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations @@ -307,13 +307,13 @@ func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentR return &p2ppb.AnchorDocumentRequest{ Header: &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), }, Document: doc, } } func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureRequest { return &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config.GetNetworkID(), + CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID(), }, Document: doc} } diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 028fb040b..fd5928417 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -39,7 +39,7 @@ var coreDoc = testingcoredocument.GenerateCoreDocument() func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config.GetNetworkID(), + CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID(), }} resp, err := handler.RequestDocumentSignature(context.Background(), req) @@ -49,7 +49,7 @@ func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { func TestHandler_RequestDocumentSignature_version_fail(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: config.Config.GetNetworkID(), + CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: config.Config().GetNetworkID(), }} resp, err := handler.RequestDocumentSignature(context.Background(), req) @@ -62,7 +62,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { // Test invalid version header := &p2ppb.CentrifugeHeader{ CentNodeVersion: "1000.0.0-invalid", - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Document: coreDoc, Header: header} res, err := handler.SendAnchoredDocument(context.Background(), &req) @@ -72,7 +72,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { assert.Nil(t, res) // Test invalid network - header.NetworkIdentifier = config.Config.GetNetworkID() + 1 + header.NetworkIdentifier = config.Config().GetNetworkID() + 1 header.CentNodeVersion = version.GetVersion().String() res, err = handler.SendAnchoredDocument(context.Background(), &req) assert.Error(t, err) @@ -84,7 +84,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { func TestSendAnchoredDocument_NilDocument(t *testing.T) { header := &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Header: header} res, err := handler.SendAnchoredDocument(context.Background(), &req) @@ -97,7 +97,7 @@ func TestHandler_SendAnchoredDocument_getServiceAndModel_fail(t *testing.T) { req := &p2ppb.AnchorDocumentRequest{ Header: &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config.GetNetworkID(), + NetworkIdentifier: config.Config().GetNetworkID(), }, Document: coredocument.New(), } @@ -115,16 +115,16 @@ func TestP2PService_basicChecks(t *testing.T) { }{ { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "someversion", NetworkIdentifier: 12}, - err: documents.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(config.Config.GetNetworkID(), 12)), + err: documents.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(config.Config().GetNetworkID(), 12)), }, { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "0.0.1", NetworkIdentifier: 12}, - err: documents.AppendError(incompatibleNetworkError(config.Config.GetNetworkID(), 12), nil), + err: documents.AppendError(incompatibleNetworkError(config.Config().GetNetworkID(), 12), nil), }, { - header: &p2ppb.CentrifugeHeader{CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config.GetNetworkID()}, + header: &p2ppb.CentrifugeHeader{CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID()}, }, } diff --git a/p2p/server.go b/p2p/server.go index 5190e56a9..1fc989007 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -189,7 +189,7 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { return nil, err } - externalIP := config.Config.GetP2PExternalIP() + externalIP := config.Config().GetP2PExternalIP() var extMultiAddr ma.Multiaddr if externalIP == "" { log.Warning("External IP not defined, Peers might not be able to resolve this node if behind NAT\n") diff --git a/p2p/server_test.go b/p2p/server_test.go index 0d32d67e4..3a42dcee7 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -64,7 +64,7 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 - config.Config.V.Set("p2p.externalIP", externalIP) + config.Config().Set("p2p.externalIP", externalIP) priv, pub, err := getKeys() assert.Nil(t, err) cp2p := NewCentP2PServer(listenPort, []string{}, pub, priv) @@ -80,7 +80,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 - config.Config.V.Set("p2p.externalIP", externalIP) + config.Config().Set("p2p.externalIP", externalIP) priv, pub, err := getKeys() assert.Nil(t, err) cp2p := NewCentP2PServer(listenPort, []string{}, pub, priv) diff --git a/p2p/validator.go b/p2p/validator.go index 14f2b79d2..ef353f351 100644 --- a/p2p/validator.go +++ b/p2p/validator.go @@ -56,8 +56,8 @@ func networkValidator() Validator { if header == nil { return fmt.Errorf("nil header") } - if config.Config.GetNetworkID() != header.NetworkIdentifier { - return incompatibleNetworkError(config.Config.GetNetworkID(), header.NetworkIdentifier) + if config.Config().GetNetworkID() != header.NetworkIdentifier { + return incompatibleNetworkError(config.Config().GetNetworkID(), header.NetworkIdentifier) } return nil }) diff --git a/p2p/validator_test.go b/p2p/validator_test.go index ada43f4fd..b2e052e6c 100644 --- a/p2p/validator_test.go +++ b/p2p/validator_test.go @@ -56,7 +56,7 @@ func TestValidate_networkValidator(t *testing.T) { assert.NotNil(t, err) // Compatible network - header.NetworkIdentifier = config.Config.GetNetworkID() + header.NetworkIdentifier = config.Config().GetNetworkID() err = nv.Validate(header) assert.Nil(t, err) } @@ -73,7 +73,7 @@ func TestValidate_handshakeValidator(t *testing.T) { assert.NotNil(t, err) // Incompatible version, correct network - header.NetworkIdentifier = config.Config.GetNetworkID() + header.NetworkIdentifier = config.Config().GetNetworkID() err = hv.Validate(header) assert.NotNil(t, err) @@ -84,7 +84,7 @@ func TestValidate_handshakeValidator(t *testing.T) { assert.NotNil(t, err) // Compatible version and network - header.NetworkIdentifier = config.Config.GetNetworkID() + header.NetworkIdentifier = config.Config().GetNetworkID() err = hv.Validate(header) assert.Nil(t, err) } diff --git a/queue/queue.go b/queue/queue.go index 4f3b73d2e..c282f2c8d 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -22,8 +22,8 @@ func InitQueue(tasks []QueuedTask) { Queue, err = gocelery.NewCeleryClient( gocelery.NewInMemoryBroker(), gocelery.NewInMemoryBackend(), - config.Config.GetNumWorkers(), - config.Config.GetWorkerWaitTimeMS(), + config.Config().GetNumWorkers(), + config.Config().GetWorkerWaitTimeMS(), ) if err != nil { panic("Could not initialize the queue") diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index 36d91ad2c..f159bfa43 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -16,7 +16,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.New("config not initialised") } - levelDB, err := NewLevelDBStorage(config.Config.GetStoragePath()) + levelDB, err := NewLevelDBStorage(config.Config().GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index 22ad678dd..bc5812f91 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -14,14 +14,14 @@ const testStoragePath = "/tmp/centrifuge_data.leveldb_TESTING" func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { rs := getRandomTestStoragePath() - config.Config.V.SetDefault("storage.Path", rs) - log.Info("Set storage.Path to:", config.Config.GetStoragePath()) - levelDB, err := NewLevelDBStorage(config.Config.GetStoragePath()) + config.Config().SetDefault("storage.Path", rs) + log.Info("Set storage.Path to:", config.Config().GetStoragePath()) + levelDB, err := NewLevelDBStorage(config.Config().GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } - log.Infof("Setting levelDb at: %s", config.Config.GetStoragePath()) + log.Infof("Setting levelDb at: %s", config.Config().GetStoragePath()) context[bootstrap.BootstrappedLevelDb] = levelDB return nil } diff --git a/testingutils/utils.go b/testingutils/utils.go index 9fefd8254..a67554fb2 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -7,10 +7,10 @@ import ( ) func MockConfigOption(key string, value interface{}) func() { - mockedValue := config.Config.V.Get(key) - config.Config.V.Set(key, value) + mockedValue := config.Config().Get(key) + config.Config().Set(key, value) return func() { - config.Config.V.Set(key, mockedValue) + config.Config().Set(key, mockedValue) } } From 20a622800cbc6a93c9316a7df7185b4d8ffb1e1a Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 6 Nov 2018 21:35:56 +0530 Subject: [PATCH 014/220] Hex convert webhook fields (#409) * Hex convert webhook fields * Hex convert webhook fields * Test --- Gopkg.lock | 5 +++-- Gopkg.toml | 2 +- build/package.json | 2 +- build/swagger_config.js | 2 +- documents/invoice/service.go | 10 +++++----- documents/purchaseorder/service.go | 10 +++++----- notification/notification_test.go | 7 ++++--- protobufs/gen/swagger.json | 2 +- .../gen/swagger/notification/service.swagger.json | 8 +++----- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 10024bd9d..54b0a812c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -46,7 +46,7 @@ revision = "c60964592c1a2b83c5676878c937cdbe6719869d" [[projects]] - digest = "1:c6e2ed36c71d00b36eb36fa5b7aad8c06a1c07f58701557c4bb7b8e0084356d8" + digest = "1:172fd1858be37ef797612b58214f4d0a15f75a39d43b0fa2774ffca69f82f5c2" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -58,7 +58,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "838c11114163b6152d7b56574536f046b858e68d" + revision = "be7d05cddb4149670d475538e208f358a99518e6" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" @@ -1407,6 +1407,7 @@ "github.com/multiformats/go-multihash", "github.com/paralin/go-libp2p-grpc", "github.com/roboll/go-vendorinstall", + "github.com/spf13/cast", "github.com/spf13/cobra", "github.com/spf13/viper", "github.com/stretchr/testify/assert", diff --git a/Gopkg.toml b/Gopkg.toml index fd0cf3084..c82b11718 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "838c11114163b6152d7b56574536f046b858e68d" + revision = "be7d05cddb4149670d475538e208f358a99518e6" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/build/package.json b/build/package.json index 8f6caa7fa..cd221df70 100644 --- a/build/package.json +++ b/build/package.json @@ -1,6 +1,6 @@ { "name": "go-centrifuge", - "version": "0.0.1", + "version": "0.0.2", "description": "Protobuf files & go bindings for go-centrifuge", "main": "index.js", "scripts": { diff --git a/build/swagger_config.js b/build/swagger_config.js index bce806f5f..3d4747053 100644 --- a/build/swagger_config.js +++ b/build/swagger_config.js @@ -1,6 +1,6 @@ module.exports = { info: { - version: "0.0.1", + version: "0.0.2", title: "Centrifuge OS Node API", description: "\n", contact: { diff --git a/documents/invoice/service.go b/documents/invoice/service.go index b0fefa17b..e76b36898 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -378,11 +378,11 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C ts, _ := ptypes.TimestampProto(time.Now().UTC()) notificationMsg := ¬ificationpb.NotificationMessage{ - EventType: uint32(notification.ReceivedPayload), - CentrifugeId: headers.SenderCentrifugeId, - Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentIdentifier: doc.DocumentIdentifier, + EventType: uint32(notification.ReceivedPayload), + CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), + Recorded: ts, + DocumentType: doc.EmbeddedData.TypeUrl, + DocumentId: hexutil.Encode(doc.DocumentIdentifier), } // Async until we add queuing diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 4b699d75e..01c399b7b 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -378,11 +378,11 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C ts, _ := ptypes.TimestampProto(time.Now().UTC()) notificationMsg := ¬ificationpb.NotificationMessage{ - EventType: uint32(notification.ReceivedPayload), - CentrifugeId: headers.SenderCentrifugeId, - Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentIdentifier: doc.DocumentIdentifier, + EventType: uint32(notification.ReceivedPayload), + CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), + Recorded: ts, + DocumentType: doc.EmbeddedData.TypeUrl, + DocumentId: hexutil.Encode(doc.DocumentIdentifier), } // Async until we add queuing diff --git a/notification/notification_test.go b/notification/notification_test.go index 3340a1868..9d0eca064 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -18,6 +18,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/ptypes" "github.com/stretchr/testify/assert" + "github.com/ethereum/go-ethereum/common/hexutil" ) func TestMain(m *testing.M) { @@ -40,9 +41,9 @@ func TestWebhookConstructPayload(t *testing.T) { ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") notificationMessage := ¬ificationpb.NotificationMessage{ - DocumentIdentifier: coredoc.DocumentIdentifier, + DocumentId: hexutil.Encode(coredoc.DocumentIdentifier), DocumentType: documenttypes.InvoiceDataTypeUrl, - CentrifugeId: cid, + CentrifugeId: hexutil.Encode(cid), EventType: uint32(ReceivedPayload), Recorded: ts, } @@ -57,7 +58,7 @@ func TestWebhookConstructPayload(t *testing.T) { assert.Equal(t, notificationMessage.Recorded, unmarshaledNotificationMessage.Recorded, "Recorder Timestamp should be equal") assert.Equal(t, notificationMessage.DocumentType, unmarshaledNotificationMessage.DocumentType, "DocumentType should be equal") - assert.Equal(t, notificationMessage.DocumentIdentifier, unmarshaledNotificationMessage.DocumentIdentifier, "DocumentIdentifier should be equal") + assert.Equal(t, notificationMessage.DocumentId, unmarshaledNotificationMessage.DocumentId, "DocumentIdentifier should be equal") assert.Equal(t, notificationMessage.CentrifugeId, unmarshaledNotificationMessage.CentrifugeId, "CentrifugeID should be equal") assert.Equal(t, notificationMessage.EventType, unmarshaledNotificationMessage.EventType, "EventType should be equal") } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index c687f2417..2f95363f6 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.1","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"type":{"type":"string","title":"Document type"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string","format":"byte"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_identifier":{"type":"string","format":"byte"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"type":{"type":"string","title":"Document type"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/notification/service.swagger.json b/protobufs/gen/swagger/notification/service.swagger.json index 1a68285af..8d1e1f753 100644 --- a/protobufs/gen/swagger/notification/service.swagger.json +++ b/protobufs/gen/swagger/notification/service.swagger.json @@ -42,8 +42,7 @@ "format": "int64" }, "centrifuge_id": { - "type": "string", - "format": "byte" + "type": "string" }, "recorded": { "type": "string", @@ -52,9 +51,8 @@ "document_type": { "type": "string" }, - "document_identifier": { - "type": "string", - "format": "byte" + "document_id": { + "type": "string" } }, "title": "NotificationMessage wraps a single CoreDocument to be notified to upstream services" From 9a925a92a4862f3fbb68d15e5588fdca0ecfcb55 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 7 Nov 2018 14:12:11 +0100 Subject: [PATCH 015/220] Updated Precise proof with hex value (#414) --- Gopkg.lock | 16 ++++------------ Gopkg.toml | 4 ++-- build/package-lock.json | 2 +- documents/invoice/model_test.go | 3 +++ documents/purchaseorder/model_test.go | 3 +++ notification/notification_test.go | 12 ++++++------ 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 54b0a812c..ffd6a3ba5 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -46,7 +46,7 @@ revision = "c60964592c1a2b83c5676878c937cdbe6719869d" [[projects]] - digest = "1:172fd1858be37ef797612b58214f4d0a15f75a39d43b0fa2774ffca69f82f5c2" + digest = "1:66b6977457e5e7eff7aba31099caed6f2a21480f5616b4e32bf982715ab24b8b" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -58,7 +58,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "be7d05cddb4149670d475538e208f358a99518e6" + revision = "2660f56a4edb61312b7eb83a986fb5ae6ea73255" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" @@ -68,14 +68,14 @@ revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" [[projects]] - digest = "1:9ecc8c63be5b2a2e9c4daefc265ea476757d91a04394fbb984bcdb3c652129da" + digest = "1:3d9dcd118a682029404e301e7769803c3e6a48e7a964eb03364b938007080e24" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "c673e56ee0de0d721a10dee5cd2aa59015e4420a" + revision = "1abae88cef959657117754ae7602a5285d1008cc" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" @@ -354,14 +354,6 @@ pruneopts = "UT" revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca" -[[projects]] - branch = "master" - digest = "1:89cd2208bdeb192cc83ee287216af3c987fc87a90b9087718ad6631b636cefcf" - name = "github.com/iancoleman/strcase" - packages = ["."] - pruneopts = "UT" - revision = "3605ed457bf7f8caa1371b4fafadadc026673479" - [[projects]] digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" name = "github.com/inconshreveable/mousetrap" diff --git a/Gopkg.toml b/Gopkg.toml index c82b11718..cd62bc726 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "be7d05cddb4149670d475538e208f358a99518e6" + revision = "2660f56a4edb61312b7eb83a986fb5ae6ea73255" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" @@ -40,7 +40,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/precise-proofs" - revision = "c673e56ee0de0d721a10dee5cd2aa59015e4420a" + revision = "1abae88cef959657117754ae7602a5285d1008cc" [[constraint]] name = "github.com/centrifuge/gocelery" diff --git a/build/package-lock.json b/build/package-lock.json index 4eae7c3b5..58f0d65e4 100644 --- a/build/package-lock.json +++ b/build/package-lock.json @@ -1,6 +1,6 @@ { "name": "go-centrifuge", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index c98a0f78d..7dd54bcf1 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -237,6 +237,9 @@ func TestInvoiceModel_createProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) + // Validate '0x' Hex format in []byte value + assert.Equal(t, hexutil.Encode(i.CoreDocument.Collaborators[0]), proof[1].Value) + // Validate document_type valid, err = tree.ValidateProof(proof[2]) assert.Nil(t, err) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index ee4ccd3f4..c9caf4d32 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -210,6 +210,9 @@ func TestPOModel_createProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) + // Validate '0x' Hex format in []byte value + assert.Equal(t, hexutil.Encode(poModel.CoreDocument.Collaborators[0]), proof[1].Value) + // Validate document_type valid, err = tree.ValidateProof(proof[2]) assert.Nil(t, err) diff --git a/notification/notification_test.go b/notification/notification_test.go index 9d0eca064..abd393fa5 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -15,10 +15,10 @@ import ( "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/ptypes" "github.com/stretchr/testify/assert" - "github.com/ethereum/go-ethereum/common/hexutil" ) func TestMain(m *testing.M) { @@ -41,11 +41,11 @@ func TestWebhookConstructPayload(t *testing.T) { ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") notificationMessage := ¬ificationpb.NotificationMessage{ - DocumentId: hexutil.Encode(coredoc.DocumentIdentifier), - DocumentType: documenttypes.InvoiceDataTypeUrl, - CentrifugeId: hexutil.Encode(cid), - EventType: uint32(ReceivedPayload), - Recorded: ts, + DocumentId: hexutil.Encode(coredoc.DocumentIdentifier), + DocumentType: documenttypes.InvoiceDataTypeUrl, + CentrifugeId: hexutil.Encode(cid), + EventType: uint32(ReceivedPayload), + Recorded: ts, } whs := WebhookSender{} From c1f7df22a477982df06a43aa03a1881c6028b009 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 8 Nov 2018 12:19:10 +0530 Subject: [PATCH 016/220] Add api logs (#413) * Add api logs * Review comments --- documents/invoice/handler.go | 4 ++++ documents/purchaseorder/handler.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 9ea0db8ab..6e39016c6 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -34,6 +34,7 @@ func GRPCHandler() (clientinvoicepb.DocumentServiceServer, error) { // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { + apiLog.Debugf("Create request %v", req) ctxHeader, err := documents.NewContextHeader() if err != nil { apiLog.Error(err) @@ -58,6 +59,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { + apiLog.Debugf("Update request %v", payload) ctxHeader, err := documents.NewContextHeader() if err != nil { apiLog.Error(err) @@ -81,6 +83,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi // GetVersion returns the requested version of the document func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clientinvoicepb.GetVersionRequest) (*clientinvoicepb.InvoiceResponse, error) { + apiLog.Debugf("Get version request %v", getVersionRequest) identifier, err := hexutil.Decode(getVersionRequest.Identifier) if err != nil { apiLog.Error(err) @@ -106,6 +109,7 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti // Get returns the invoice the latest version of the document with given identifier func (h *grpcHandler) Get(ctx context.Context, getRequest *clientinvoicepb.GetRequest) (*clientinvoicepb.InvoiceResponse, error) { + apiLog.Debugf("Get request %v", getRequest) identifier, err := hexutil.Decode(getRequest.Identifier) if err != nil { apiLog.Error(err) diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index abf348533..6c993e203 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -35,6 +35,7 @@ func GRPCHandler() (clientpurchaseorderpb.DocumentServiceServer, error) { // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { + apiLog.Debugf("Create request %v", req) ctxh, err := documents.NewContextHeader() if err != nil { apiLog.Error(err) @@ -59,6 +60,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { + apiLog.Debugf("Update request %v", payload) ctxHeader, err := documents.NewContextHeader() if err != nil { apiLog.Error(err) @@ -82,6 +84,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. // GetVersion returns the requested version of a purchase order func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb.GetVersionRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { + apiLog.Debugf("GetVersion request %v", req) identifier, err := hexutil.Decode(req.Identifier) if err != nil { apiLog.Error(err) @@ -107,6 +110,7 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. // Get returns the purchase order the latest version of the document with given identifier func (h grpcHandler) Get(ctx context.Context, getRequest *clientpurchaseorderpb.GetRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { + apiLog.Debugf("Get request %v", getRequest) identifier, err := hexutil.Decode(getRequest.Identifier) if err != nil { apiLog.Error(err) From c369ea27a8b3423ca2648d980b830fcfd0640e23 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 8 Nov 2018 10:11:05 +0100 Subject: [PATCH 017/220] Adding notification sample to config example (#416) --- build/resources/centrifuge_example.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/resources/centrifuge_example.yaml b/build/resources/centrifuge_example.yaml index d41454d53..3abe8c7af 100644 --- a/build/resources/centrifuge_example.yaml +++ b/build/resources/centrifuge_example.yaml @@ -23,6 +23,10 @@ p2p: #externalIP: 100.111.112.113 port: 38202 +#Configure your node to push notifications to your custom WebHook +#notifications: +# endpoint: "https://webhook.site/9fa0b32f-c745-4367-acd6-a7ed418ef608" + ethereum: accounts: main: From c10f8d534ae87ae23a129a30c80c93870f8018f0 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 9 Nov 2018 11:27:55 +0100 Subject: [PATCH 018/220] NFT: added events/workers, latest contract version, using centrifuge/go-ethereum (#400) * Fix problem with creating ids * Worker for watching NFT minting events * Worker for watching NFT minting events * added correct encoding for worker * formatting * updated to latest paymentObligation contract version * correct collaborators passing * latest centrifuge contracts & using centrifuge/go-ethereum * fixed dependencies except contracts * added latest contracts * reset integration test config * formatting * fixed unit tests for nft minting * reduced scope of public variables * formatting * reduced public functions in nft package --- Gopkg.lock | 27 ++-- Gopkg.toml | 11 +- build/scripts/tests/run_integration_tests.sh | 2 +- cmd/manage_identities.go | 3 +- nft/bootstrapper.go | 7 +- nft/ethereum_payment_obligation.go | 123 +++++++++++------ nft/ethereum_payment_obligation_contract.go | 26 ++-- nft/ethereum_payment_obligation_test.go | 30 +++-- nft/handler.go | 5 +- nft/handler_test.go | 19 ++- nft/minting_confirmation_task.go | 132 +++++++++++++++++++ nft/payment_obligation.go | 9 +- nft/payment_obligation_integration_test.go | 11 +- 13 files changed, 303 insertions(+), 102 deletions(-) create mode 100644 nft/minting_confirmation_task.go diff --git a/Gopkg.lock b/Gopkg.lock index ffd6a3ba5..0836fa8e4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -38,15 +38,14 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - branch = "develop" - digest = "1:2ad07f3fadd7fbed5895432782ffd4c427b766a1237b979590edbcc02d78ba68" + digest = "1:8f8c3deed3c1e42a1fbe03b386408023f376f388297294b683125ae4bb90324a" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "c60964592c1a2b83c5676878c937cdbe6719869d" + revision = "d9a240d86d05350de86c26ed23d72b45562ae155" [[projects]] - digest = "1:66b6977457e5e7eff7aba31099caed6f2a21480f5616b4e32bf982715ab24b8b" + digest = "1:e296ad994e618f237b1fd55450f99007017a8aedd981628d2bb3d09704deab3a" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -58,7 +57,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "2660f56a4edb61312b7eb83a986fb5ae6ea73255" + revision = "51fb5cf922b4a413a78397ad3707f755cfd48abf" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" @@ -75,7 +74,7 @@ "proofs/proto", ] pruneopts = "UT" - revision = "1abae88cef959657117754ae7602a5285d1008cc" + revision = "ff15857d84b0eea93e52cc465f71662b78f62f6f" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" @@ -102,7 +101,7 @@ version = "v1.7" [[projects]] - digest = "1:ba11b65320bfa1a5e8e43b050833bca23490e508a67c45d7e430156cefc2ab7f" + digest = "1:0f390470311a75caba6b4223dcd881d4a9c5141afaf7fef3c5908c145a5073dd" name = "github.com/ethereum/go-ethereum" packages = [ ".", @@ -114,6 +113,7 @@ "common/hexutil", "common/math", "common/mclock", + "common/prque", "core/types", "crypto", "crypto/secp256k1", @@ -130,8 +130,8 @@ "trie", ] pruneopts = "T" - revision = "89451f7c382ad2185987ee369f16416f89c28a7d" - version = "v1.8.15" + revision = "e024c16f34c6028060b645efae1d6258e442442a" + source = "github.com/centrifuge/go-ethereum" [[projects]] digest = "1:d1341a04a4443bba8c8af76ec6c3960206074490a1284b4853ff5a88a66c63b7" @@ -1311,14 +1311,6 @@ revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1" version = "v1.15.0" -[[projects]] - branch = "v2" - digest = "1:0a2f4b974a413866afa1b41130d756643841fb9ad661b81c9a6dd9f1364ed19f" - name = "gopkg.in/karalabe/cookiejar.v2" - packages = ["collections/prque"] - pruneopts = "UT" - revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57" - [[projects]] branch = "v2" digest = "1:3d3f9391ab615be8655ae0d686a1564f3fec413979bb1aaf018bac1ec1bb1cc7" @@ -1369,6 +1361,7 @@ "github.com/ethereum/go-ethereum/crypto/secp256k1", "github.com/ethereum/go-ethereum/ethclient", "github.com/ethereum/go-ethereum/event", + "github.com/ethereum/go-ethereum/log", "github.com/ethereum/go-ethereum/rpc", "github.com/go-errors/errors", "github.com/golang/protobuf/jsonpb", diff --git a/Gopkg.toml b/Gopkg.toml index cd62bc726..e1e36c10f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,11 +28,11 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "2660f56a4edb61312b7eb83a986fb5ae6ea73255" + revision = "51fb5cf922b4a413a78397ad3707f755cfd48abf" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - branch = "develop" + revision = "d9a240d86d05350de86c26ed23d72b45562ae155" [[constraint]] name = "github.com/Masterminds/semver" @@ -40,7 +40,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/precise-proofs" - revision = "1abae88cef959657117754ae7602a5285d1008cc" + revision = "ff15857d84b0eea93e52cc465f71662b78f62f6f" [[constraint]] name = "github.com/centrifuge/gocelery" @@ -52,7 +52,8 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/ethereum/go-ethereum" - version = "1.8.15" + source = "github.com/centrifuge/go-ethereum" + revision = "e024c16f34c6028060b645efae1d6258e442442a" [[override]] name = "github.com/satori/go.uuid" @@ -293,4 +294,4 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [prune] go-tests = true - unused-packages = true + unused-packages = true \ No newline at end of file diff --git a/build/scripts/tests/run_integration_tests.sh b/build/scripts/tests/run_integration_tests.sh index 767336b17..f15ee24b3 100755 --- a/build/scripts/tests/run_integration_tests.sh +++ b/build/scripts/tests/run_integration_tests.sh @@ -24,4 +24,4 @@ for d in $(go list -tags=integration ./... | grep -v vendor); do fi done -exit $status +exit $status \ No newline at end of file diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 38350ce4a..773ce9723 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -18,7 +18,6 @@ var createIdentityCmd = &cobra.Command{ //cmd requires a config file readConfigFile() baseBootstrap() - identityService := identity.EthereumIdentityService{} var centrifugeId identity.CentID var err error if centrifugeIdString == "" { @@ -29,7 +28,7 @@ var createIdentityCmd = &cobra.Command{ panic(err) } } - _, confirmations, err := identityService.CreateIdentity(centrifugeId) + _, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) if err != nil { panic(err) } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 75b25a3f9..41b58ef99 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" ) type Bootstrapper struct { @@ -25,8 +26,10 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } - setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config())) - return nil + + setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config(), setupMintListener)) + return queue.InstallQueuedTask(context, + newMintingConfirmationTask(contract, ethereum.DefaultWaitForTransactionMiningContext)) } func getPaymentObligationContract() (*EthereumPaymentObligationContract, error) { diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 4e9b4fd28..6ecc3d768 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -1,18 +1,24 @@ package nft import ( + "context" + "encoding/hex" + "fmt" "math/big" + "github.com/centrifuge/gocelery" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/go-errors/errors" + logging "github.com/ipfs/go-log" ) @@ -20,6 +26,8 @@ var log = logging.Logger("nft") var po *ethereumPaymentObligation +const amountOfProofs = 5 + func setPaymentObligation(s *ethereumPaymentObligation) { po = s } @@ -38,7 +46,7 @@ type Config interface { type ethereumPaymentObligationContract interface { // Mint method abstracts Mint method on the contract - Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values [3]string, _salts [3][32]byte, _proofs [3][][32]byte) (*types.Transaction, error) + Mint(opts *bind.TransactOpts, to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, merkleRoot [32]byte, collaboratorField string, values [5]string, salts [5][32]byte, proofs [5][][32]byte) (*types.Transaction, error) } // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum @@ -47,72 +55,107 @@ type ethereumPaymentObligation struct { identityService identity.Service ethClient ethereum.Client config Config + setupMintListener func(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error) } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func NewEthereumPaymentObligation(paymentObligation ethereumPaymentObligationContract, identityService identity.Service, ethClient ethereum.Client, config Config) *ethereumPaymentObligation { - return ðereumPaymentObligation{paymentObligation: paymentObligation, identityService: identityService, ethClient: ethClient, config: config} +func NewEthereumPaymentObligation(paymentObligation ethereumPaymentObligationContract, identityService identity.Service, ethClient ethereum.Client, config Config, setupMintListener func(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error)) *ethereumPaymentObligation { + return ðereumPaymentObligation{paymentObligation: paymentObligation, identityService: identityService, ethClient: ethClient, config: config, setupMintListener: setupMintListener} } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (string, error) { +func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { docService, err := getDocumentService(docType) if err != nil { - return "", err + return nil, err } model, err := docService.GetCurrentVersion(documentID) if err != nil { - return "", err + return nil, err } corDoc, err := model.PackCoreDocument() if err != nil { - return "", err + return nil, err } proofs, err := docService.CreateProofs(documentID, proofFields) if err != nil { - return "", err + return nil, err } toAddress, err := s.getIdentityAddress() if err != nil { - return "", nil + return nil, nil } anchorID, err := anchors.ToAnchorID(corDoc.CurrentVersion) if err != nil { - return "", nil + return nil, nil } rootHash, err := anchors.ToDocumentRoot(corDoc.DocumentRoot) if err != nil { - return "", nil + return nil, nil } - requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash) + //last proofField should be the collaborator + requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash, proofFields[len(proofFields)-1]) if err != nil { - return "", err + return nil, err } opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { - return "", err + return nil, err + } + + watch, err := s.setupMintListener(requestData.TokenID) + if err != nil { + return nil, err } err = s.sendMintTransaction(s.paymentObligation, opts, requestData) if err != nil { - return "", err + return nil, err } - return requestData.TokenID.String(), nil + return watch, nil +} + +// setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code +// about successful minting of an NFt +func setupMintListener(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error) { + confirmations = make(chan *WatchTokenMinted) + conn := ethereum.GetClient() + + h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) + if err != nil { + return nil, err + } + asyncRes, err := queue.Queue.DelayKwargs(mintingConfirmationTaskName, map[string]interface{}{ + tokenIDParam: hex.EncodeToString(tokenID.Bytes()), + blockHeight: h.Number.Uint64(), + }) + if err != nil { + return nil, err + } + + go waitAndRouteNFTApprovedEvent(asyncRes, tokenID, confirmations) + return confirmations, nil +} + +// waitAndRouteNFTApprovedEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event +func waitAndRouteNFTApprovedEvent(asyncRes *gocelery.AsyncResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { + _, err := asyncRes.Get(ethereum.GetDefaultContextTimeout()) + confirmations <- &WatchTokenMinted{tokenID, err} } // sendMintTransaction sends the actual transaction to mint the NFT func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (err error) { tx, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, - requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) + requestData.MerkleRoot, requestData.CollaboratorField, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { return err } @@ -158,18 +201,21 @@ type MintRequest struct { // MerkleRoot is the root hash of the merkle proof/doc MerkleRoot [32]byte + //CollaboratorField contains the value of the collaborator leaf + CollaboratorField string + // Values are the values of the leafs that is being proved Will be converted to string and concatenated for proof verification as outlined in precise-proofs library. - Values [3]string + Values [amountOfProofs]string // salts are the salts for the field that is being proved Will be concatenated for proof verification as outlined in precise-proofs library. - Salts [3][32]byte + Salts [amountOfProofs][32]byte // Proofs are the documents proofs that are needed - Proofs [3][][32]byte + Proofs [amountOfProofs][][32]byte } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (*MintRequest, error) { +func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte, collaboratorField string) (*MintRequest, error) { tokenID := utils.ByteSliceToBigInt(utils.RandomSlice(256)) tokenURI := "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" proofData, err := createProofData(proofs) @@ -178,29 +224,30 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo } return &MintRequest{ - To: to, - TokenID: tokenID, - TokenURI: tokenURI, - AnchorID: anchorID.BigInt(), - MerkleRoot: rootHash, - Values: proofData.Values, - Salts: proofData.Salts, - Proofs: proofData.Proofs}, nil + To: to, + TokenID: tokenID, + TokenURI: tokenURI, + AnchorID: anchorID.BigInt(), + MerkleRoot: rootHash, + CollaboratorField: collaboratorField, + Values: proofData.Values, + Salts: proofData.Salts, + Proofs: proofData.Proofs}, nil } type proofData struct { - Values [3]string - Salts [3][32]byte - Proofs [3][][32]byte + Values [amountOfProofs]string + Salts [amountOfProofs][32]byte + Proofs [amountOfProofs][][32]byte } func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { - if len(proofspb) > 3 { - return nil, errors.New("no more than 3 field proofs are accepted") + if len(proofspb) > amountOfProofs { + return nil, fmt.Errorf("no more than %v field proofs are accepted", amountOfProofs) } - var values [3]string - var salts [3][32]byte - var proofs [3][][32]byte + var values [amountOfProofs]string + var salts [amountOfProofs][32]byte + var proofs [amountOfProofs][][32]byte for i, p := range proofspb { values[i] = p.Value diff --git a/nft/ethereum_payment_obligation_contract.go b/nft/ethereum_payment_obligation_contract.go index a2018de38..140f3e6a5 100644 --- a/nft/ethereum_payment_obligation_contract.go +++ b/nft/ethereum_payment_obligation_contract.go @@ -16,7 +16,7 @@ import ( ) // EthereumPaymentObligationContractABI is the input ABI used to generate the binding from. -const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"InterfaceId_ERC165\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes4\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"},{\"name\":\"_anchorRegistry\",\"type\":\"address\"},{\"name\":\"_identityRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_tokenURI\",\"type\":\"string\"},{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_values\",\"type\":\"string[3]\"},{\"name\":\"_salts\",\"type\":\"bytes32[3]\"},{\"name\":\"_proofs\",\"type\":\"bytes32[][3]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"string\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"dueDate\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"InterfaceId_ERC165\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes4\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"},{\"name\":\"_anchorRegistry\",\"type\":\"address\"},{\"name\":\"_identityRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_tokenURI\",\"type\":\"string\"},{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_collaboratorField\",\"type\":\"string\"},{\"name\":\"_values\",\"type\":\"string[5]\"},{\"name\":\"_salts\",\"type\":\"bytes32[5]\"},{\"name\":\"_proofs\",\"type\":\"bytes32[][5]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"string\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"dueDate\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // EthereumPaymentObligationContract is an auto generated Go binding around an Ethereum contract. type EthereumPaymentObligationContract struct { @@ -593,25 +593,25 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTrans return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId) } -// Mint is a paid mutator transaction binding the contract method 0xb279f8f1. +// Mint is a paid mutator transaction binding the contract method 0xcb40425f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[3], _salts bytes32[3], _proofs bytes32[][3]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values [3]string, _salts [3][32]byte, _proofs [3][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) } -// Mint is a paid mutator transaction binding the contract method 0xb279f8f1. +// Mint is a paid mutator transaction binding the contract method 0xcb40425f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[3], _salts bytes32[3], _proofs bytes32[][3]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values [3]string, _salts [3][32]byte, _proofs [3][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) } -// Mint is a paid mutator transaction binding the contract method 0xb279f8f1. +// Mint is a paid mutator transaction binding the contract method 0xcb40425f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[3], _salts bytes32[3], _proofs bytes32[][3]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values [3]string, _salts [3][32]byte, _proofs [3][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 991a59547..7e61efb2c 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -51,9 +51,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [3]string{"value1", "value2"}, - Proofs: [3][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [3][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: [amountOfProofs]string{"value1", "value2"}, + Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, nil, }, @@ -74,9 +74,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [3]string{"value1", "value2"}, - Proofs: [3][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [3][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: [amountOfProofs]string{"value1", "value2"}, + Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, errors.New("input exceeds length of 32"), }, @@ -97,9 +97,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [3]string{"value1", "value2"}, - Proofs: [3][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [3][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: [amountOfProofs]string{"value1", "value2"}, + Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, errors.New("input exceeds length of 32"), }, @@ -124,7 +124,7 @@ type MockPaymentObligation struct { mock.Mock } -func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values [3]string, _salts [3][32]byte, _proofs [3][][32]byte) (*types.Transaction, error) { +func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, collaboratorField string, _values [amountOfProofs]string, _salts [amountOfProofs][32]byte, _proofs [amountOfProofs][][32]byte) (*types.Transaction, error) { args := m.Called(opts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) return args.Get(0).(*types.Transaction), args.Error(1) } @@ -171,7 +171,7 @@ func TestPaymentObligationService(t *testing.T) { ethClientMock.On("SubmitTransactionWithRetries", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, ).Return(&types.Transaction{}, nil) configMock := MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") @@ -189,8 +189,11 @@ func TestPaymentObligationService(t *testing.T) { docService, paymentOb, idService, ethClient, config := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton documents.GetRegistryInstance().Register(test.name, &docService) - service := NewEthereumPaymentObligation(paymentOb, &idService, ðClient, &config) - tokenID, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.Type, test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + confirmations := make(chan *WatchTokenMinted) + service := NewEthereumPaymentObligation(paymentOb, &idService, ðClient, &config, func(tokenID *big.Int) (chan *WatchTokenMinted, error) { + return confirmations, nil + }) + _, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.Type, test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { @@ -201,7 +204,6 @@ func TestPaymentObligationService(t *testing.T) { idService.AssertExpectations(t) ethClient.AssertExpectations(t) config.AssertExpectations(t) - assert.NotEmpty(t, tokenID) }) } } diff --git a/nft/handler.go b/nft/handler.go index 48c28891b..2d8cdb4dc 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -29,9 +29,10 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) } - tokenID, err := g.service.MintNFT(identifier, request.Type, request.RegistryAddress, request.DepositAddress, request.ProofFields) + confirmation, err := g.service.MintNFT(identifier, request.Type, request.RegistryAddress, request.DepositAddress, request.ProofFields) if err != nil { return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) } - return &nftpb.NFTMintResponse{TokenId: tokenID}, nil + watchToken := <-confirmation + return &nftpb.NFTMintResponse{TokenId: watchToken.TokenID.String()}, watchToken.Err } diff --git a/nft/handler_test.go b/nft/handler_test.go index b389ff60f..0100315d7 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "math/big" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/go-errors/errors" @@ -17,25 +19,31 @@ type MockPaymentObligationService struct { mock.Mock } -func (m *MockPaymentObligationService) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (string, error) { +func (m *MockPaymentObligationService) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { args := m.Called(documentID, docType, registryAddress, depositAddress, proofFields) - return args.Get(0).(string), args.Error(1) + return args.Get(0).(chan *WatchTokenMinted), args.Error(1) } func TestNFTMint_success(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &MockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) + confirmations := make(chan *WatchTokenMinted) mockService. On("MintNFT", docID, nftMintRequest.Type, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return("tokenID", nil) + Return(confirmations, nil) + + tokID := big.NewInt(1) + go func() { + confirmations <- &WatchTokenMinted{tokID, nil} + }() handler := grpcHandler{mockService} nftMintResponse, err := handler.MintNFT(context.Background(), nftMintRequest) mockService.AssertExpectations(t) assert.Nil(t, err, "mint nft should be successful") - assert.NotEqual(t, "", nftMintResponse.TokenId, "tokenId should have a dummy value") + assert.Equal(t, tokID.String(), nftMintResponse.TokenId, "TokenID should have a dummy value") } func TestNFTMint_InvalidIdentifier(t *testing.T) { @@ -50,9 +58,10 @@ func TestNFTMint_ServiceError(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &MockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) + confirmations := make(chan *WatchTokenMinted) mockService. On("MintNFT", docID, nftMintRequest.Type, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return("", errors.New("service error")) + Return(confirmations, errors.New("service error")) handler := grpcHandler{mockService} _, err := handler.MintNFT(context.Background(), nftMintRequest) diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go new file mode 100644 index 000000000..e7cb615be --- /dev/null +++ b/nft/minting_confirmation_task.go @@ -0,0 +1,132 @@ +package nft + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/centrifuge/gocelery" + + "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/accounts/abi/bind" +) + +const ( + mintingConfirmationTaskName string = "MintingConfirmationTaskName" + tokenIDParam string = "TokenIDParam" + blockHeight string = "BlockHeight" +) + +// paymentObligationMintedFilterer filters the approved NFTs +type paymentObligationMintedFilterer interface { + + // FilterPaymentObligationMinted filters PaymentObligationMinted events + FilterPaymentObligationMinted(opts *bind.FilterOpts) (*EthereumPaymentObligationContractPaymentObligationMintedIterator, error) +} + +// mintingConfirmationTask confirms the minting of a payment obligation NFT +type mintingConfirmationTask struct { + TokenID string + BlockHeight uint64 + EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + EthContext context.Context + PaymentObligationMintedFilterer paymentObligationMintedFilterer +} + +func newMintingConfirmationTask( + nftApprovedFilterer paymentObligationMintedFilterer, + ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), +) *mintingConfirmationTask { + return &mintingConfirmationTask{ + PaymentObligationMintedFilterer: nftApprovedFilterer, + EthContextInitializer: ethContextInitializer, + } +} + +// Name returns mintingConfirmationTaskName +func (nftc *mintingConfirmationTask) Name() string { + return mintingConfirmationTaskName +} + +// Init registers the task to the queue +func (nftc *mintingConfirmationTask) Init() error { + queue.Queue.Register(mintingConfirmationTaskName, nftc) + return nil +} + +// Copy returns a new instance of mintingConfirmationTask +func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { + return &mintingConfirmationTask{ + nftc.TokenID, + nftc.BlockHeight, + nftc.EthContextInitializer, + nftc.EthContext, + nftc.PaymentObligationMintedFilterer, + }, nil +} + +// ParseKwargs - define a method to parse CentID +func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + tokenID, ok := kwargs[tokenIDParam] + if !ok { + return fmt.Errorf("undefined kwarg " + tokenIDParam) + } + nftc.TokenID, ok = tokenID.(string) + if !ok { + return fmt.Errorf("malformed kwarg [%s]", tokenIDParam) + } + + nftc.BlockHeight, err = parseBlockHeight(kwargs) + if err != nil { + return err + } + return nil +} + +func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { + if bhi, ok := valMap[blockHeight]; ok { + bhf, ok := bhi.(float64) + if ok { + return uint64(bhf), nil + } + } + return 0, errors.New("value can not be parsed") +} + +// RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. +func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { + log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.TokenID) + if nftc.EthContext == nil { + nftc.EthContext, _ = nftc.EthContextInitializer() + } + + fOpts := &bind.FilterOpts{ + Context: nftc.EthContext, + Start: nftc.BlockHeight, + } + + for { + iter, err := nftc.PaymentObligationMintedFilterer.FilterPaymentObligationMinted( + fOpts, + ) + if err != nil { + return nil, centerrors.Wrap(err, "failed to start filtering token minted logs") + } + + err = utils.LookForEvent(iter) + if err == nil { + log.Infof("Received filtered event NFT minted for token [%s] \n", nftc.TokenID) + return iter.Event, nil + } + + if err != utils.EventNotFound { + return nil, err + } + time.Sleep(100 * time.Millisecond) + } + + return nil, fmt.Errorf("failed to filter nft minted events") +} diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index 1000a354c..8ccdef025 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -1,8 +1,15 @@ package nft +import "math/big" + // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (string, error) + MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) +} + +type WatchTokenMinted struct { + TokenID *big.Int + Err error } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 1049354ca..cfe76495b 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/log" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" @@ -21,6 +23,7 @@ import ( ) func TestMain(m *testing.M) { + log.Debug("Test PreSetup for NFT") cc.TestFunctionalEthereumBootstrap() prevSignPubkey := config.Config().Get("keys.signing.publicKey") prevSignPrivkey := config.Config().Get("keys.signing.privateKey") @@ -41,6 +44,7 @@ func TestMain(m *testing.M) { func TestPaymentObligationService_mint(t *testing.T) { // create identity + log.Debug("Create Identity for Testing") testingidentity.CreateIdentityWithKeys() // create invoice (anchor) @@ -69,12 +73,15 @@ func TestPaymentObligationService_mint(t *testing.T) { assert.Nil(t, err, "should not error out when getting invoice ID") // call mint // assert no error - _, err = nft.GetPaymentObligation().MintNFT( + confirmations, err := nft.GetPaymentObligation().MintNFT( ID, documenttypes.InvoiceDataTypeUrl, "doesntmatter", "doesntmatter", - []string{"gross_amount", "currency", "due_date"}, + []string{"gross_amount", "currency", "due_date", "document_type", "collaborators[0]"}, ) assert.Nil(t, err, "should not error out when minting an invoice") + tokenConfirm := <-confirmations + assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") + assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") } From 06b5c4fe633a2354a0fc28ce9f9d505f7adab593 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 9 Nov 2018 16:57:10 +0100 Subject: [PATCH 019/220] add additional nil checks for data in the payload (#424) Fixes #419 Functional tests will be done once this is merged to develop --- documents/invoice/handler.go | 7 +++++++ documents/invoice/service.go | 11 +++++------ documents/invoice/service_test.go | 12 +++++++++++- documents/purchaseorder/handler.go | 7 +++++++ documents/purchaseorder/service.go | 4 ++-- documents/purchaseorder/service_test.go | 14 +++++++++++++- 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 6e39016c6..1d2619469 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -89,21 +89,25 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is invalid") } + version, err := hexutil.Decode(getVersionRequest.Version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "version is invalid") } + model, err := h.service.GetVersion(identifier, version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") } + resp, err := h.service.DeriveInvoiceResponse(model) if err != nil { apiLog.Error(err) return nil, err } + return resp, nil } @@ -115,15 +119,18 @@ func (h *grpcHandler) Get(ctx context.Context, getRequest *clientinvoicepb.GetRe apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is an invalid hex string") } + model, err := h.service.GetCurrentVersion(identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") } + resp, err := h.service.DeriveInvoiceResponse(model) if err != nil { apiLog.Error(err) return nil, err } + return resp, nil } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index e76b36898..8abe79de9 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -115,13 +115,13 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call -func (s service) DeriveFromCreatePayload(invoiceInput *clientinvoicepb.InvoiceCreatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { - if invoiceInput == nil { +func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { + if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "input is nil") } invoiceModel := new(Invoice) - err := invoiceModel.InitInvoiceInput(invoiceInput, contextHeader) + err := invoiceModel.InitInvoiceInput(payload, contextHeader) if err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -283,13 +283,12 @@ func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.Invoic return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") } - data := inv.getClientData() - return data, nil + return inv.getClientData(), nil } // DeriveFromUpdatePayload returns a new version of the old invoice identified by identifier in payload func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { - if payload == nil { + if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "invalid payload") } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 489a061d9..046f655ba 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -98,6 +98,10 @@ func TestService_DeriveFromPayload(t *testing.T) { _, err = invSrv.DeriveFromCreatePayload(nil, nil) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") + // fail due to nil payload data + _, err = invSrv.DeriveFromCreatePayload(&clientinvoicepb.InvoiceCreatePayload{}, nil) + assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") + contextHeader, err := documents.NewContextHeader() assert.Nil(t, err) model, err = invSrv.DeriveFromCreatePayload(payload, contextHeader) @@ -478,10 +482,16 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Contains(t, err.Error(), "invalid payload") assert.Nil(t, doc) + // nil payload data + doc, err = invSrv.DeriveFromUpdatePayload(&clientinvoicepb.InvoiceUpdatePayload{}, nil) + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid payload") + assert.Nil(t, doc) + // messed up identifier contextHeader, err := documents.NewContextHeader() assert.Nil(t, err) - payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier"} + payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to decode identifier") diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 6c993e203..d673cf00b 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -90,21 +90,25 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is invalid") } + version, err := hexutil.Decode(req.Version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "version is invalid") } + model, err := h.service.GetVersion(identifier, version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") } + resp, err := h.service.DerivePurchaseOrderResponse(model) if err != nil { apiLog.Error(err) return nil, err } + return resp, nil } @@ -116,15 +120,18 @@ func (h grpcHandler) Get(ctx context.Context, getRequest *clientpurchaseorderpb. apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is an invalid hex string") } + model, err := h.service.GetCurrentVersion(identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") } + resp, err := h.service.DerivePurchaseOrderResponse(model) if err != nil { apiLog.Error(err) return nil, err } + return resp, nil } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 01c399b7b..c70acbb40 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -143,7 +143,7 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode // DeriveFromCreatePayload derives purchase order from create payload func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *documents.ContextHeader) (documents.Model, error) { - if payload == nil { + if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "input is nil") } @@ -158,7 +158,7 @@ func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreate // DeriveFromUpdatePayload derives purchase order from update payload func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *documents.ContextHeader) (documents.Model, error) { - if payload == nil { + if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "invalid payload") } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 44e6e26c5..9ff66e7b5 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -133,10 +133,16 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Contains(t, err.Error(), "invalid payload") assert.Nil(t, doc) + // nil payload data + doc, err = poSrv.DeriveFromUpdatePayload(&clientpurchaseorderpb.PurchaseOrderUpdatePayload{}, nil) + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid payload") + assert.Nil(t, doc) + // messed up identifier contextHeader, err := documents.NewContextHeader() assert.Nil(t, err) - payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier"} + payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to decode identifier") @@ -209,6 +215,12 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "input is nil") + // nil data payload + m, err = poSrv.DeriveFromCreatePayload(&clientpurchaseorderpb.PurchaseOrderCreatePayload{}, ctxh) + assert.Nil(t, m) + assert.Error(t, err) + assert.Contains(t, err.Error(), "input is nil") + // Init fails payload := &clientpurchaseorderpb.PurchaseOrderCreatePayload{ Data: &clientpurchaseorderpb.PurchaseOrderData{ From 8097b2b747f218b67018b707f5e3dc9bd1beb52d Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 12 Nov 2018 11:19:15 +0100 Subject: [PATCH 020/220] First Step config (#422) * First Phase config * cleanup --- anchors/bootstrapper.go | 6 ++-- bootstrap/bootstrapper.go | 1 + cmd/create_config.go | 3 +- cmd/manage_identities.go | 9 +++--- cmd/root.go | 21 +++++++------ cmd/run.go | 4 +-- config/bootstrapper.go | 9 ++++-- config/configuration.go | 12 ++++---- ethereum/bootstrapper.go | 3 +- identity/bootstrapper.go | 26 ++++++++-------- nft/bootstrapper.go | 11 ++++--- node/bootstrapper.go | 63 ++++++++++++++++++++------------------- storage/bootstrapper.go | 3 +- 13 files changed, 92 insertions(+), 79 deletions(-) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 09fe3d58f..2ea3cc5a0 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -18,17 +18,19 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } client := ethereum.GetClient() - repositoryContract, err := NewEthereumAnchorRepositoryContract(config.Config().GetContractAddress("anchorRepository"), client.GetEthClient()) + repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress("anchorRepository"), client.GetEthClient()) if err != nil { return err } - anchorRepo := NewEthereumAnchorRepository(config.Config(), repositoryContract) + anchorRepo := NewEthereumAnchorRepository(cfg, repositoryContract) setAnchorRepository(anchorRepo) if err != nil { return err diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index b371a32a3..eef1d548c 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -3,6 +3,7 @@ package bootstrap // DO NOT PUT any app logic in this package to avoid any dependency cycles const ( + BootstrappedConfigFile string = "BootstrappedConfigFile" BootstrappedConfig string = "BootstrappedConfig" BootstrappedLevelDb string = "BootstrappedLevelDb" BootstrappedEthereumClient string = "BootstrappedEthereumClient" diff --git a/cmd/create_config.go b/cmd/create_config.go index 91eccc3f8..84fb61549 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -84,9 +84,8 @@ func init() { } log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) - config.Bootstrap(v.ConfigFileUsed()) + baseBootstrap(v.ConfigFileUsed()) generateKeys() - baseBootstrap() id, err := createIdentity() if err != nil { panic(err) diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 773ce9723..9363ef4e1 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -16,8 +16,8 @@ var createIdentityCmd = &cobra.Command{ Long: "", Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file - readConfigFile() - baseBootstrap() + cfgFile = ensureConfigFile() + baseBootstrap(cfgFile) var centrifugeId identity.CentID var err error if centrifugeIdString == "" { @@ -52,9 +52,8 @@ var addKeyCmd = &cobra.Command{ Long: "add a signing key as p2p id against ethereum", Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file - readConfigFile() - - baseBootstrap() + cfgFile = ensureConfigFile() + baseBootstrap(cfgFile) var purposeInt int diff --git a/cmd/root.go b/cmd/root.go index 8e7f8009a..aebf87b7f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" @@ -52,8 +52,8 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "set loglevel to debug") } -// readConfigFile reads in config file and ENV variables if set. -func readConfigFile() { +// ensureConfigFile ensures a config file is provided +func ensureConfigFile() string { if cfgFile == "" { // Find home directory. home, err := homedir.Dir() @@ -68,8 +68,7 @@ func readConfigFile() { cfgFile = "" } } - // If a config file is found, read it in. - config.Bootstrap(cfgFile) + return cfgFile } //setCentrifugeLoggers sets the loggers. @@ -86,20 +85,24 @@ func setCentrifugeLoggers() { } -func runBootstrap() { +func runBootstrap(cfgFile string) { mb := cc.MainBootstrapper{} mb.PopulateRunBootstrappers() - err := mb.Bootstrap(map[string]interface{}{}) + ctx := map[string]interface{}{} + ctx[bootstrap.BootstrappedConfigFile] = cfgFile + err := mb.Bootstrap(ctx) if err != nil { // application must not continue to run panic(err) } } -func baseBootstrap() { +func baseBootstrap(cfgFile string) { mb := cc.MainBootstrapper{} mb.PopulateBaseBootstrappers() - err := mb.Bootstrap(map[string]interface{}{}) + ctx := map[string]interface{}{} + ctx[bootstrap.BootstrappedConfigFile] = cfgFile + err := mb.Bootstrap(ctx) if err != nil { // application must not continue to run panic(err) diff --git a/cmd/run.go b/cmd/run.go index 3163580e9..e7ddd061c 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -11,9 +11,9 @@ var runCmd = &cobra.Command{ Long: ``, Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file - readConfigFile() + cfgFile := ensureConfigFile() // the following call will block - runBootstrap() + runBootstrap(cfgFile) }, } diff --git a/config/bootstrapper.go b/config/bootstrapper.go index c8566617e..8333652bc 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -1,13 +1,18 @@ package config import ( + "errors" + "github.com/centrifuge/go-centrifuge/bootstrap" ) type Bootstrapper struct{} func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - Config().InitializeViper() - context[bootstrap.BootstrappedConfig] = Config() + if _, ok := context[bootstrap.BootstrappedConfigFile]; !ok { + return errors.New("config file hasn't been provided") + } + cfgFile := context[bootstrap.BootstrappedConfigFile].(string) + context[bootstrap.BootstrappedConfig] = NewConfiguration(cfgFile) return nil } diff --git a/config/configuration.go b/config/configuration.go index a0e5c0c27..7e0bd7d7e 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -265,7 +265,11 @@ func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { // Configuration Implementation func NewConfiguration(configFile string) *Configuration { - return &Configuration{configFile: configFile, mu: sync.RWMutex{}} + cfg := &Configuration{configFile: configFile, mu: sync.RWMutex{}} + cfg.InitializeViper() + //TODO Will remove this soon, when we do not use global config variable + SetConfig(cfg) + return cfg } func (c *Configuration) readConfigFile(path string) error { @@ -313,12 +317,6 @@ func (c *Configuration) InitializeViper() { c.v.SetEnvPrefix("CENT") } -func Bootstrap(configFile string) { - c := NewConfiguration(configFile) - c.InitializeViper() - SetConfig(c) -} - // CreateConfigFile creates minimum config file with arguments func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { targetDataDir := args["targetDataDir"].(string) diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index c5feeaa42..4359a4706 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -14,7 +14,8 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - client, err := NewGethClient(config.Config()) + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + client, err := NewGethClient(cfg) if err != nil { return err } diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 5df617ebe..2b7cd68ca 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" + "github.com/ethereum/go-ethereum/common" ) type Bootstrapper struct { @@ -18,47 +19,44 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } - idFactory, err := getIdentityFactoryContract() + idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress("identityFactory")) if err != nil { return err } - registryContract, err := getIdentityRegistryContract() + registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress("identityRegistry")) if err != nil { return err } - IDService = NewEthereumIdentityService(config.Config(), idFactory, registryContract) - - identityContract, err := getIdentityFactoryContract() - if err != nil { - return err - } + IDService = NewEthereumIdentityService(cfg, idFactory, registryContract) err = queue.InstallQueuedTask(context, - newIdRegistrationConfirmationTask(&identityContract.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) + newIdRegistrationConfirmationTask(&idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) if err != nil { return err } err = queue.InstallQueuedTask(context, - newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, config.Config())) + newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg)) if err != nil { return err } return nil } -func getIdentityFactoryContract() (identityFactoryContract *EthereumIdentityFactoryContract, err error) { +func getIdentityFactoryContract(factoryAddress common.Address) (identityFactoryContract *EthereumIdentityFactoryContract, err error) { client := ethereum.GetClient() - return NewEthereumIdentityFactoryContract(config.Config().GetContractAddress("identityFactory"), client.GetEthClient()) + return NewEthereumIdentityFactoryContract(factoryAddress, client.GetEthClient()) } -func getIdentityRegistryContract() (identityRegistryContract *EthereumIdentityRegistryContract, err error) { +func getIdentityRegistryContract(registryAddress common.Address) (identityRegistryContract *EthereumIdentityRegistryContract, err error) { client := ethereum.GetClient() - return NewEthereumIdentityRegistryContract(config.Config().GetContractAddress("identityRegistry"), client.GetEthClient()) + return NewEthereumIdentityRegistryContract(registryAddress, client.GetEthClient()) } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 41b58ef99..128acf758 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + "github.com/ethereum/go-ethereum/common" ) type Bootstrapper struct { @@ -18,21 +19,23 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } - contract, err := getPaymentObligationContract() + contract, err := getPaymentObligationContract(cfg.GetContractAddress("paymentObligation")) if err != nil { return err } - setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), config.Config(), setupMintListener)) + setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), cfg, setupMintListener)) return queue.InstallQueuedTask(context, newMintingConfirmationTask(contract, ethereum.DefaultWaitForTransactionMiningContext)) } -func getPaymentObligationContract() (*EthereumPaymentObligationContract, error) { +func getPaymentObligationContract(obligationAddress common.Address) (*EthereumPaymentObligationContract, error) { client := ethereum.GetClient() - return NewEthereumPaymentObligationContract(config.Config().GetContractAddress("paymentObligation"), client.GetEthClient()) + return NewEthereumPaymentObligationContract(obligationAddress, client.GetEthClient()) } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 913b022ef..c775df3ca 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -18,36 +18,39 @@ type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { - if _, ok := c[bootstrap.BootstrappedConfig]; ok { - services, err := defaultServerList() - if err != nil { - return fmt.Errorf("failed to get default server list: %v", err) - } + if _, ok := c[bootstrap.BootstrappedConfig]; !ok { + return errors.New("config hasn't been initialized") + } + cfg := c[bootstrap.BootstrappedConfig].(*config.Configuration) + + services, err := defaultServerList(cfg) + if err != nil { + return fmt.Errorf("failed to get default server list: %v", err) + } - n := NewNode(services) - feedback := make(chan error) - // may be we can pass a context that exists in c here - ctx, canc := context.WithCancel(context.Background()) - go n.Start(ctx, feedback) - controlC := make(chan os.Signal, 1) - signal.Notify(controlC, os.Interrupt) - for { - select { - case err := <-feedback: - panic(err) - case sig := <-controlC: - log.Info("Node shutting down because of ", sig) - canc() - err := <-feedback - return err - } + n := NewNode(services) + feedback := make(chan error) + // may be we can pass a context that exists in c here + ctx, canc := context.WithCancel(context.Background()) + go n.Start(ctx, feedback) + controlC := make(chan os.Signal, 1) + signal.Notify(controlC, os.Interrupt) + for { + select { + case err := <-feedback: + panic(err) + case sig := <-controlC: + log.Info("Node shutting down because of ", sig) + canc() + err := <-feedback + return err } - return nil } - return errors.New("could not initialize node") + + return nil } -func defaultServerList() ([]Server, error) { +func defaultServerList(cfg *config.Configuration) ([]Server, error) { publicKey, privateKey, err := ed25519.GetSigningKeyPairFromConfig() if err != nil { return nil, fmt.Errorf("failed to get keys: %v", err) @@ -55,13 +58,13 @@ func defaultServerList() ([]Server, error) { return []Server{ api.NewCentAPIServer( - config.Config().GetServerAddress(), - config.Config().GetServerPort(), - config.Config().GetNetworkString(), + cfg.GetServerAddress(), + cfg.GetServerPort(), + cfg.GetNetworkString(), ), p2p.NewCentP2PServer( - config.Config().GetP2PPort(), - config.Config().GetBootstrapPeers(), + cfg.GetP2PPort(), + cfg.GetBootstrapPeers(), publicKey, privateKey, ), }, nil diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index f159bfa43..7f5dbc165 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -15,8 +15,9 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config not initialised") } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) - levelDB, err := NewLevelDBStorage(config.Config().GetStoragePath()) + levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } From 373a486b2ae392fba42481870c22ff3ff394d3ad Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 13 Nov 2018 12:20:01 +0100 Subject: [PATCH 021/220] First batch of removing global config access (#441) * First Phase config * cleanup * global removal --- api/server.go | 32 +++++++-------- api/server_test.go | 18 +++++++-- api/service.go | 4 +- config/test_bootstrapper.go | 2 - coredocument/coredocument_test.go | 30 ++++++++++++-- coredocument/processor.go | 37 ++++++++++------- coredocument/processor_test.go | 33 ++++++++------- coredocument/validator_test.go | 19 --------- documents/invoice/bootstrapper.go | 8 +++- documents/invoice/service.go | 5 ++- documents/invoice/service_test.go | 4 +- documents/purchaseorder/bootstrapper.go | 8 +++- documents/purchaseorder/service.go | 5 ++- documents/purchaseorder/service_test.go | 2 +- ethereum/geth_client_test.go | 14 ++++--- healthcheck/handler.go | 17 +++++--- healthcheck/handler_test.go | 13 +++--- node/bootstrapper.go | 19 +-------- notification/notification.go | 15 +++++-- p2p/client.go | 23 ++++++----- p2p/client_test.go | 23 ++--------- p2p/handler.go | 5 +-- p2p/handler_integration_test.go | 3 +- p2p/handler_test.go | 33 ++++++++++----- p2p/server.go | 53 ++++++++++++------------- p2p/server_test.go | 51 +++++++++++------------- queue/bootstrapper.go | 13 +++++- queue/queue.go | 7 ++-- testingutils/utils.go | 8 ++-- 29 files changed, 265 insertions(+), 239 deletions(-) diff --git a/api/server.go b/api/server.go index 656b5159e..689a74af2 100644 --- a/api/server.go +++ b/api/server.go @@ -24,23 +24,19 @@ import ( var log = logging.Logger("cent-api-server") +type Config interface { + GetServerAddress() string + GetServerPort() int + GetNetworkString() string +} + // CentAPIServer is an implementation of node.Server interface for serving HTTP based Centrifuge API type CentAPIServer struct { - Address string - Port int - CentNetwork string + config Config } -func NewCentAPIServer( - address string, - port int, - centNetwork string, -) *CentAPIServer { - return &CentAPIServer{ - Address: address, - Port: port, - CentNetwork: centNetwork, - } +func NewCentAPIServer(config Config) *CentAPIServer { + return &CentAPIServer{config} } func (*CentAPIServer) Name() string { @@ -58,7 +54,7 @@ func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr if err != nil { startupErr <- err } - addr := c.Address + addr := c.config.GetServerAddress() creds := credentials.NewTLS(&tls.Config{ RootCAs: certPool, @@ -81,7 +77,7 @@ func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr mux := http.NewServeMux() gwmux := runtime.NewServeMux() - err = registerServices(ctx, grpcServer, gwmux, addr, dopts) + err = registerServices(ctx, c.config, grpcServer, gwmux, addr, dopts) if err != nil { startupErr <- err return @@ -99,13 +95,13 @@ func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr startUpErrOut := make(chan error) go func(startUpErrInner chan<- error) { - conn, err := net.Listen("tcp", c.Address) + conn, err := net.Listen("tcp", c.config.GetServerAddress()) if err != nil { startUpErrInner <- err return } - log.Infof("HTTP/gRpc listening on Port: %d\n", c.Port) - log.Infof("Connecting to Network: %s\n", c.CentNetwork) + log.Infof("HTTP/gRpc listening on Port: %d\n", c.config.GetServerPort()) + log.Infof("Connecting to Network: %s\n", c.config.GetNetworkString()) err = srv.Serve(tls.NewListener(conn, srv.TLSConfig)) if err != nil { startUpErrInner <- err diff --git a/api/server_test.go b/api/server_test.go index 7ff2f6f99..e91299a30 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -20,6 +20,9 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, @@ -28,7 +31,8 @@ func TestMain(m *testing.M) { &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -36,8 +40,11 @@ func TestMain(m *testing.M) { } func TestCentAPIServer_StartContextCancel(t *testing.T) { - documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(nil, nil, nil)) - capi := NewCentAPIServer("0.0.0.0:9000", 9000, "") + cfg.Set("nodeHostname", "0.0.0.0") + cfg.Set("nodePort", 9000) + cfg.Set("centrifugeNetwork", "") + documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil)) + capi := NewCentAPIServer(cfg) ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -50,7 +57,10 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { func TestCentAPIServer_StartListenError(t *testing.T) { // cause an error by using an invalid port - capi := NewCentAPIServer("0.0.0.0:100000000", 100000000, "") + cfg.Set("nodeHostname", "0.0.0.0") + cfg.Set("nodePort", 100000000) + cfg.Set("centrifugeNetwork", "") + capi := NewCentAPIServer(cfg) ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup diff --git a/api/service.go b/api/service.go index c67ffd193..825afc716 100644 --- a/api/service.go +++ b/api/service.go @@ -19,7 +19,7 @@ import ( ) // registerServices registers all endpoints to the grpc server -func registerServices(ctx context.Context, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { +func registerServices(ctx context.Context, config Config, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { // documents (common) documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler()) err := documentpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) @@ -51,7 +51,7 @@ func registerServices(ctx context.Context, grpcServer *grpc.Server, gwmux *runti } // healthcheck - healthpb.RegisterHealthCheckServiceServer(grpcServer, healthcheck.GRPCHandler()) + healthpb.RegisterHealthCheckServiceServer(grpcServer, healthcheck.GRPCHandler(config)) err = healthpb.RegisterHealthCheckServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 12ca4e692..8a50149f3 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -24,8 +24,6 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { } } c := NewConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) - c.InitializeViper() - SetConfig(c) context[bootstrap.BootstrappedConfig] = c return nil } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 0201839b7..9ded8d43e 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -6,8 +6,12 @@ import ( "crypto/sha256" "testing" + "flag" + "os" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" @@ -25,6 +29,26 @@ var ( id5 = utils.RandomSlice(32) ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &config.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + dp = DefaultProcessor(nil, nil, nil, cfg).(defaultProcessor) + flag.Parse() + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestGetSigningProofHashes(t *testing.T) { docAny := &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, @@ -232,11 +256,11 @@ func TestGetExternalCollaborators_ErrorConfig(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - currentKeyPath, _ := config.Config().GetSigningKeyPair() + currentKeyPath, _ := cfg.GetSigningKeyPair() //Wrong path - config.Config().Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") collaborators, err := GetExternalCollaborators(cd) assert.NotNil(t, err) assert.Nil(t, collaborators) - config.Config().Set("keys.signing.publicKey", currentKeyPath) + cfg.Set("keys.signing.publicKey", currentKeyPath) } diff --git a/coredocument/processor.go b/coredocument/processor.go index 3d1617f95..b346bd390 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" @@ -20,6 +19,12 @@ import ( var log = logging.Logger("coredocument") +// config defines functions to get processor details +type Config interface { + GetNetworkID() uint32 + GetIdentityID() ([]byte, error) +} + // Processor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type Processor interface { @@ -40,17 +45,19 @@ type client interface { // defaultProcessor implements Processor interface type defaultProcessor struct { - IdentityService identity.Service - P2PClient client - AnchorRepository anchors.AnchorRepository + identityService identity.Service + p2pClient client + anchorRepository anchors.AnchorRepository + config Config } // DefaultProcessor returns the default implementation of CoreDocument Processor -func DefaultProcessor(idService identity.Service, p2pClient client, repository anchors.AnchorRepository) Processor { +func DefaultProcessor(idService identity.Service, p2pClient client, repository anchors.AnchorRepository, config Config) Processor { return defaultProcessor{ - IdentityService: idService, - P2PClient: p2pClient, - AnchorRepository: repository, + identityService: idService, + p2pClient: p2pClient, + anchorRepository: repository, + config: config, } } @@ -61,7 +68,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) - id, err := dp.IdentityService.LookupIdentityForID(recipient) + id, err := dp.identityService.LookupIdentityForID(recipient) if err != nil { return centerrors.Wrap(err, "error fetching receiver identity") } @@ -73,7 +80,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp log.Infof("Sending Document to CentID [%v] with Key [%v]\n", recipient, lastB58Key) clientWithProtocol := fmt.Sprintf("/ipfs/%s", lastB58Key) - client, err := dp.P2PClient.OpenClient(clientWithProtocol) + client, err := dp.p2pClient.OpenClient(clientWithProtocol) if err != nil { return fmt.Errorf("failed to open client: %v", err) } @@ -88,7 +95,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp header := &p2ppb.CentrifugeHeader{ SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: dp.config.GetNetworkID(), } resp, err := client.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: header}) @@ -142,7 +149,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model document return fmt.Errorf("failed to validate model for signature request: %v", err) } - err = dp.P2PClient.GetSignaturesForDocument(ctx, cd) + err = dp.p2pClient.GetSignaturesForDocument(ctx, cd) if err != nil { return fmt.Errorf("failed to collect signatures from the collaborators: %v", err) } @@ -199,7 +206,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to get document root: %v", err) } - id, err := config.Config().GetIdentityID() + id, err := dp.config.GetIdentityID() if err != nil { return fmt.Errorf("failed to get self cent ID: %v", err) } @@ -226,7 +233,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) - confirmations, err := dp.AnchorRepository.CommitAnchor(anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) + confirmations, err := dp.anchorRepository.CommitAnchor(anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) if err != nil { return fmt.Errorf("failed to commit anchor: %v", err) } @@ -243,7 +250,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Mod return fmt.Errorf("failed to pack core document: %v", err) } - av := PostAnchoredValidator(dp.AnchorRepository) + av := PostAnchoredValidator(dp.anchorRepository) err = av.Validate(nil, model) if err != nil { return fmt.Errorf("post anchor validations failed: %v", err) diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 00d6cb9dd..7ae682728 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/signatures" @@ -58,8 +57,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} // failed to get id - pub, _ := config.Config().GetSigningKeyPair() - config.Config().Set("keys.signing.publicKey", "wrong path") + pub, _ := cfg.GetSigningKeyPair() + cfg.Set("keys.signing.publicKey", "wrong path") cd = New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ @@ -73,7 +72,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get keys for signing") - config.Config().Set("keys.signing.publicKey", pub) + cfg.Set("keys.signing.publicKey", pub) // failed unpack model = mockModel{} @@ -145,7 +144,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model.AssertExpectations(t) c := p2pClient{} c.On("GetSignaturesForDocument", ctx, cd).Return(fmt.Errorf("error")).Once() - dp.P2PClient = c + dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) err = dp.RequestSignatures(ctx, model) @@ -157,7 +156,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // unpack fail c = p2pClient{} c.On("GetSignaturesForDocument", ctx, cd).Return(nil).Once() - dp.P2PClient = c + dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() @@ -170,7 +169,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // success c = p2pClient{} c.On("GetSignaturesForDocument", ctx, cd).Return(nil).Once() - dp.P2PClient = c + dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(nil).Once() @@ -314,15 +313,15 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() identity.IDService = srv - oldID := config.Config().GetString("identityId") - config.Config().Set("identityId", "wrong id") + oldID := cfg.GetString("identityId") + cfg.Set("identityId", "wrong id") err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get self cent ID") - config.Config().Set("identityId", "0x0102030405060708") + cfg.Set("identityId", "0x0102030405060708") // wrong ID model = mockModel{} @@ -336,11 +335,11 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "centID invalid") - config.Config().Set("identityId", oldID) + cfg.Set("identityId", oldID) // missing eth keys - oldPth := config.Config().Get("keys.ethauth.publicKey") - config.Config().Set("keys.ethauth.publicKey", "wrong path") + oldPth := cfg.Get("keys.ethauth.publicKey") + cfg.Set("keys.ethauth.publicKey", "wrong path") model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() @@ -352,7 +351,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get eth keys") - config.Config().Set("keys.ethauth.publicKey", oldPth) + cfg.Set("keys.ethauth.publicKey", oldPth) // failed anchor commit model = mockModel{} @@ -362,7 +361,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { identity.IDService = srv repo := mockRepo{} repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error")).Once() - dp.AnchorRepository = repo + dp.anchorRepository = repo err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) @@ -381,7 +380,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { ch := make(chan *anchors.WatchCommit, 1) ch <- new(anchors.WatchCommit) repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ch, nil).Once() - dp.AnchorRepository = repo + dp.anchorRepository = repo err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) @@ -443,7 +442,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Nil(t, err) repo := mockRepo{} repo.On("GetDocumentRootOf", mock.Anything).Return(docRoot, nil).Once() - dp.AnchorRepository = repo + dp.anchorRepository = repo err = dp.SendDocument(ctx, model) model.AssertExpectations(t) srv.AssertExpectations(t) diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index c8404d0c8..acb56aeee 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -3,17 +3,13 @@ package coredocument import ( - "flag" "fmt" "math/big" - "os" "testing" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/signatures" @@ -24,21 +20,6 @@ import ( "github.com/stretchr/testify/mock" ) -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &config.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - flag.Parse() - config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - func TestUpdateVersionValidator(t *testing.T) { uvv := UpdateVersionValidator() diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index f5dd211e0..70789ce42 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -17,12 +18,17 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + return errors.New("config hasn't been initialized") + } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } // register service - srv := DefaultService(getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(cfg), anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 8abe79de9..0257cb04e 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -58,8 +59,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: ¬ification.WebhookSender{}, anchorRepository: anchorRepository} +func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository} } // CreateProofs creates proofs for the latest version document given the fields diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 046f655ba..68f53debb 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -44,12 +44,12 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil) + srv := DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() Service { - return DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) } func createMockDocument() (*Invoice, error) { diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 4bb36d372..076843101 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -17,12 +18,17 @@ type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + return errors.New("config hasn't been initialized") + } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("could not initialize purchase order repository") } // register service - srv := DefaultService(getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(), anchors.GetAnchorRepository()), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(cfg), anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index c70acbb40..a277b5f04 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" @@ -58,8 +59,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: ¬ification.WebhookSender{}, anchorRepository: anchorRepository} +func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository} } // DeriveFromCoreDocument takes a core document and returns a purchase order diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 9ff66e7b5..4db400503 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -42,7 +42,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func getServiceWithMockedLayers() Service { - return DefaultService(getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) } func TestService_Update(t *testing.T) { diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index bca730103..32880c21d 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -22,14 +22,18 @@ import ( "github.com/stretchr/testify/mock" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - config.Config().Set("ethereum.txPoolAccessEnabled", false) - config.Config().Set("ethereum.intervalRetry", time.Millisecond*100) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg.Set("ethereum.txPoolAccessEnabled", false) + cfg.Set("ethereum.intervalRetry", time.Millisecond*100) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -61,7 +65,7 @@ func TestInitTransactionWithRetries(t *testing.T) { accounts: make(map[string]*bind.TransactOpts), accMu: sync.Mutex{}, txMu: sync.Mutex{}, - config: config.Config(), + config: cfg, } SetClient(gc) @@ -76,7 +80,7 @@ func TestInitTransactionWithRetries(t *testing.T) { tx, err = gc.SubmitTransactionWithRetries(mockRequest.RegisterTransaction, &bind.TransactOpts{}, "otherError", "var2") assert.EqualError(t, err, "Some other error", "Should error out") - mockRetries := testingutils.MockConfigOption("ethereum.maxRetries", 10) + mockRetries := testingutils.MockConfigOption(cfg, "ethereum.maxRetries", 10) defer mockRetries() mockRequest.count = 0 diff --git a/healthcheck/handler.go b/healthcheck/handler.go index 268bc53e5..f7364508e 100644 --- a/healthcheck/handler.go +++ b/healthcheck/handler.go @@ -3,24 +3,29 @@ package healthcheck import ( "context" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/health" "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/empty" ) +type Config interface { + GetNetworkString() string +} + // handler is the grpc handler that implements healthpb.HealthCheckServiceServer -type handler struct{} +type handler struct { + config Config +} // GRPCHandler returns the grpc implementation instance of healthpb.HealthCheckServiceServer -func GRPCHandler() healthpb.HealthCheckServiceServer { - return handler{} +func GRPCHandler(config Config) healthpb.HealthCheckServiceServer { + return handler{config} } // Ping returns the network node is connected to and version of the node -func (handler) Ping(context.Context, *empty.Empty) (pong *healthpb.Pong, err error) { +func (h handler) Ping(context.Context, *empty.Empty) (pong *healthpb.Pong, err error) { return &healthpb.Pong{ Version: version.GetVersion().String(), - Network: config.Config().GetNetworkString(), + Network: h.config.GetNetworkString(), }, nil } diff --git a/healthcheck/handler_test.go b/healthcheck/handler_test.go index 10c87969c..fb8c9f559 100644 --- a/healthcheck/handler_test.go +++ b/healthcheck/handler_test.go @@ -4,7 +4,6 @@ package healthcheck import ( "context" - "flag" "os" "testing" @@ -15,23 +14,25 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } - - bootstrap.RunTestBootstrappers(ibootstappers, nil) - flag.Parse() + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) } func TestHandler_Ping(t *testing.T) { - h := GRPCHandler() + h := GRPCHandler(cfg) pong, err := h.Ping(context.Background(), &empty.Empty{}) assert.Nil(t, err) assert.NotNil(t, pong) assert.Equal(t, pong.Version, version.GetVersion().String()) - assert.Equal(t, pong.Network, config.Config().GetNetworkString()) + assert.Equal(t, pong.Network, cfg.GetNetworkString()) } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index c775df3ca..c387db516 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/go-centrifuge/api" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/p2p" ) @@ -51,21 +50,5 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { } func defaultServerList(cfg *config.Configuration) ([]Server, error) { - publicKey, privateKey, err := ed25519.GetSigningKeyPairFromConfig() - if err != nil { - return nil, fmt.Errorf("failed to get keys: %v", err) - } - - return []Server{ - api.NewCentAPIServer( - cfg.GetServerAddress(), - cfg.GetServerPort(), - cfg.GetNetworkString(), - ), - p2p.NewCentP2PServer( - cfg.GetP2PPort(), - cfg.GetBootstrapPeers(), - publicKey, privateKey, - ), - }, nil + return []Server{api.NewCentAPIServer(cfg), p2p.NewCentP2PServer(cfg)}, nil } diff --git a/notification/notification.go b/notification/notification.go index 05d182d65..16588b681 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -2,7 +2,6 @@ package notification import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/jsonpb" logging "github.com/ipfs/go-log" @@ -20,14 +19,24 @@ const ( Success Status = 1 ) +type Config interface { + GetReceiveEventNotificationEndpoint() string +} + type Sender interface { Send(notification *notificationpb.NotificationMessage) (Status, error) } -type WebhookSender struct{} +func NewWebhookSender(config Config) *WebhookSender { + return &WebhookSender{config} +} + +type WebhookSender struct { + config Config +} func (wh *WebhookSender) Send(notification *notificationpb.NotificationMessage) (Status, error) { - url := config.Config().GetReceiveEventNotificationEndpoint() + url := wh.config.GetReceiveEventNotificationEndpoint() if url == "" { log.Warningf("Webhook URL not defined, manually fetch received document") return Success, nil diff --git a/p2p/client.go b/p2p/client.go index f468f4877..82654066f 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/signatures" @@ -24,11 +23,13 @@ type Client interface { GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error } -func NewP2PClient() Client { - return &defaultClient{} +func NewP2PClient(config Config) Client { + return &defaultClient{config} } -type defaultClient struct{} +type defaultClient struct { + config Config +} // Opens a client connection with libp2p func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error) { @@ -62,7 +63,7 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error // make a new stream from host B to host A with timeout // Retrial is handled internally, connection request will be cancelled by the connection timeout context - ctx, _ := context.WithTimeout(context.Background(), config.Config().GetP2PConnectionTimeout()) + ctx, _ := context.WithTimeout(context.Background(), d.config.GetP2PConnectionTimeout()) g, err := grpcProtoInstance.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) @@ -72,14 +73,14 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error } // getSignatureForDocument requests the target node to sign the document -func getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { - senderId, err := config.Config().GetIdentityID() +func (d *defaultClient) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { + senderId, err := d.config.GetIdentityID() if err != nil { return nil, err } header := p2ppb.CentrifugeHeader{ - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: d.config.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), SenderCentrifugeId: senderId, } @@ -121,8 +122,8 @@ type signatureResponseWrap struct { err error } -func getSignatureAsync(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { - resp, err := getSignatureForDocument(ctx, doc, client, receiverCentId) +func (d *defaultClient) getSignatureAsync(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { + resp, err := d.getSignatureForDocument(ctx, doc, client, receiverCentId) out <- signatureResponseWrap{ resp: resp, err: err, @@ -160,7 +161,7 @@ func (d *defaultClient) GetSignaturesForDocument(ctx context.Context, doc *cored // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - go getSignatureAsync(ctx, *doc, client, collaboratorID, in) + go d.getSignatureAsync(ctx, *doc, client, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/p2p/client_test.go b/p2p/client_test.go index 792a1ca7b..c3a9d0607 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -5,16 +5,11 @@ package p2p import ( "context" "fmt" - "os" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" @@ -23,18 +18,6 @@ import ( "github.com/stretchr/testify/mock" ) -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &storage.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - func TestGetSignatureForDocument_fail_connect(t *testing.T) { client := &testingcommons.P2PMockClient{} coreDoc := testingcoredocument.GenerateCoreDocument() @@ -43,7 +26,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("signature failed")).Once() - resp, err := getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -59,7 +42,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(resp, nil).Once() - resp, err = getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err = defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -83,7 +66,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(sigResp, nil).Once() - resp, err := getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Nil(t, resp, "must be nil") diff --git a/p2p/handler.go b/p2p/handler.go index 3bec3544a..f890a1ab0 100644 --- a/p2p/handler.go +++ b/p2p/handler.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/notification" "github.com/centrifuge/go-centrifuge/version" ) @@ -38,9 +37,7 @@ func getServiceAndModel(cd *coredocumentpb.CoreDocument) (documents.Service, doc } // Handler implements the grpc interface -type Handler struct { - Notifier notification.Sender -} +type Handler struct{} // RequestDocumentSignature signs the received document and returns the signature of the signingRoot // Document signing root will be recalculated and verified diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 94dd4836a..7acc2fd80 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -18,7 +18,6 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" - "github.com/centrifuge/go-centrifuge/notification" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -31,7 +30,7 @@ import ( "golang.org/x/crypto/ed25519" ) -var handler = p2p.Handler{Notifier: ¬ification.WebhookSender{}} +var handler = p2p.Handler{} func TestMain(m *testing.M) { cc.TestFunctionalEthereumBootstrap() diff --git a/p2p/handler_test.go b/p2p/handler_test.go index fd5928417..55d9dda2a 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -8,15 +8,18 @@ import ( "strconv" "testing" + "os" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/notification" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/any" @@ -25,17 +28,27 @@ import ( ) var ( - handler = Handler{Notifier: &MockWebhookSender{}} + handler = Handler{} ) -// MockWebhookSender implements notification.Sender -type MockWebhookSender struct{} - -func (wh *MockWebhookSender) Send(notification *notificationpb.NotificationMessage) (status notification.Status, err error) { - return -} - var coreDoc = testingcoredocument.GenerateCoreDocument() +var ctx = map[string]interface{}{} +var cfg *config.Configuration +var defaultTestClient defaultClient + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + defaultTestClient = defaultClient{cfg} + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ diff --git a/p2p/server.go b/p2p/server.go index 1fc989007..5fb6ad8a2 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -9,8 +9,7 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/notification" + cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-ipfs-addr" @@ -24,32 +23,27 @@ import ( ma "github.com/multiformats/go-multiaddr" mh "github.com/multiformats/go-multihash" "github.com/paralin/go-libp2p-grpc" - "golang.org/x/crypto/ed25519" ) var log = logging.Logger("cent-p2p-server") var HostInstance host.Host var GRPCProtoInstance p2pgrpc.GRPCProtocol +type Config interface { + GetP2PExternalIP() string + GetP2PPort() int + GetBootstrapPeers() []string + GetP2PConnectionTimeout() time.Duration + GetNetworkID() uint32 + GetIdentityID() ([]byte, error) +} + type CentP2PServer struct { - Port int - BootstrapPeers []string - PublicKey ed25519.PublicKey - PrivateKey ed25519.PrivateKey + config Config } -func NewCentP2PServer( - port int, - bootstrapPeers []string, - publicKey ed25519.PublicKey, - privateKey ed25519.PrivateKey, -) *CentP2PServer { - return &CentP2PServer{ - Port: port, - BootstrapPeers: bootstrapPeers, - PublicKey: publicKey, - PrivateKey: privateKey, - } +func NewCentP2PServer(config Config) *CentP2PServer { + return &CentP2PServer{config} } func (*CentP2PServer) Name() string { @@ -59,13 +53,13 @@ func (*CentP2PServer) Name() string { func (c *CentP2PServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { defer wg.Done() - if c.Port == 0 { + if c.config.GetP2PPort() == 0 { startupErr <- errors.New("please provide a port to bind on") return } // Make a host that listens on the given multiaddress - hostInstance, err := c.makeBasicHost(c.Port) + hostInstance, err := c.makeBasicHost(c.config.GetP2PPort()) if err != nil { startupErr <- err return @@ -75,7 +69,7 @@ func (c *CentP2PServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr grpcProto := p2pgrpc.NewGRPCProtocol(context.Background(), hostInstance) GRPCProtoInstance = *grpcProto - p2ppb.RegisterP2PServiceServer(grpcProto.GetGRPCServer(), &Handler{Notifier: ¬ification.WebhookSender{}}) + p2ppb.RegisterP2PServiceServer(grpcProto.GetGRPCServer(), &Handler{}) errOut := make(chan error) go func(proto *p2pgrpc.GRPCProtocol, errOut chan<- error) { errOut <- proto.Serve() @@ -106,8 +100,8 @@ func (c *CentP2PServer) runDHT(ctx context.Context, h host.Host) error { //dhtClient := dht.NewDHTClient(ctx, h, rdStore) // Just run it as a client, will not respond to discovery requests dhtClient := dht.NewDHT(ctx, h, ds.NewMapDatastore()) // Run it as a Bootstrap Node - log.Infof("Bootstrapping %s\n", c.BootstrapPeers) - for _, addr := range c.BootstrapPeers { + log.Infof("Bootstrapping %s\n", c.config.GetBootstrapPeers()) + for _, addr := range c.config.GetBootstrapPeers() { iaddr, _ := ipfsaddr.ParseString(addr) pinfo, _ := pstore.InfoFromP2pAddr(iaddr.Multiaddr()) @@ -189,7 +183,7 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { return nil, err } - externalIP := config.Config().GetP2PExternalIP() + externalIP := c.config.GetP2PExternalIP() var extMultiAddr ma.Multiaddr if externalIP == "" { log.Warning("External IP not defined, Peers might not be able to resolve this node if behind NAT\n") @@ -231,9 +225,14 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { func (c *CentP2PServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { // Create the signing key for the host + publicKey, privateKey, err := cented25519.GetSigningKeyPairFromConfig() + if err != nil { + return nil, nil, fmt.Errorf("failed to get keys: %v", err) + } + var key []byte - key = append(key, c.PrivateKey...) - key = append(key, c.PublicKey...) + key = append(key, privateKey...) + key = append(key, publicKey...) priv, err = crypto.UnmarshalEd25519PrivateKey(key) if err != nil { diff --git a/p2p/server_test.go b/p2p/server_test.go index 3a42dcee7..2497bdf6f 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -9,11 +9,8 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/config" - cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" - "golang.org/x/crypto/ed25519" ) func TestCentP2PServer_Start(t *testing.T) { @@ -21,9 +18,10 @@ func TestCentP2PServer_Start(t *testing.T) { } func TestCentP2PServer_StartContextCancel(t *testing.T) { - priv, pub, err := getKeys() - assert.Nil(t, err) - cp2p := NewCentP2PServer(38203, []string{}, pub, priv) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("p2p.port", 38203) + cp2p := NewCentP2PServer(cfg) ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -36,16 +34,17 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { } func TestCentP2PServer_StartListenError(t *testing.T) { + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") // cause an error by using an invalid port - priv, pub, err := getKeys() - assert.Nil(t, err) - cp2p := NewCentP2PServer(100000000, []string{}, pub, priv) + cfg.Set("p2p.port", 100000000) + cp2p := NewCentP2PServer(cfg) ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) go cp2p.Start(ctx, &wg, startErr) - err = <-startErr + err := <-startErr wg.Wait() assert.NotNil(t, err, "Error should be not nil") assert.Equal(t, "failed to parse tcp: 100000000 failed to parse port addr: greater than 65536", err.Error()) @@ -53,9 +52,10 @@ func TestCentP2PServer_StartListenError(t *testing.T) { func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { listenPort := 38202 - priv, pub, err := getKeys() - assert.Nil(t, err) - cp2p := NewCentP2PServer(listenPort, []string{}, pub, priv) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("p2p.port", listenPort) + cp2p := NewCentP2PServer(cfg) h, err := cp2p.makeBasicHost(listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -64,10 +64,11 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 - config.Config().Set("p2p.externalIP", externalIP) - priv, pub, err := getKeys() - assert.Nil(t, err) - cp2p := NewCentP2PServer(listenPort, []string{}, pub, priv) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("p2p.port", listenPort) + cfg.Set("p2p.externalIP", externalIP) + cp2p := NewCentP2PServer(cfg) h, err := cp2p.makeBasicHost(listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -80,18 +81,12 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 - config.Config().Set("p2p.externalIP", externalIP) - priv, pub, err := getKeys() - assert.Nil(t, err) - cp2p := NewCentP2PServer(listenPort, []string{}, pub, priv) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("p2p.port", listenPort) + cfg.Set("p2p.externalIP", externalIP) + cp2p := NewCentP2PServer(cfg) h, err := cp2p.makeBasicHost(listenPort) assert.NotNil(t, err) assert.Nil(t, h) } - -func getKeys() (ed25519.PrivateKey, ed25519.PublicKey, error) { - pub, err := cented25519.GetPublicSigningKey("../build/resources/signingKey.pub.pem") - pri, err := cented25519.GetPrivateSigningKey("../build/resources/signingKey.key.pem") - return pri, pub, err - -} diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index 4c0e873a7..88dc72caf 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -1,6 +1,11 @@ package queue -import "errors" +import ( + "errors" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" +) const BootstrappedQueuedTasks string = "BootstrappedQueuedTasks" @@ -8,10 +13,14 @@ type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + return errors.New("config hasn't been initialized") + } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) // to see how BootstrappedQueuedTasks get populated check usages of InstallQueuedTask if queuedTasks, ok := context[BootstrappedQueuedTasks]; ok { if queuedTasksTyped, ok := queuedTasks.([]QueuedTask); ok { - InitQueue(queuedTasksTyped) + InitQueue(queuedTasksTyped, cfg.GetNumWorkers(), cfg.GetWorkerWaitTimeMS()) return nil } } diff --git a/queue/queue.go b/queue/queue.go index c282f2c8d..cd950b62c 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -3,7 +3,6 @@ package queue import ( "sync" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/gocelery" ) @@ -16,14 +15,14 @@ type QueuedTask interface { Init() error } -func InitQueue(tasks []QueuedTask) { +func InitQueue(tasks []QueuedTask, numWorkers, workerWaitTime int) { queueInit.Do(func() { var err error Queue, err = gocelery.NewCeleryClient( gocelery.NewInMemoryBroker(), gocelery.NewInMemoryBackend(), - config.Config().GetNumWorkers(), - config.Config().GetWorkerWaitTimeMS(), + numWorkers, + workerWaitTime, ) if err != nil { panic("Could not initialize the queue") diff --git a/testingutils/utils.go b/testingutils/utils.go index a67554fb2..d7a293906 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -6,11 +6,11 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) -func MockConfigOption(key string, value interface{}) func() { - mockedValue := config.Config().Get(key) - config.Config().Set(key, value) +func MockConfigOption(cfg *config.Configuration, key string, value interface{}) func() { + mockedValue := cfg.Get(key) + cfg.Set(key, value) return func() { - config.Config().Set(key, mockedValue) + cfg.Set(key, mockedValue) } } From fb2bf8a2358bdd178b8e34b715ab60172fbab40b Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 13 Nov 2018 12:29:29 +0100 Subject: [PATCH 022/220] nft: added format checks for collaborator proofField (#442) * added collaborators field check * improved regex performance --- nft/ethereum_payment_obligation.go | 31 +++++++++++++++++++++++-- nft/ethereum_payment_obligation_test.go | 27 +++++++++++++++++++-- nft/handler.go | 21 +++++++++++++++++ nft/handler_test.go | 14 +++++++++++ 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 6ecc3d768..093d4407d 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -6,6 +6,8 @@ import ( "fmt" "math/big" + "regexp" + "github.com/centrifuge/gocelery" "github.com/centrifuge/go-centrifuge/anchors" @@ -28,6 +30,8 @@ var po *ethereumPaymentObligation const amountOfProofs = 5 +var regexCollaborators, _ = regexp.Compile("collaborators\\[[0-9]+\\]") + func setPaymentObligation(s *ethereumPaymentObligation) { po = s } @@ -100,8 +104,12 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registry return nil, nil } - //last proofField should be the collaborator - requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash, proofFields[len(proofFields)-1]) + collaboratorField, err := getCollaboratorProofField(proofFields) + if err != nil { + return nil, err + } + + requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash, collaboratorField) if err != nil { return nil, err } @@ -287,3 +295,22 @@ func getDocumentService(documentType string) (documents.Service, error) { } return docService, nil } + +// getCollaborator returns the needed collaboratorField for a PaymentObligation NFT +// In the current contract implementation the proofField for collaborator is a separated parameter +// pattern: 'collaborators' + '[i]' +// examples: 'collaborators[0]','collaborators[1]', etc +func getCollaboratorProofField(proofFields []string) (string, error) { + + for _, proofField := range proofFields { + + match := regexCollaborators.MatchString(proofField) + + if match { + return proofField, nil + } + } + + return "", fmt.Errorf("proof_fields should contain a collaborator. (example: 'collaborators[0]')") + +} diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 7e61efb2c..a13f3e415 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -162,7 +162,7 @@ func TestPaymentObligationService(t *testing.T) { proof := getDummyProof(coreDoc) docServiceMock := testingdocuments.MockService{} docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocument: coreDoc}, nil) - docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"somefield"}).Return(proof, nil) + docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIDService{} idServiceMock.On("GetIdentityAddress", centID).Return(address, nil) @@ -178,7 +178,7 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetIdentityID").Return(centIDByte, nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock }, - &nftpb.NFTMintRequest{Identifier: "0x1212", Type: "happypath", ProofFields: []string{"somefield"}}, + &nftpb.NFTMintRequest{Identifier: "0x1212", Type: "happypath", ProofFields: []string{"collaborators[0]"}}, nil, "", }, @@ -248,3 +248,26 @@ func decodeHex(hex string) []byte { h, _ := hexutil.Decode(hex) return h } + +func TestGetCollaboratorProofField(t *testing.T) { + + proofField, err := getCollaboratorProofField([]string{"fuu", "foo", "collaborators[0]"}) + assert.Nil(t, err, "getCollaboratorProofField should not throw an error") + assert.Equal(t, "collaborators[0]", proofField, "proofField should contain the correct field") + + proofField, err = getCollaboratorProofField([]string{"fuu", "foo"}) + assert.Error(t, err, "getCollaboratorProofField should throw an error") + assert.Equal(t, "", proofField, "proofField should be empty") + + proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators"}) + assert.Error(t, err, "getCollaboratorProofField should throw an error") + assert.Equal(t, "", proofField, "proofField should be empty") + + proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators[a]"}) + assert.Error(t, err, "getCollaboratorProofField should throw an error") + assert.Equal(t, "", proofField, "proofField should be empty") + + proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators[12345678]"}) + assert.Nil(t, err, "getCollaboratorProofField should not throw an error") + assert.Equal(t, "collaborators[12345678]", proofField, "proofField should contain the correct field") +} diff --git a/nft/handler.go b/nft/handler.go index 2d8cdb4dc..c9d840dcb 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -3,6 +3,8 @@ package nft import ( "context" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" @@ -24,6 +26,11 @@ func GRPCHandler() nftpb.NFTServiceServer { // MintNFT will be called from the client API to mint an NFT func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { apiLog.Infof("Received request to Mint an NFT for document %s type %s with proof fields %s", request.Identifier, request.Type, request.ProofFields) + + err := g.validateParameters(request) + if err != nil { + return nil, err + } identifier, err := hexutil.Decode(request.Identifier) if err != nil { return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) @@ -36,3 +43,17 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ watchToken := <-confirmation return &nftpb.NFTMintResponse{TokenId: watchToken.TokenID.String()}, watchToken.Err } + +func (g grpcHandler) validateParameters(request *nftpb.NFTMintRequest) error { + + if !common.IsHexAddress(request.RegistryAddress) { + return centerrors.New(code.Unknown, "RegistryAddress is not a valid Ethereum address") + } + + if !common.IsHexAddress(request.DepositAddress) { + return centerrors.New(code.Unknown, "DepositAddress is not a valid Ethereum address") + } + + return nil + +} diff --git a/nft/handler_test.go b/nft/handler_test.go index 0100315d7..2d9b5e3ec 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -69,6 +69,20 @@ func TestNFTMint_ServiceError(t *testing.T) { assert.NotNil(t, err) } +func TestNFTMint_InvalidAddresses(t *testing.T) { + nftMintRequest := getTestSetupData() + nftMintRequest.RegistryAddress = "0x1234" + handler := grpcHandler{&MockPaymentObligationService{}} + _, err := handler.MintNFT(context.Background(), nftMintRequest) + assert.Error(t, err, "invalid registry address should throw an error") + + nftMintRequest = getTestSetupData() + nftMintRequest.DepositAddress = "abc" + handler = grpcHandler{&MockPaymentObligationService{}} + _, err = handler.MintNFT(context.Background(), nftMintRequest) + assert.Error(t, err, "invalid deposit address should throw an error") +} + func getTestSetupData() *nftpb.NFTMintRequest { return &nftpb.NFTMintRequest{ Identifier: "0x12121212", From b58fbc9f956c86493abe84495426a622edeea8ff Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 13 Nov 2018 15:03:12 +0100 Subject: [PATCH 023/220] NFT: using passed registryAddress for dynamic contract binding (#443) * added generic registry address support --- nft/bootstrapper.go | 16 +----- nft/ethereum_payment_obligation.go | 53 +++++++++++++++---- nft/ethereum_payment_obligation_test.go | 20 ++++++- nft/handler.go | 4 +- nft/handler_test.go | 1 + nft/minting_confirmation_task.go | 61 ++++++++++++++++------ nft/payment_obligation_integration_test.go | 4 +- 7 files changed, 112 insertions(+), 47 deletions(-) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 128acf758..dd9d79909 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" - "github.com/ethereum/go-ethereum/common" ) type Bootstrapper struct { @@ -25,17 +24,6 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.New("ethereum client hasn't been initialized") } - contract, err := getPaymentObligationContract(cfg.GetContractAddress("paymentObligation")) - if err != nil { - return err - } - - setPaymentObligation(NewEthereumPaymentObligation(contract, identity.IDService, ethereum.GetClient(), cfg, setupMintListener)) - return queue.InstallQueuedTask(context, - newMintingConfirmationTask(contract, ethereum.DefaultWaitForTransactionMiningContext)) -} - -func getPaymentObligationContract(obligationAddress common.Address) (*EthereumPaymentObligationContract, error) { - client := ethereum.GetClient() - return NewEthereumPaymentObligationContract(obligationAddress, client.GetEthClient()) + setPaymentObligation(NewEthereumPaymentObligation(identity.IDService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) + return queue.InstallQueuedTask(context, newMintingConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext)) } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 093d4407d..19853ef7d 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -44,6 +44,7 @@ func GetPaymentObligation() *ethereumPaymentObligation { type Config interface { GetIdentityID() ([]byte, error) GetEthereumDefaultAccountName() string + GetContractAddress(address string) common.Address } // ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out @@ -55,20 +56,24 @@ type ethereumPaymentObligationContract interface { // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum type ethereumPaymentObligation struct { - paymentObligation ethereumPaymentObligationContract identityService identity.Service ethClient ethereum.Client config Config - setupMintListener func(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error) + setupMintListener func(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) + bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func NewEthereumPaymentObligation(paymentObligation ethereumPaymentObligationContract, identityService identity.Service, ethClient ethereum.Client, config Config, setupMintListener func(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error)) *ethereumPaymentObligation { - return ðereumPaymentObligation{paymentObligation: paymentObligation, identityService: identityService, ethClient: ethClient, config: config, setupMintListener: setupMintListener} +func NewEthereumPaymentObligation(identityService identity.Service, ethClient ethereum.Client, config Config, + setupMintListener func(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { + return ðereumPaymentObligation{identityService: identityService, + ethClient: ethClient, + config: config, + setupMintListener: setupMintListener, + bindContract: bindContract} } -// MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { +func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, docType string, proofFields []string) (*MintRequest, error) { docService, err := getDocumentService(docType) if err != nil { return nil, err @@ -114,17 +119,38 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registry return nil, err } + return requestData, nil + +} + +// MintNFT mints an NFT +func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { + + requestData, err := s.prepareMintRequest(documentID, docType, proofFields) + opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { return nil, err } - watch, err := s.setupMintListener(requestData.TokenID) + var contract *EthereumPaymentObligationContract + if registryAddress == "" { + defaultRegistry := s.config.GetContractAddress("paymentObligation") + contract, err = s.bindContract(defaultRegistry, s.ethClient) + registryAddress = defaultRegistry.String() + } else { + contract, err = s.bindContract(common.HexToAddress(registryAddress), s.ethClient) + } + if err != nil { + return nil, err + } + + watch, err := s.setupMintListener(requestData.TokenID, registryAddress) if err != nil { return nil, err } - err = s.sendMintTransaction(s.paymentObligation, opts, requestData) + err = s.sendMintTransaction(contract, opts, requestData) if err != nil { return nil, err } @@ -134,7 +160,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registry // setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code // about successful minting of an NFt -func setupMintListener(tokenID *big.Int) (confirmations chan *WatchTokenMinted, err error) { +func setupMintListener(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { confirmations = make(chan *WatchTokenMinted) conn := ethereum.GetClient() @@ -143,8 +169,9 @@ func setupMintListener(tokenID *big.Int) (confirmations chan *WatchTokenMinted, return nil, err } asyncRes, err := queue.Queue.DelayKwargs(mintingConfirmationTaskName, map[string]interface{}{ - tokenIDParam: hex.EncodeToString(tokenID.Bytes()), - blockHeight: h.Number.Uint64(), + tokenIDParam: hex.EncodeToString(tokenID.Bytes()), + blockHeightParam: h.Number.Uint64(), + registryAddressParam: registryAddress, }) if err != nil { return nil, err @@ -314,3 +341,7 @@ func getCollaboratorProofField(proofFields []string) (string, error) { return "", fmt.Errorf("proof_fields should contain a collaborator. (example: 'collaborators[0]')") } + +func bindContract(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + return NewEthereumPaymentObligationContract(address, client.GetEthClient()) +} diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index a13f3e415..c0d604586 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,6 +7,10 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/ethereum" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -143,6 +147,16 @@ func (m *MockConfig) GetEthereumDefaultAccountName() string { return args.Get(0).(string) } +func (m *MockConfig) Config() *config.Configuration { + args := m.Called() + return args.Get(0).(*config.Configuration) +} + +func (m *MockConfig) GetContractAddress(address string) common.Address { + args := m.Called() + return args.Get(0).(common.Address) +} + func TestPaymentObligationService(t *testing.T) { tests := []struct { name string @@ -176,6 +190,8 @@ func TestPaymentObligationService(t *testing.T) { configMock := MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") configMock.On("GetIdentityID").Return(centIDByte, nil) + configMock.On("GetContractAddress").Return(common.HexToAddress("0xd0dbc72ae5e71382b3cc9cfdc53f6952a085db6d")) + return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock }, &nftpb.NFTMintRequest{Identifier: "0x1212", Type: "happypath", ProofFields: []string{"collaborators[0]"}}, @@ -190,8 +206,10 @@ func TestPaymentObligationService(t *testing.T) { // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton documents.GetRegistryInstance().Register(test.name, &docService) confirmations := make(chan *WatchTokenMinted) - service := NewEthereumPaymentObligation(paymentOb, &idService, ðClient, &config, func(tokenID *big.Int) (chan *WatchTokenMinted, error) { + service := NewEthereumPaymentObligation(&idService, ðClient, &config, func(tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { return confirmations, nil + }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + return &EthereumPaymentObligationContract{}, nil }) _, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.Type, test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { diff --git a/nft/handler.go b/nft/handler.go index c9d840dcb..371670875 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -27,7 +27,7 @@ func GRPCHandler() nftpb.NFTServiceServer { func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { apiLog.Infof("Received request to Mint an NFT for document %s type %s with proof fields %s", request.Identifier, request.Type, request.ProofFields) - err := g.validateParameters(request) + err := validateParameters(request) if err != nil { return nil, err } @@ -44,7 +44,7 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ return &nftpb.NFTMintResponse{TokenId: watchToken.TokenID.String()}, watchToken.Err } -func (g grpcHandler) validateParameters(request *nftpb.NFTMintRequest) error { +func validateParameters(request *nftpb.NFTMintRequest) error { if !common.IsHexAddress(request.RegistryAddress) { return centerrors.New(code.Unknown, "RegistryAddress is not a valid Ethereum address") diff --git a/nft/handler_test.go b/nft/handler_test.go index 2d9b5e3ec..74e760d1a 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -28,6 +28,7 @@ func TestNFTMint_success(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &MockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) + confirmations := make(chan *WatchTokenMinted) mockService. On("MintNFT", docID, nftMintRequest.Type, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index e7cb615be..cf0d41126 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -6,6 +6,10 @@ import ( "fmt" "time" + "github.com/centrifuge/go-centrifuge/ethereum" + + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/gocelery" "github.com/centrifuge/go-centrifuge/centerrors" @@ -17,7 +21,8 @@ import ( const ( mintingConfirmationTaskName string = "MintingConfirmationTaskName" tokenIDParam string = "TokenIDParam" - blockHeight string = "BlockHeight" + blockHeightParam string = "BlockHeightParam" + registryAddressParam string = "RegistryAddressParam" ) // paymentObligationMintedFilterer filters the approved NFTs @@ -29,20 +34,21 @@ type paymentObligationMintedFilterer interface { // mintingConfirmationTask confirms the minting of a payment obligation NFT type mintingConfirmationTask struct { - TokenID string - BlockHeight uint64 - EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) - EthContext context.Context - PaymentObligationMintedFilterer paymentObligationMintedFilterer + //task parameter + TokenID string + BlockHeight uint64 + RegistryAddress string + + //state + EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) } func newMintingConfirmationTask( - nftApprovedFilterer paymentObligationMintedFilterer, ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), ) *mintingConfirmationTask { return &mintingConfirmationTask{ - PaymentObligationMintedFilterer: nftApprovedFilterer, - EthContextInitializer: ethContextInitializer, + + EthContextInitializer: ethContextInitializer, } } @@ -62,14 +68,14 @@ func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &mintingConfirmationTask{ nftc.TokenID, nftc.BlockHeight, + nftc.RegistryAddress, nftc.EthContextInitializer, - nftc.EthContext, - nftc.PaymentObligationMintedFilterer, }, nil } // ParseKwargs - define a method to parse CentID func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + // parse TokenID tokenID, ok := kwargs[tokenIDParam] if !ok { return fmt.Errorf("undefined kwarg " + tokenIDParam) @@ -79,15 +85,28 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) return fmt.Errorf("malformed kwarg [%s]", tokenIDParam) } + // parse BlockHeight nftc.BlockHeight, err = parseBlockHeight(kwargs) if err != nil { return err } + + //parse RegistryAddress + registryAddress, ok := kwargs[registryAddressParam] + if !ok { + return fmt.Errorf("undefined kwarg " + registryAddressParam) + } + + nftc.RegistryAddress, ok = registryAddress.(string) + if !ok { + return fmt.Errorf("malformed kwarg [%s]", registryAddressParam) + } + return nil } func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[blockHeight]; ok { + if bhi, ok := valMap[blockHeightParam]; ok { bhf, ok := bhi.(float64) if ok { return uint64(bhf), nil @@ -99,17 +118,25 @@ func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { // RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.TokenID) - if nftc.EthContext == nil { - nftc.EthContext, _ = nftc.EthContextInitializer() - } + + ethContext, _ := nftc.EthContextInitializer() fOpts := &bind.FilterOpts{ - Context: nftc.EthContext, + Context: ethContext, Start: nftc.BlockHeight, } + var filter paymentObligationMintedFilterer + var err error + + filter, err = bindContract(common.HexToAddress(nftc.RegistryAddress), ethereum.GetClient()) + + if err != nil { + return nil, err + } + for { - iter, err := nftc.PaymentObligationMintedFilterer.FilterPaymentObligationMinted( + iter, err := filter.FilterPaymentObligationMinted( fOpts, ) if err != nil { diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index cfe76495b..f3a0f5f63 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -76,8 +76,8 @@ func TestPaymentObligationService_mint(t *testing.T) { confirmations, err := nft.GetPaymentObligation().MintNFT( ID, documenttypes.InvoiceDataTypeUrl, - "doesntmatter", - "doesntmatter", + config.Config().GetContractAddress("paymentObligation").String(), + "0xf72855759a39fb75fc7341139f5d7a3974d4da08", []string{"gross_amount", "currency", "due_date", "document_type", "collaborators[0]"}, ) assert.Nil(t, err, "should not error out when minting an invoice") From 04802f1828a34ec0fd4e0d0ab2cfb0bef9f20f94 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 14 Nov 2018 11:24:30 +0100 Subject: [PATCH 024/220] remove global dependencies for p2p layer (#446) * remove global dependencies for p2p layer * add p2p boostrap * remove test checks * use ctx from args * fix tests * check for startup errors * better tests * remove debug point * fix tests --- api/bootstrapper.go | 24 +++++ api/bootstrapper_test.go | 30 +++++++ api/server.go | 19 ++-- api/server_test.go | 7 +- api/test_bootstrapper.go | 11 +++ bootstrap/bootstrapper.go | 3 + config/configuration.go | 2 +- context/bootstrapper.go | 4 + context/testingbootstrap/testing_bootstrap.go | 2 + documents/invoice/bootstrapper.go | 8 +- documents/invoice/bootstrapper_test.go | 2 + documents/purchaseorder/bootstrapper.go | 7 +- documents/purchaseorder/bootstrapper_test.go | 2 + node/bootstrapper.go | 32 ++++--- p2p/bootstrapper.go | 24 +++++ p2p/bootstrapper_test.go | 35 ++++++++ p2p/client.go | 37 +++----- p2p/client_test.go | 6 +- p2p/handler_test.go | 4 +- p2p/server.go | 90 ++++++++----------- p2p/server_test.go | 16 ++-- p2p/test_bootstrapper.go | 11 +++ 22 files changed, 258 insertions(+), 118 deletions(-) create mode 100644 api/bootstrapper.go create mode 100644 api/bootstrapper_test.go create mode 100644 api/test_bootstrapper.go create mode 100644 p2p/bootstrapper.go create mode 100644 p2p/bootstrapper_test.go create mode 100644 p2p/test_bootstrapper.go diff --git a/api/bootstrapper.go b/api/bootstrapper.go new file mode 100644 index 000000000..7d4decb23 --- /dev/null +++ b/api/bootstrapper.go @@ -0,0 +1,24 @@ +package api + +import ( + "fmt" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" +) + +// Bootstrapper implements bootstrapper.Bootstrapper +type Bootstrapper struct{} + +// Bootstrap initiates api server +func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + return fmt.Errorf("config not initialised") + } + + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + srv := apiServer{config: cfg} + + ctx[bootstrap.BootstrappedAPIServer] = srv + return nil +} diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go new file mode 100644 index 000000000..41c008fdb --- /dev/null +++ b/api/bootstrapper_test.go @@ -0,0 +1,30 @@ +// +build unit + +package api + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/node" + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + b := Bootstrapper{} + + // no config + m := make(map[string]interface{}) + err := b.Bootstrap(m) + assert.Error(t, err) + + // config + c := &config.Configuration{} + m[bootstrap.BootstrappedConfig] = c + err = b.Bootstrap(m) + assert.Nil(t, err) + assert.NotNil(t, m[bootstrap.BootstrappedAPIServer]) + _, ok := m[bootstrap.BootstrappedAPIServer].(node.Server) + assert.True(t, ok) +} diff --git a/api/server.go b/api/server.go index 689a74af2..aa6662aa5 100644 --- a/api/server.go +++ b/api/server.go @@ -22,7 +22,7 @@ import ( "google.golang.org/grpc/credentials" ) -var log = logging.Logger("cent-api-server") +var log = logging.Logger("api-server") type Config interface { GetServerAddress() string @@ -30,21 +30,17 @@ type Config interface { GetNetworkString() string } -// CentAPIServer is an implementation of node.Server interface for serving HTTP based Centrifuge API -type CentAPIServer struct { +// apiServer is an implementation of node.Server interface for serving HTTP based Centrifuge API +type apiServer struct { config Config } -func NewCentAPIServer(config Config) *CentAPIServer { - return &CentAPIServer{config} -} - -func (*CentAPIServer) Name() string { - return "CentAPIServer" +func (apiServer) Name() string { + return "APIServer" } // Serve exposes the client APIs for interacting with a centrifuge node -func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { +func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { defer wg.Done() certPool, err := loadCertPool() if err != nil { @@ -54,8 +50,8 @@ func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr if err != nil { startupErr <- err } - addr := c.config.GetServerAddress() + addr := c.config.GetServerAddress() creds := credentials.NewTLS(&tls.Config{ RootCAs: certPool, ServerName: addr, @@ -100,6 +96,7 @@ func (c *CentAPIServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr startUpErrInner <- err return } + log.Infof("HTTP/gRpc listening on Port: %d\n", c.config.GetServerPort()) log.Infof("Connecting to Network: %s\n", c.config.GetNetworkString()) err = srv.Serve(tls.NewListener(conn, srv.TLSConfig)) diff --git a/api/server_test.go b/api/server_test.go index e91299a30..b6d1b233c 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" ) @@ -28,11 +29,13 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -44,7 +47,7 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil)) - capi := NewCentAPIServer(cfg) + capi := apiServer{config: cfg} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -60,8 +63,8 @@ func TestCentAPIServer_StartListenError(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 100000000) cfg.Set("centrifugeNetwork", "") - capi := NewCentAPIServer(cfg) ctx, _ := context.WithCancel(context.Background()) + capi := apiServer{config: cfg} startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) diff --git a/api/test_bootstrapper.go b/api/test_bootstrapper.go new file mode 100644 index 000000000..99f2e4a36 --- /dev/null +++ b/api/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build unit integration + +package api + +func (b Bootstrapper) TestBootstrap(ctx map[string]interface{}) error { + return b.Bootstrap(ctx) +} + +func (b Bootstrapper) TestTearDown() error { + return nil +} diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index eef1d548c..75a42d6f7 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -8,6 +8,9 @@ const ( BootstrappedLevelDb string = "BootstrappedLevelDb" BootstrappedEthereumClient string = "BootstrappedEthereumClient" BootstrappedAnchorRepository string = "BootstrappedAnchorRepository" + BootstrappedP2PClient string = "BootstrappedP2PClient" + BootstrappedP2PServer string = "BootstrappedP2PServer" + BootstrappedAPIServer string = "BootstrappedAPIServer" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/config/configuration.go b/config/configuration.go index 7e0bd7d7e..9a5a18e37 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -336,7 +336,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { } if _, err := os.Stat(accountKeyPath); os.IsNotExist(err) { - return nil, errors.New("Account Key Path does not exist") + return nil, errors.New("account Key Path does not exist") } bfile, err := ioutil.ReadFile(accountKeyPath) diff --git a/context/bootstrapper.go b/context/bootstrapper.go index 9b56ee6f2..74c5118ca 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -2,6 +2,7 @@ package context import ( "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/api" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -10,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/node" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/version" @@ -30,6 +32,8 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { ðereum.Bootstrapper{}, &anchors.Bootstrapper{}, &identity.Bootstrapper{}, + p2p.Bootstrapper{}, + api.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index 85fcf41df..ef75a6b47 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" logging "github.com/ipfs/go-log" @@ -26,6 +27,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ ðereum.Bootstrapper{}, &anchors.Bootstrapper{}, &identity.Bootstrapper{}, + p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 70789ce42..213901f66 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -21,14 +21,20 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } + cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } + p2pClient, ok := context[bootstrap.BootstrappedP2PClient].(p2p.Client) + if !ok { + return fmt.Errorf("p2p client not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(cfg), anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index 211b23a36..c1e67eaff 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -11,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" ) @@ -20,6 +21,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &storage.Bootstrapper{}, &anchors.Bootstrapper{}, + p2p.Bootstrapper{}, &Bootstrapper{}, } diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 076843101..7cf34c5de 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -27,8 +27,13 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.New("could not initialize purchase order repository") } + p2pClient, ok := context[bootstrap.BootstrappedP2PClient].(p2p.Client) + if !ok { + return fmt.Errorf("p2p client not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2p.NewP2PClient(cfg), anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) err := documents.GetRegistryInstance().Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/bootstrapper_test.go b/documents/purchaseorder/bootstrapper_test.go index fd28ca6a5..3f2e4d280 100644 --- a/documents/purchaseorder/bootstrapper_test.go +++ b/documents/purchaseorder/bootstrapper_test.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" ) @@ -19,6 +20,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + p2p.Bootstrapper{}, &Bootstrapper{}, } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index c387db516..b12d742d6 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -2,32 +2,23 @@ package node import ( "context" - "errors" "fmt" "os" "os/signal" - "github.com/centrifuge/go-centrifuge/api" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/p2p" ) type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { - if _, ok := c[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") - } - cfg := c[bootstrap.BootstrappedConfig].(*config.Configuration) - - services, err := defaultServerList(cfg) + srvs, err := getServers(c) if err != nil { - return fmt.Errorf("failed to get default server list: %v", err) + return fmt.Errorf("failed to load servers: %v", err) } - n := NewNode(services) + n := NewNode(srvs) feedback := make(chan error) // may be we can pass a context that exists in c here ctx, canc := context.WithCancel(context.Background()) @@ -49,6 +40,19 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { return nil } -func defaultServerList(cfg *config.Configuration) ([]Server, error) { - return []Server{api.NewCentAPIServer(cfg), p2p.NewCentP2PServer(cfg)}, nil +func getServers(ctx map[string]interface{}) ([]Server, error) { + p2pSrv, ok := ctx[bootstrap.BootstrappedP2PServer] + if !ok { + return nil, fmt.Errorf("p2p server not initialised") + } + + apiSrv, ok := ctx[bootstrap.BootstrappedAPIServer] + if !ok { + return nil, fmt.Errorf("API server not initiliase") + } + + var servers []Server + servers = append(servers, p2pSrv.(Server)) + servers = append(servers, apiSrv.(Server)) + return servers, nil } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go new file mode 100644 index 000000000..3e3abdaef --- /dev/null +++ b/p2p/bootstrapper.go @@ -0,0 +1,24 @@ +package p2p + +import ( + "fmt" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" +) + +// Bootstrapper implements Bootstrapper with p2p details +type Bootstrapper struct{} + +// Bootstrap initiates p2p server and client into context +func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + return fmt.Errorf("config not initialised") + } + + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + srv := &p2pServer{config: cfg} + ctx[bootstrap.BootstrappedP2PServer] = srv + ctx[bootstrap.BootstrappedP2PClient] = srv + return nil +} diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go new file mode 100644 index 000000000..5527540f9 --- /dev/null +++ b/p2p/bootstrapper_test.go @@ -0,0 +1,35 @@ +// +build unit + +package p2p + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/node" + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + b := Bootstrapper{} + + // no config + m := make(map[string]interface{}) + err := b.Bootstrap(m) + assert.Error(t, err) + + // config + c := &config.Configuration{} + m[bootstrap.BootstrappedConfig] = c + err = b.Bootstrap(m) + assert.Nil(t, err) + + assert.NotNil(t, m[bootstrap.BootstrappedP2PServer]) + _, ok := m[bootstrap.BootstrappedP2PServer].(node.Server) + assert.True(t, ok) + + assert.NotNil(t, m[bootstrap.BootstrappedP2PClient]) + _, ok = m[bootstrap.BootstrappedP2PClient].(Client) + assert.True(t, ok) +} diff --git a/p2p/client.go b/p2p/client.go index 82654066f..0fb7d9ab3 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -23,16 +23,8 @@ type Client interface { GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error } -func NewP2PClient(config Config) Client { - return &defaultClient{config} -} - -type defaultClient struct { - config Config -} - -// Opens a client connection with libp2p -func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error) { +// OpenClient returns P2PServiceClient to contact the remote peer +func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { log.Info("Opening connection to: %s", target) ipfsAddr, err := ma.NewMultiaddr(target) if err != nil { @@ -54,17 +46,14 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerID))) targetAddr := ipfsAddr.Decapsulate(targetPeerAddr) - hostInstance := GetHost() - grpcProtoInstance := GetGRPCProto() - // We have a peer ID and a targetAddr so we add it to the peer store // so LibP2P knows how to contact it - hostInstance.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) + s.host.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) // make a new stream from host B to host A with timeout // Retrial is handled internally, connection request will be cancelled by the connection timeout context - ctx, _ := context.WithTimeout(context.Background(), d.config.GetP2PConnectionTimeout()) - g, err := grpcProtoInstance.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) + ctx, _ := context.WithTimeout(context.Background(), s.config.GetP2PConnectionTimeout()) + g, err := s.protocol.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) } @@ -73,14 +62,14 @@ func (d *defaultClient) OpenClient(target string) (p2ppb.P2PServiceClient, error } // getSignatureForDocument requests the target node to sign the document -func (d *defaultClient) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { - senderId, err := d.config.GetIdentityID() +func (s *p2pServer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { + senderId, err := s.config.GetIdentityID() if err != nil { return nil, err } header := p2ppb.CentrifugeHeader{ - NetworkIdentifier: d.config.GetNetworkID(), + NetworkIdentifier: s.config.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), SenderCentrifugeId: senderId, } @@ -122,8 +111,8 @@ type signatureResponseWrap struct { err error } -func (d *defaultClient) getSignatureAsync(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { - resp, err := d.getSignatureForDocument(ctx, doc, client, receiverCentId) +func (s *p2pServer) getSignatureAsync(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, doc, client, receiverCentId) out <- signatureResponseWrap{ resp: resp, err: err, @@ -131,7 +120,7 @@ func (d *defaultClient) getSignatureAsync(ctx context.Context, doc coredocumentp } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (d *defaultClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { +func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) @@ -152,7 +141,7 @@ func (d *defaultClient) GetSignaturesForDocument(ctx context.Context, doc *cored return centerrors.Wrap(err, "failed to get P2P url") } - client, err := d.OpenClient(target) + client, err := s.OpenClient(target) if err != nil { log.Error(centerrors.Wrap(err, "failed to connect to target")) continue @@ -161,7 +150,7 @@ func (d *defaultClient) GetSignaturesForDocument(ctx context.Context, doc *cored // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - go d.getSignatureAsync(ctx, *doc, client, collaboratorID, in) + go s.getSignatureAsync(ctx, *doc, client, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/p2p/client_test.go b/p2p/client_test.go index c3a9d0607..5a594be50 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -26,7 +26,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("signature failed")).Once() - resp, err := defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -42,7 +42,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(resp, nil).Once() - resp, err = defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err = testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -66,7 +66,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(sigResp, nil).Once() - resp, err := defaultTestClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Nil(t, resp, "must be nil") diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 55d9dda2a..e72450230 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -34,7 +34,7 @@ var ( var coreDoc = testingcoredocument.GenerateCoreDocument() var ctx = map[string]interface{}{} var cfg *config.Configuration -var defaultTestClient defaultClient +var testClient *p2pServer func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ @@ -44,7 +44,7 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - defaultTestClient = defaultClient{cfg} + testClient = &p2pServer{config: cfg} result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/p2p/server.go b/p2p/server.go index 5fb6ad8a2..2b8ab88eb 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -25,9 +25,7 @@ import ( "github.com/paralin/go-libp2p-grpc" ) -var log = logging.Logger("cent-p2p-server") -var HostInstance host.Host -var GRPCProtoInstance p2pgrpc.GRPCProtocol +var log = logging.Logger("p2p-server") type Config interface { GetP2PExternalIP() string @@ -38,47 +36,47 @@ type Config interface { GetIdentityID() ([]byte, error) } -type CentP2PServer struct { - config Config +// p2pServer implements api.Server +type p2pServer struct { + config Config + host host.Host + protocol *p2pgrpc.GRPCProtocol } -func NewCentP2PServer(config Config) *CentP2PServer { - return &CentP2PServer{config} +// Name returns the P2PServer +func (*p2pServer) Name() string { + return "P2PServer" } -func (*CentP2PServer) Name() string { - return "CentP2PServer" -} - -func (c *CentP2PServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { +// Start starts the DHT and GRPC server for p2p communications +func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { defer wg.Done() - if c.config.GetP2PPort() == 0 { + if s.config.GetP2PPort() == 0 { startupErr <- errors.New("please provide a port to bind on") return } // Make a host that listens on the given multiaddress - hostInstance, err := c.makeBasicHost(c.config.GetP2PPort()) + var err error + s.host, err = s.makeBasicHost(s.config.GetP2PPort()) if err != nil { startupErr <- err return } - HostInstance = hostInstance - // Set the grpc protocol handler on it - grpcProto := p2pgrpc.NewGRPCProtocol(context.Background(), hostInstance) - GRPCProtoInstance = *grpcProto - p2ppb.RegisterP2PServiceServer(grpcProto.GetGRPCServer(), &Handler{}) + // Set the grpc protocol handler on it + s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) + p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), &Handler{}) errOut := make(chan error) go func(proto *p2pgrpc.GRPCProtocol, errOut chan<- error) { errOut <- proto.Serve() - }(grpcProto, errOut) + }(s.protocol, errOut) - hostInstance.Peerstore().AddAddr(hostInstance.ID(), hostInstance.Addrs()[0], pstore.TempAddrTTL) + s.host.Peerstore().AddAddr(s.host.ID(), s.host.Addrs()[0], pstore.TempAddrTTL) // Start DHT - c.runDHT(ctx, hostInstance) + s.runDHT(ctx, s.host) for { select { @@ -88,24 +86,23 @@ func (c *CentP2PServer) Start(ctx context.Context, wg *sync.WaitGroup, startupEr return case <-ctx.Done(): log.Info("Shutting down GRPC server") - grpcProto.GetGRPCServer().Stop() + s.protocol.GetGRPCServer().GracefulStop() log.Info("GRPC server stopped") return } } } -func (c *CentP2PServer) runDHT(ctx context.Context, h host.Host) error { +func (s *p2pServer) runDHT(ctx context.Context, h host.Host) error { + // Run it as a Bootstrap Node + dhtClient := dht.NewDHT(ctx, h, ds.NewMapDatastore()) - //dhtClient := dht.NewDHTClient(ctx, h, rdStore) // Just run it as a client, will not respond to discovery requests - dhtClient := dht.NewDHT(ctx, h, ds.NewMapDatastore()) // Run it as a Bootstrap Node + bootstrapPeers := s.config.GetBootstrapPeers() + log.Infof("Bootstrapping %s\n", bootstrapPeers) - log.Infof("Bootstrapping %s\n", c.config.GetBootstrapPeers()) - for _, addr := range c.config.GetBootstrapPeers() { + for _, addr := range bootstrapPeers { iaddr, _ := ipfsaddr.ParseString(addr) - pinfo, _ := pstore.InfoFromP2pAddr(iaddr.Multiaddr()) - if err := h.Connect(ctx, *pinfo); err != nil { log.Info("Bootstrapping to peer failed: ", err) } @@ -129,17 +126,18 @@ func (c *CentP2PServer) runDHT(ctx context.Context, h host.Host) error { if err != nil { log.Error(err) } + log.Infof("Found %d peers!\n", len(peers)) - for _, p1 := range peers { - log.Infof("Peer %s %s\n", p1.ID.Pretty(), p1.Addrs) - } // Now connect to them, so they are added to the PeerStore for _, pe := range peers { + log.Infof("Peer %s %s\n", pe.ID.Pretty(), pe.Addrs) + if pe.ID == h.ID() { // No sense connecting to ourselves continue } + tctx, _ := context.WithTimeout(ctx, time.Second*5) if err := h.Connect(tctx, pe); err != nil { log.Info("Failed to connect to peer: ", err) @@ -151,8 +149,8 @@ func (c *CentP2PServer) runDHT(ctx context.Context, h host.Host) error { } // makeBasicHost creates a LibP2P host with a peer ID listening on the given port -func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { - priv, pub, err := c.createSigningKey() +func (s *p2pServer) makeBasicHost(listenPort int) (host.Host, error) { + priv, pub, err := s.createSigningKey() if err != nil { return nil, err } @@ -177,13 +175,14 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { log.Infof("Could not enable encryption: %v\n", err) return nil, err } + err = ps.AddPrivKey(pid, priv) if err != nil { log.Infof("Could not enable encryption: %v\n", err) return nil, err } - externalIP := c.config.GetP2PExternalIP() + externalIP := s.config.GetP2PExternalIP() var extMultiAddr ma.Multiaddr if externalIP == "" { log.Warning("External IP not defined, Peers might not be able to resolve this node if behind NAT\n") @@ -223,7 +222,7 @@ func (c *CentP2PServer) makeBasicHost(listenPort int) (host.Host, error) { return bhost, nil } -func (c *CentP2PServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { +func (s *p2pServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { // Create the signing key for the host publicKey, privateKey, err := cented25519.GetSigningKeyPairFromConfig() if err != nil { @@ -238,22 +237,7 @@ func (c *CentP2PServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubK if err != nil { return nil, nil, err } + pub = priv.GetPublic() return priv, pub, nil } - -func GetHost() (h host.Host) { - h = HostInstance - if h == nil { - log.Fatal("Host undefined") - } - return -} - -func GetGRPCProto() (g *p2pgrpc.GRPCProtocol) { - g = &GRPCProtoInstance - if g == nil { - log.Fatal("Grpc not instantiated") - } - return -} diff --git a/p2p/server_test.go b/p2p/server_test.go index 2497bdf6f..ec7ccee85 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -18,10 +18,12 @@ func TestCentP2PServer_Start(t *testing.T) { } func TestCentP2PServer_StartContextCancel(t *testing.T) { + cfg.Set("p2p.port", 38203) + k := cfg.GetNetworkKey("bootstrapPeers") + cfg.Set(k, nil) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("p2p.port", 38203) - cp2p := NewCentP2PServer(cfg) + cp2p := &p2pServer{config: cfg} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -31,6 +33,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { // cancel the context to shutdown the server canc() wg.Wait() + assert.Equal(t, 0, len(startErr), "should not error out") } func TestCentP2PServer_StartListenError(t *testing.T) { @@ -38,7 +41,7 @@ func TestCentP2PServer_StartListenError(t *testing.T) { cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") // cause an error by using an invalid port cfg.Set("p2p.port", 100000000) - cp2p := NewCentP2PServer(cfg) + cp2p := &p2pServer{config: cfg} ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -55,7 +58,8 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) - cp2p := NewCentP2PServer(cfg) + cp2p := &p2pServer{config: cfg} + h, err := cp2p.makeBasicHost(listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -68,7 +72,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) cfg.Set("p2p.externalIP", externalIP) - cp2p := NewCentP2PServer(cfg) + cp2p := &p2pServer{config: cfg} h, err := cp2p.makeBasicHost(listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -85,7 +89,7 @@ func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) cfg.Set("p2p.externalIP", externalIP) - cp2p := NewCentP2PServer(cfg) + cp2p := &p2pServer{config: cfg} h, err := cp2p.makeBasicHost(listenPort) assert.NotNil(t, err) assert.Nil(t, h) diff --git a/p2p/test_bootstrapper.go b/p2p/test_bootstrapper.go new file mode 100644 index 000000000..687eb2b56 --- /dev/null +++ b/p2p/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build unit integration + +package p2p + +func (b Bootstrapper) TestBootstrap(ctx map[string]interface{}) error { + return b.Bootstrap(ctx) +} + +func (b Bootstrapper) TestTearDown() error { + return nil +} From 16eb689dba430ad0b56ff7ef53904fa315526d29 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 14 Nov 2018 14:31:23 +0100 Subject: [PATCH 025/220] Fix/p2p test (#449) * fix the deadlock * dont propagte shutdown error * propagate the ctx --- p2p/server.go | 11 +++-------- p2p/server_test.go | 4 +--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index 2b8ab88eb..f5632973b 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -68,10 +68,9 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch // Set the grpc protocol handler on it s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), &Handler{}) - errOut := make(chan error) - go func(proto *p2pgrpc.GRPCProtocol, errOut chan<- error) { - errOut <- proto.Serve() - }(s.protocol, errOut) + go func(proto *p2pgrpc.GRPCProtocol) { + proto.Serve() + }(s.protocol) s.host.Peerstore().AddAddr(s.host.ID(), s.host.Addrs()[0], pstore.TempAddrTTL) @@ -80,10 +79,6 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch for { select { - case err := <-errOut: - log.Infof("failed to accept p2p grpc connections: %v\n", err) - startupErr <- err - return case <-ctx.Done(): log.Info("Shutting down GRPC server") s.protocol.GetGRPCServer().GracefulStop() diff --git a/p2p/server_test.go b/p2p/server_test.go index ec7ccee85..b9669da8f 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -19,13 +19,11 @@ func TestCentP2PServer_Start(t *testing.T) { func TestCentP2PServer_StartContextCancel(t *testing.T) { cfg.Set("p2p.port", 38203) - k := cfg.GetNetworkKey("bootstrapPeers") - cfg.Set(k, nil) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cp2p := &p2pServer{config: cfg} ctx, canc := context.WithCancel(context.Background()) - startErr := make(chan error) + startErr := make(chan error, 1) var wg sync.WaitGroup wg.Add(1) go cp2p.Start(ctx, &wg, startErr) From 145414d98fc2749cd2401ef557e61cdbe18862da Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 16 Nov 2018 10:41:09 +0100 Subject: [PATCH 026/220] NFT: added tests for minting confirmation task (#445) added tests for checking the correct parsing of the arguments --- nft/minting_confirmation_task_test.go | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 nft/minting_confirmation_task_test.go diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go new file mode 100644 index 000000000..8811f0435 --- /dev/null +++ b/nft/minting_confirmation_task_test.go @@ -0,0 +1,66 @@ +// +build unit + +package nft + +import ( + "encoding/hex" + "testing" + + "github.com/centrifuge/go-centrifuge/utils" + "github.com/stretchr/testify/assert" +) + +func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { + task := mintingConfirmationTask{} + tokenId := hex.EncodeToString(utils.RandomSlice(256)) + blockHeight := uint64(12) + registryAddress := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" + + kwargs := map[string]interface{}{ + tokenIDParam: tokenId, + blockHeightParam: blockHeight, + registryAddressParam: registryAddress, + } + + decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + assert.Nil(t, err, "json decode should not thrown an error") + err = task.ParseKwargs(decoded) + assert.Nil(t, err, "parsing should be successful") + + assert.Equal(t, tokenId, task.TokenID, "tokenId should be parsed correctly") + assert.Equal(t, blockHeight, task.BlockHeight, "blockHeight should be parsed correctly") + assert.Equal(t, registryAddress, task.RegistryAddress, "registryAddress should be parsed correctly") + +} + +func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { + task := mintingConfirmationTask{} + tests := []map[string]interface{}{ + { + blockHeightParam: uint64(12), + registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", + }, + { + tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), + registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", + }, + { + tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), + blockHeightParam: uint64(12), + }, + { + //empty map + + }, + { + "dummy": "dummy", + }, + } + + for i, test := range tests { + decoded, err := utils.SimulateJsonDecodeForGocelery(test) + assert.Nil(t, err, "json decode should not thrown an error") + err = task.ParseKwargs(decoded) + assert.Error(t, err, "test case %v: parsing should fail", i) + } +} From d57f3d6f1ca4b897145b458faca417c32b1776ca Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 16 Nov 2018 10:41:23 +0100 Subject: [PATCH 027/220] NFT: removed type parameter from endpoint (#448) * removed type from nft endpoint * find service based on documentID * added tests for findService * fixed findService test * fixed unit tests for type field * deactivated the test case --- documents/invoice/service.go | 5 ++ documents/invoice/service_test.go | 21 ++++++ documents/purchaseorder/service.go | 5 ++ documents/purchaseorder/service_test.go | 21 ++++++ documents/registry.go | 18 +++++ documents/registry_test.go | 25 ++++++- documents/service.go | 3 + nft/ethereum_payment_obligation.go | 12 +-- nft/ethereum_payment_obligation_test.go | 5 +- nft/handler.go | 4 +- nft/handler_test.go | 8 +- nft/payment_obligation.go | 2 +- nft/payment_obligation_integration_test.go | 1 - protobufs/gen/go/nft/service.pb.go | 74 ++++++++----------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/nft/service.swagger.json | 4 - protobufs/nft/service.proto | 8 +- testingutils/documents/documents.go | 5 ++ 18 files changed, 153 insertions(+), 70 deletions(-) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 0257cb04e..a2b4d5e56 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -390,3 +390,8 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return nil } + +// Exists checks if an invoice exists +func (s service) Exists(documentID []byte) bool { + return s.repo.Exists(documentID) +} diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 68f53debb..02b148a32 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -186,6 +186,27 @@ func TestService_GetVersion(t *testing.T) { assert.Error(t, err) } +func TestService_Exists(t *testing.T) { + invSrv := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + inv := &Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + }, + } + err := getRepository().Create(documentIdentifier, inv) + assert.Nil(t, err) + + exists := invSrv.Exists(documentIdentifier) + assert.True(t, exists, "invoice should exist") + + exists = invSrv.Exists(utils.RandomSlice(32)) + assert.False(t, exists, "invoice should not exist") + +} + func TestService_Create(t *testing.T) { ctxh, err := documents.NewContextHeader() assert.Nil(t, err) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index a277b5f04..535e84a79 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -391,3 +391,8 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return nil } + +// Exists checks if an purchase order exists +func (s service) Exists(documentID []byte) bool { + return s.repo.Exists(documentID) +} diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 4db400503..9c954558d 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -657,6 +657,27 @@ func TestService_GetVersion(t *testing.T) { assert.Error(t, err) } +func TestService_Exists(t *testing.T) { + poSrv := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + po := &PurchaseOrder{ + OrderAmount: 42, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + }, + } + err := getRepository().Create(documentIdentifier, po) + assert.Nil(t, err) + + exists := poSrv.Exists(documentIdentifier) + assert.True(t, exists, "purchase order should exist") + + exists = poSrv.Exists(utils.RandomSlice(32)) + assert.False(t, exists, "purchase order should not exist") + +} + func TestService_ReceiveAnchoredDocument(t *testing.T) { poSrv := service{} err := poSrv.ReceiveAnchoredDocument(nil, nil) diff --git a/documents/registry.go b/documents/registry.go index c11fa9419..cae810d97 100644 --- a/documents/registry.go +++ b/documents/registry.go @@ -46,3 +46,21 @@ func (s *ServiceRegistry) LocateService(serviceID string) (Service, error) { return s.services[serviceID], nil } + +// FindService will search the service based on the documentID +func (s *ServiceRegistry) FindService(documentID []byte) (Service, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + for _, service := range s.services { + + exists := service.Exists(documentID) + + if exists { + return service, nil + } + + } + return nil, fmt.Errorf("no service exists for provided documentID") + +} diff --git a/documents/registry_test.go b/documents/registry_test.go index 9eb713b15..49d3e31f8 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -18,10 +18,32 @@ func TestRegistry_GetRegistryInstance(t *testing.T) { assert.Equal(t, ®istryFirst, ®istrySecond, "only one instance of registry should exist") } -func TestRegistry_Register_LocateService_successful(t *testing.T) { + +/* + +testcase requires a mocked Exist method in every service registered +currently the registry is not independent from other test cases +other testcases add services without mocked Exist method to the registry + +func TestServiceRegistry_FindService(t *testing.T) { registry := documents.GetRegistryInstance() a := &testingdocuments.MockService{} + b := &testingdocuments.MockService{} + a.On("Exists").Return(true) + b.On("Exists").Return(false) + err := registry.Register("a service", a) + err = registry.Register("b service", b) + + service, err := registry.FindService([]byte{}) + assert.Nil(t, err, "findService should be successful") + + assert.Equal(t, a, service, "service a should be returned") +}*/ + +func TestRegistry_Register_LocateService_successful(t *testing.T) { + registry := documents.GetRegistryInstance() + a := &testingdocuments.MockService{} coreDocument := testingcoredocument.GenerateCoreDocument() documentType, err := cd.GetTypeURL(coreDocument) assert.Nil(t, err, "should not throw an error because core document contains a type") @@ -37,7 +59,6 @@ func TestRegistry_Register_LocateService_successful(t *testing.T) { func TestRegistry_Register_invalidId(t *testing.T) { registry := documents.GetRegistryInstance() a := &testingdocuments.MockService{} - coreDocument := testingcoredocument.GenerateCoreDocument() coreDocument.EmbeddedData.TypeUrl = "testID_1" diff --git a/documents/service.go b/documents/service.go index cac0c7830..a9a539ab6 100644 --- a/documents/service.go +++ b/documents/service.go @@ -20,6 +20,9 @@ type Service interface { // GetCurrentVersion reads a document from the database GetCurrentVersion(documentID []byte) (Model, error) + // Exists checks if a document exists + Exists(documentID []byte) bool + // GetVersion reads a document from the database GetVersion(documentID []byte, version []byte) (Model, error) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 19853ef7d..2f5c8c498 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -73,8 +73,8 @@ func NewEthereumPaymentObligation(identityService identity.Service, ethClient et bindContract: bindContract} } -func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, docType string, proofFields []string) (*MintRequest, error) { - docService, err := getDocumentService(docType) +func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, proofFields []string) (*MintRequest, error) { + docService, err := getDocumentService(documentID) if err != nil { return nil, err } @@ -124,9 +124,9 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, docTyp } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { +func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { - requestData, err := s.prepareMintRequest(documentID, docType, proofFields) + requestData, err := s.prepareMintRequest(documentID, proofFields) opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { @@ -315,8 +315,8 @@ func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { return property, nil } -func getDocumentService(documentType string) (documents.Service, error) { - docService, err := documents.GetRegistryInstance().LocateService(documentType) +func getDocumentService(documentID []byte) (documents.Service, error) { + docService, err := documents.GetRegistryInstance().FindService(documentID) if err != nil { return nil, err } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index c0d604586..49bfc661f 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -177,6 +177,7 @@ func TestPaymentObligationService(t *testing.T) { docServiceMock := testingdocuments.MockService{} docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocument: coreDoc}, nil) docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) + docServiceMock.On("Exists").Return(true) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIDService{} idServiceMock.On("GetIdentityAddress", centID).Return(address, nil) @@ -194,7 +195,7 @@ func TestPaymentObligationService(t *testing.T) { return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock }, - &nftpb.NFTMintRequest{Identifier: "0x1212", Type: "happypath", ProofFields: []string{"collaborators[0]"}}, + &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}}, nil, "", }, @@ -211,7 +212,7 @@ func TestPaymentObligationService(t *testing.T) { }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil }) - _, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.Type, test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + _, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { diff --git a/nft/handler.go b/nft/handler.go index 371670875..2228d4ec3 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -25,7 +25,7 @@ func GRPCHandler() nftpb.NFTServiceServer { // MintNFT will be called from the client API to mint an NFT func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { - apiLog.Infof("Received request to Mint an NFT for document %s type %s with proof fields %s", request.Identifier, request.Type, request.ProofFields) + apiLog.Infof("Received request to Mint an NFT with %s with proof fields %s", request.Identifier, request.ProofFields) err := validateParameters(request) if err != nil { @@ -36,7 +36,7 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) } - confirmation, err := g.service.MintNFT(identifier, request.Type, request.RegistryAddress, request.DepositAddress, request.ProofFields) + confirmation, err := g.service.MintNFT(identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) if err != nil { return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) } diff --git a/nft/handler_test.go b/nft/handler_test.go index 74e760d1a..147318d64 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -19,8 +19,8 @@ type MockPaymentObligationService struct { mock.Mock } -func (m *MockPaymentObligationService) MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { - args := m.Called(documentID, docType, registryAddress, depositAddress, proofFields) +func (m *MockPaymentObligationService) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { + args := m.Called(documentID, registryAddress, depositAddress, proofFields) return args.Get(0).(chan *WatchTokenMinted), args.Error(1) } @@ -31,7 +31,7 @@ func TestNFTMint_success(t *testing.T) { confirmations := make(chan *WatchTokenMinted) mockService. - On("MintNFT", docID, nftMintRequest.Type, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(confirmations, nil) tokID := big.NewInt(1) @@ -61,7 +61,7 @@ func TestNFTMint_ServiceError(t *testing.T) { docID, _ := hexutil.Decode(nftMintRequest.Identifier) confirmations := make(chan *WatchTokenMinted) mockService. - On("MintNFT", docID, nftMintRequest.Type, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(confirmations, errors.New("service error")) handler := grpcHandler{mockService} diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index 8ccdef025..b2a7c074b 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -6,7 +6,7 @@ import "math/big" type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(documentID []byte, docType, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) + MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) } type WatchTokenMinted struct { diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index f3a0f5f63..653e9cd1f 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -75,7 +75,6 @@ func TestPaymentObligationService_mint(t *testing.T) { // assert no error confirmations, err := nft.GetPaymentObligation().MintNFT( ID, - documenttypes.InvoiceDataTypeUrl, config.Config().GetContractAddress("paymentObligation").String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", []string{"gross_amount", "currency", "due_date", "document_type", "collaborators[0]"}, diff --git a/protobufs/gen/go/nft/service.pb.go b/protobufs/gen/go/nft/service.pb.go index a52eabd2f..e16a63f6d 100644 --- a/protobufs/gen/go/nft/service.pb.go +++ b/protobufs/gen/go/nft/service.pb.go @@ -28,12 +28,10 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type NFTMintRequest struct { // Document identifier Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - // Document type - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // The contract address of the registry where the token should be minted - RegistryAddress string `protobuf:"bytes,3,opt,name=registry_address,json=registryAddress,proto3" json:"registry_address,omitempty"` - DepositAddress string `protobuf:"bytes,4,opt,name=deposit_address,json=depositAddress,proto3" json:"deposit_address,omitempty"` - ProofFields []string `protobuf:"bytes,5,rep,name=proof_fields,json=proofFields,proto3" json:"proof_fields,omitempty"` + RegistryAddress string `protobuf:"bytes,2,opt,name=registry_address,json=registryAddress,proto3" json:"registry_address,omitempty"` + DepositAddress string `protobuf:"bytes,3,opt,name=deposit_address,json=depositAddress,proto3" json:"deposit_address,omitempty"` + ProofFields []string `protobuf:"bytes,4,rep,name=proof_fields,json=proofFields,proto3" json:"proof_fields,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -43,7 +41,7 @@ func (m *NFTMintRequest) Reset() { *m = NFTMintRequest{} } func (m *NFTMintRequest) String() string { return proto.CompactTextString(m) } func (*NFTMintRequest) ProtoMessage() {} func (*NFTMintRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_deadd92188acecb1, []int{0} + return fileDescriptor_service_b4e252768b910acc, []int{0} } func (m *NFTMintRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintRequest.Unmarshal(m, b) @@ -70,13 +68,6 @@ func (m *NFTMintRequest) GetIdentifier() string { return "" } -func (m *NFTMintRequest) GetType() string { - if m != nil { - return m.Type - } - return "" -} - func (m *NFTMintRequest) GetRegistryAddress() string { if m != nil { return m.RegistryAddress @@ -109,7 +100,7 @@ func (m *NFTMintResponse) Reset() { *m = NFTMintResponse{} } func (m *NFTMintResponse) String() string { return proto.CompactTextString(m) } func (*NFTMintResponse) ProtoMessage() {} func (*NFTMintResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_deadd92188acecb1, []int{1} + return fileDescriptor_service_b4e252768b910acc, []int{1} } func (m *NFTMintResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintResponse.Unmarshal(m, b) @@ -213,32 +204,31 @@ var _NFTService_serviceDesc = grpc.ServiceDesc{ Metadata: "nft/service.proto", } -func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_deadd92188acecb1) } - -var fileDescriptor_service_deadd92188acecb1 = []byte{ - // 371 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xc1, 0x8e, 0xd3, 0x30, - 0x10, 0x86, 0x95, 0xed, 0x2e, 0x65, 0xbd, 0xab, 0xed, 0x62, 0x38, 0x84, 0x08, 0x21, 0x93, 0x03, - 0x14, 0xd4, 0x36, 0x12, 0xdc, 0xb8, 0xb5, 0xa0, 0x48, 0x1c, 0x88, 0xaa, 0x92, 0x13, 0x97, 0x2a, - 0x4d, 0xc6, 0x91, 0x45, 0x33, 0x36, 0xf6, 0x94, 0xaa, 0x57, 0x24, 0x5e, 0x00, 0x1e, 0x87, 0xc7, - 0xe0, 0x15, 0x78, 0x10, 0x14, 0xa7, 0xad, 0xa8, 0xf6, 0x64, 0xfb, 0x9b, 0xcf, 0xa3, 0x5f, 0x33, - 0xec, 0x01, 0x4a, 0x4a, 0x1c, 0xd8, 0x6f, 0xaa, 0x84, 0x89, 0xb1, 0x9a, 0x34, 0xef, 0xa1, 0xa4, - 0xe8, 0x49, 0xad, 0x75, 0xbd, 0x86, 0xa4, 0x30, 0x2a, 0x29, 0x10, 0x35, 0x15, 0xa4, 0x34, 0xba, - 0x4e, 0x89, 0x46, 0xfe, 0x28, 0xc7, 0x35, 0xe0, 0xd8, 0x6d, 0x8b, 0xba, 0x06, 0x9b, 0x68, 0xe3, - 0x8d, 0xbb, 0x76, 0xfc, 0x3b, 0x60, 0x37, 0x59, 0x9a, 0x7f, 0x54, 0x48, 0x0b, 0xf8, 0xba, 0x01, - 0x47, 0xfc, 0x29, 0x63, 0xaa, 0x02, 0x24, 0x25, 0x15, 0xd8, 0x30, 0x10, 0xc1, 0xf0, 0x72, 0xf1, - 0x1f, 0xe1, 0x9c, 0x9d, 0xd3, 0xce, 0x40, 0x78, 0xe6, 0x2b, 0xfe, 0xce, 0x5f, 0xb2, 0x5b, 0x0b, - 0xb5, 0x72, 0x64, 0x77, 0xcb, 0xa2, 0xaa, 0x2c, 0x38, 0x17, 0xf6, 0x7c, 0x7d, 0x70, 0xe0, 0xd3, - 0x0e, 0xf3, 0x17, 0x6c, 0x50, 0x81, 0xd1, 0x4e, 0xd1, 0xd1, 0x3c, 0xf7, 0xe6, 0xcd, 0x1e, 0x1f, - 0xc4, 0x67, 0xec, 0xda, 0x58, 0xad, 0xe5, 0x52, 0x2a, 0x58, 0x57, 0x2e, 0xbc, 0x10, 0xbd, 0xe1, - 0xe5, 0xe2, 0xca, 0xb3, 0xd4, 0xa3, 0x78, 0xc4, 0x06, 0xc7, 0xf0, 0xce, 0x68, 0x74, 0xc0, 0x1f, - 0xb3, 0xfb, 0xa4, 0xbf, 0x00, 0x2e, 0x55, 0xb5, 0xcf, 0xde, 0xf7, 0xef, 0x0f, 0xd5, 0xeb, 0x1f, - 0x01, 0x63, 0x59, 0x9a, 0x7f, 0xea, 0x26, 0xca, 0xb7, 0xac, 0xdf, 0xfe, 0xcc, 0xd2, 0x9c, 0x3f, - 0x9c, 0xa0, 0xa4, 0xc9, 0xe9, 0x1c, 0xa2, 0x47, 0xa7, 0xb0, 0xeb, 0x1f, 0x4f, 0x7f, 0x4e, 0x87, - 0xd1, 0xf3, 0x16, 0x89, 0x02, 0x45, 0x96, 0xe6, 0x42, 0x5a, 0xdd, 0x88, 0x42, 0xbc, 0x03, 0x24, - 0xab, 0xe4, 0xa6, 0x06, 0xf1, 0x5e, 0x97, 0x9b, 0x06, 0x90, 0xbe, 0xff, 0xf9, 0xfb, 0xeb, 0xec, - 0x36, 0xbe, 0x4a, 0x7c, 0x82, 0xa4, 0x51, 0x48, 0x6f, 0x83, 0x57, 0x33, 0xc1, 0xfa, 0xa5, 0x6e, - 0xda, 0xee, 0xb3, 0xeb, 0x7d, 0x98, 0x79, 0xbb, 0x8c, 0x79, 0xf0, 0xf9, 0x02, 0x25, 0x99, 0xd5, - 0xea, 0x9e, 0x5f, 0xce, 0x9b, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x69, 0xb7, 0x27, 0x68, 0x02, - 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_b4e252768b910acc) } + +var fileDescriptor_service_b4e252768b910acc = []byte{ + // 361 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x6e, 0xda, 0x40, + 0x14, 0x86, 0x65, 0x68, 0x4b, 0x19, 0x10, 0x50, 0xb7, 0x0b, 0x6a, 0x55, 0xd5, 0xd4, 0x8b, 0x96, + 0x56, 0x80, 0xa5, 0x76, 0xd7, 0x1d, 0xb4, 0xb2, 0xd4, 0x45, 0x2d, 0x44, 0xbd, 0xea, 0x06, 0x19, + 0xfb, 0x8d, 0x35, 0x0a, 0x7e, 0xe3, 0xcc, 0x3c, 0x82, 0xb2, 0x8d, 0x94, 0x0b, 0x24, 0x87, 0xc8, + 0x81, 0x72, 0x85, 0x1c, 0x24, 0xf2, 0x18, 0x50, 0x50, 0x56, 0xa3, 0xf9, 0xf4, 0xcd, 0xd3, 0x3f, + 0xff, 0x63, 0x6f, 0x50, 0x50, 0x60, 0x40, 0x5f, 0xc8, 0x14, 0xa6, 0xa5, 0x56, 0xa4, 0xdc, 0x26, + 0x0a, 0xf2, 0x3e, 0xe4, 0x4a, 0xe5, 0x1b, 0x08, 0x92, 0x52, 0x06, 0x09, 0xa2, 0xa2, 0x84, 0xa4, + 0x42, 0x53, 0x2b, 0xde, 0xd8, 0x1e, 0xe9, 0x24, 0x07, 0x9c, 0x98, 0x5d, 0x92, 0xe7, 0xa0, 0x03, + 0x55, 0x5a, 0xe3, 0xb9, 0xed, 0xdf, 0x39, 0xac, 0x17, 0x85, 0xf1, 0x5f, 0x89, 0xb4, 0x84, 0xf3, + 0x2d, 0x18, 0x72, 0x3f, 0x32, 0x26, 0x33, 0x40, 0x92, 0x42, 0x82, 0x1e, 0x3a, 0xdc, 0x19, 0xb5, + 0x97, 0x4f, 0x88, 0xfb, 0x95, 0x0d, 0x34, 0xe4, 0xd2, 0x90, 0xbe, 0x5c, 0x25, 0x59, 0xa6, 0xc1, + 0x98, 0x61, 0xc3, 0x5a, 0xfd, 0x03, 0x9f, 0xd5, 0xd8, 0xfd, 0xc2, 0xfa, 0x19, 0x94, 0xca, 0x48, + 0x3a, 0x9a, 0x4d, 0x6b, 0xf6, 0xf6, 0xf8, 0x20, 0x7e, 0x62, 0xdd, 0x52, 0x2b, 0x25, 0x56, 0x42, + 0xc2, 0x26, 0x33, 0xc3, 0x17, 0xbc, 0x39, 0x6a, 0x2f, 0x3b, 0x96, 0x85, 0x16, 0xf9, 0x63, 0xd6, + 0x3f, 0x06, 0x35, 0xa5, 0x42, 0x03, 0xee, 0x7b, 0xf6, 0x9a, 0xd4, 0x19, 0xe0, 0x4a, 0x66, 0xfb, + 0x9c, 0x2d, 0x7b, 0xff, 0x93, 0x7d, 0xbf, 0x76, 0x18, 0x8b, 0xc2, 0xf8, 0x5f, 0xdd, 0x9e, 0xbb, + 0x63, 0xad, 0xea, 0x65, 0x14, 0xc6, 0xee, 0xdb, 0x29, 0x0a, 0x9a, 0x9e, 0xfe, 0xd9, 0x7b, 0x77, + 0x0a, 0xeb, 0xf9, 0xfe, 0xec, 0x66, 0x36, 0xf2, 0x3e, 0x57, 0x88, 0x27, 0xc8, 0xa3, 0x30, 0xe6, + 0x42, 0xab, 0x82, 0x27, 0xfc, 0x17, 0x20, 0x69, 0x29, 0xb6, 0x39, 0xf0, 0xdf, 0x2a, 0xdd, 0x16, + 0x80, 0x74, 0x75, 0xff, 0x70, 0xdb, 0x18, 0xf8, 0x9d, 0xc0, 0x26, 0x08, 0x0a, 0x89, 0xf4, 0xd3, + 0xf9, 0x36, 0xe7, 0xac, 0x95, 0xaa, 0xa2, 0x9a, 0x3e, 0xef, 0xee, 0xc3, 0x2c, 0xaa, 0xe2, 0x17, + 0xce, 0xff, 0x97, 0x28, 0xa8, 0x5c, 0xaf, 0x5f, 0xd9, 0x45, 0xfc, 0x78, 0x0c, 0x00, 0x00, 0xff, + 0xff, 0x82, 0x2c, 0xea, 0x0e, 0xee, 0x01, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 2f95363f6..9241fdf10 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"type":{"type":"string","title":"Document type"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/nft/service.swagger.json b/protobufs/gen/swagger/nft/service.swagger.json index 7667df0ae..31792eb39 100644 --- a/protobufs/gen/swagger/nft/service.swagger.json +++ b/protobufs/gen/swagger/nft/service.swagger.json @@ -51,10 +51,6 @@ "type": "string", "title": "Document identifier" }, - "type": { - "type": "string", - "title": "Document type" - }, "registry_address": { "type": "string", "title": "The contract address of the registry where the token should be minted" diff --git a/protobufs/nft/service.proto b/protobufs/nft/service.proto index 00d900f14..83cd2e0c2 100644 --- a/protobufs/nft/service.proto +++ b/protobufs/nft/service.proto @@ -26,12 +26,10 @@ service NFTService { message NFTMintRequest { // Document identifier string identifier = 1; - // Document type - string type = 2; // The contract address of the registry where the token should be minted - string registry_address = 3; - string deposit_address = 4; - repeated string proof_fields = 5; + string registry_address = 2; + string deposit_address = 3; + repeated string proof_fields = 4; } message NFTMintResponse { diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 02638ed38..08c5e22b5 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -48,6 +48,11 @@ func (m *MockService) ReceiveAnchoredDocument(model documents.Model, headers *p2 return args.Error(0) } +func (m *MockService) Exists(documentID []byte) bool { + args := m.Called() + return args.Get(0).(bool) +} + type MockModel struct { documents.Model mock.Mock From 55dea3cffa32931b61969ed00cfa7aabdd837939 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 16 Nov 2018 11:41:41 +0100 Subject: [PATCH 028/220] NFT: usage of depositAddress parameter (#456) * removed usage of identity contract address for mint method --- nft/ethereum_payment_obligation.go | 9 +++------ nft/ethereum_payment_obligation_test.go | 8 +------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 2f5c8c498..ff8eea00e 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -73,7 +73,7 @@ func NewEthereumPaymentObligation(identityService identity.Service, ethClient et bindContract: bindContract} } -func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, proofFields []string) (*MintRequest, error) { +func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { docService, err := getDocumentService(documentID) if err != nil { return nil, err @@ -94,10 +94,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, proofF return nil, err } - toAddress, err := s.getIdentityAddress() - if err != nil { - return nil, nil - } + toAddress := common.HexToAddress(depositAddress) anchorID, err := anchors.ToAnchorID(corDoc.CurrentVersion) if err != nil { @@ -126,7 +123,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, proofF // MintNFT mints an NFT func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { - requestData, err := s.prepareMintRequest(documentID, proofFields) + requestData, err := s.prepareMintRequest(documentID, depositAddress, proofFields) opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 49bfc661f..913be149a 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -15,7 +15,6 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -168,9 +167,6 @@ func TestPaymentObligationService(t *testing.T) { { "happypath", func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, MockConfig) { - centIDByte := utils.RandomSlice(6) - centID, _ := identity.ToCentID(centIDByte) - address := common.BytesToAddress(utils.RandomSlice(32)) coreDoc := coredocument.New() coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) @@ -180,7 +176,6 @@ func TestPaymentObligationService(t *testing.T) { docServiceMock.On("Exists").Return(true) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIDService{} - idServiceMock.On("GetIdentityAddress", centID).Return(address, nil) ethClientMock := testingcommons.MockEthClient{} ethClientMock.On("GetTxOpts", "ethacc").Return(&bind.TransactOpts{}, nil) ethClientMock.On("SubmitTransactionWithRetries", @@ -190,12 +185,11 @@ func TestPaymentObligationService(t *testing.T) { ).Return(&types.Transaction{}, nil) configMock := MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") - configMock.On("GetIdentityID").Return(centIDByte, nil) configMock.On("GetContractAddress").Return(common.HexToAddress("0xd0dbc72ae5e71382b3cc9cfdc53f6952a085db6d")) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock }, - &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}}, + &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, nil, "", }, From 1a4530ab2a87cc72958e1d4426db22276624d24b Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 16 Nov 2018 15:15:35 +0100 Subject: [PATCH 029/220] remove global registry service (#457) Removes global service registry --- api/bootstrapper.go | 11 +++-- api/bootstrapper_test.go | 2 + api/server.go | 6 ++- api/server_test.go | 10 +++-- api/service.go | 8 ++-- context/bootstrapper.go | 2 + context/testingbootstrap/testing_bootstrap.go | 10 +++-- documents/bootstrapper.go | 6 ++- documents/bootstrapper_test.go | 18 ++++++++ documents/handler.go | 13 +++--- documents/handler_test.go | 28 ++++++------- documents/invoice/bootstrapper.go | 17 +++++--- documents/invoice/bootstrapper_test.go | 2 + documents/invoice/handler.go | 7 ++-- documents/purchaseorder/bootstrapper.go | 17 +++++--- documents/purchaseorder/bootstrapper_test.go | 2 + documents/purchaseorder/handler.go | 4 +- documents/registry.go | 16 +++---- documents/registry_test.go | 25 +++-------- documents/test_bootstrapper.go | 4 +- keytools/generate_test.go | 15 +------ keytools/sign_test.go | 2 - keytools/verify_test.go | 3 -- nft/bootstrapper.go | 19 ++++++--- nft/ethereum_payment_obligation.go | 20 ++++----- nft/ethereum_payment_obligation_test.go | 6 ++- nft/payment_obligation_integration_test.go | 10 +++-- p2p/handler.go | 23 ++++++---- p2p/handler_integration_test.go | 7 +++- p2p/handler_test.go | 42 ++++++++++--------- p2p/server.go | 16 +++++-- 31 files changed, 207 insertions(+), 164 deletions(-) create mode 100644 documents/bootstrapper_test.go diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 7d4decb23..92337d70a 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" ) // Bootstrapper implements bootstrapper.Bootstrapper @@ -12,13 +13,17 @@ type Bootstrapper struct{} // Bootstrap initiates api server func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + cfg, ok := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + if !ok { return fmt.Errorf("config not initialised") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - srv := apiServer{config: cfg} + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("service registry not initialised") + } + srv := apiServer{config: cfg, registry: registry} ctx[bootstrap.BootstrappedAPIServer] = srv return nil } diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index 41c008fdb..b96b73158 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/stretchr/testify/assert" ) @@ -22,6 +23,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config c := &config.Configuration{} m[bootstrap.BootstrappedConfig] = c + m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) assert.NotNil(t, m[bootstrap.BootstrappedAPIServer]) diff --git a/api/server.go b/api/server.go index aa6662aa5..69fb9bced 100644 --- a/api/server.go +++ b/api/server.go @@ -15,6 +15,7 @@ import ( "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/documents" "github.com/grpc-ecosystem/grpc-gateway/runtime" logging "github.com/ipfs/go-log" "golang.org/x/net/context" @@ -32,7 +33,8 @@ type Config interface { // apiServer is an implementation of node.Server interface for serving HTTP based Centrifuge API type apiServer struct { - config Config + config Config + registry *documents.ServiceRegistry } func (apiServer) Name() string { @@ -73,7 +75,7 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha mux := http.NewServeMux() gwmux := runtime.NewServeMux() - err = registerServices(ctx, c.config, grpcServer, gwmux, addr, dopts) + err = registerServices(ctx, c.config, c.registry, grpcServer, gwmux, addr, dopts) if err != nil { startupErr <- err return diff --git a/api/server_test.go b/api/server_test.go index b6d1b233c..3ac568fb6 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -23,19 +23,21 @@ import ( var ctx = map[string]interface{}{} var cfg *config.Configuration +var registry *documents.ServiceRegistry func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - + registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -46,8 +48,8 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil)) - capi := apiServer{config: cfg} + registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil)) + capi := apiServer{config: cfg, registry: registry} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -64,7 +66,7 @@ func TestCentAPIServer_StartListenError(t *testing.T) { cfg.Set("nodePort", 100000000) cfg.Set("centrifugeNetwork", "") ctx, _ := context.WithCancel(context.Background()) - capi := apiServer{config: cfg} + capi := apiServer{config: cfg, registry: registry} startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) diff --git a/api/service.go b/api/service.go index 825afc716..be88dad06 100644 --- a/api/service.go +++ b/api/service.go @@ -19,16 +19,16 @@ import ( ) // registerServices registers all endpoints to the grpc server -func registerServices(ctx context.Context, config Config, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { +func registerServices(ctx context.Context, config Config, registry *documents.ServiceRegistry, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { // documents (common) - documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler()) + documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler(registry)) err := documentpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err } // invoice - handler, err := invoice.GRPCHandler() + handler, err := invoice.GRPCHandler(registry) if err != nil { return err } @@ -39,7 +39,7 @@ func registerServices(ctx context.Context, config Config, grpcServer *grpc.Serve } // purchase orders - srv, err := purchaseorder.GRPCHandler() + srv, err := purchaseorder.GRPCHandler(registry) if err != nil { return fmt.Errorf("failed to get purchase order handler: %v", err) } diff --git a/context/bootstrapper.go b/context/bootstrapper.go index 74c5118ca..bb14db7fd 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/api" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -32,6 +33,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { ðereum.Bootstrapper{}, &anchors.Bootstrapper{}, &identity.Bootstrapper{}, + documents.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, &invoice.Bootstrapper{}, diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index ef75a6b47..9f8572677 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -27,6 +28,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ ðereum.Bootstrapper{}, &anchors.Bootstrapper{}, &identity.Bootstrapper{}, + documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, @@ -34,15 +36,17 @@ var bootstappers = []bootstrap.TestBootstrapper{ &queue.Bootstrapper{}, } -func TestFunctionalEthereumBootstrap() { - contextval := map[string]interface{}{} +func TestFunctionalEthereumBootstrap() map[string]interface{} { + ctx := map[string]interface{}{} for _, b := range bootstappers { - err := b.TestBootstrap(contextval) + err := b.TestBootstrap(ctx) if err != nil { log.Error("Error encountered while bootstrapping", err) panic(err) } } + + return ctx } func TestFunctionalEthereumTearDown() { for _, b := range bootstappers { diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index a636b16b3..32b74aaf1 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -1,8 +1,12 @@ package documents +// BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context +const BootstrappedRegistry = "BootstrappedRegistry" + type Bootstrapper struct{} // Bootstrap sets the required storage and registers -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + ctx[BootstrappedRegistry] = NewServiceRegistry() return nil } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go new file mode 100644 index 000000000..1da47e0b5 --- /dev/null +++ b/documents/bootstrapper_test.go @@ -0,0 +1,18 @@ +// +build unit + +package documents + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + ctx := make(map[string]interface{}) + err := Bootstrapper{}.Bootstrap(ctx) + assert.Nil(t, err) + assert.NotNil(t, ctx[BootstrappedRegistry]) + _, ok := ctx[BootstrappedRegistry].(*ServiceRegistry) + assert.True(t, ok) +} diff --git a/documents/handler.go b/documents/handler.go index 3d203c61b..3d4717581 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -15,18 +15,19 @@ var apiLog = logging.Logger("document-api") // grpcHandler handles all the common document related actions: proof generation type grpcHandler struct { + registry *ServiceRegistry } // GRPCHandler returns an implementation of documentpb.DocumentServiceServer -func GRPCHandler() documentpb.DocumentServiceServer { - return grpcHandler{} +func GRPCHandler(registry *ServiceRegistry) documentpb.DocumentServiceServer { + return grpcHandler{registry: registry} } // CreateDocumentProof creates precise proofs for the given fields -func (grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProofEnvelope *documentpb.CreateDocumentProofRequest) (*documentpb.DocumentProof, error) { +func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProofEnvelope *documentpb.CreateDocumentProofRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofEnvelope) - service, err := GetRegistryInstance().LocateService(createDocumentProofEnvelope.Type) + service, err := h.registry.LocateService(createDocumentProofEnvelope.Type) if err != nil { return &documentpb.DocumentProof{}, err } @@ -44,10 +45,10 @@ func (grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProofE } // CreateDocumentProofForVersion creates precise proofs for the given fields for the given version of the document -func (grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDocumentProofForVersionEnvelope *documentpb.CreateDocumentProofForVersionRequest) (*documentpb.DocumentProof, error) { +func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDocumentProofForVersionEnvelope *documentpb.CreateDocumentProofForVersionRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofForVersionEnvelope) - service, err := GetRegistryInstance().LocateService(createDocumentProofForVersionEnvelope.Type) + service, err := h.registry.LocateService(createDocumentProofForVersionEnvelope.Type) if err != nil { return &documentpb.DocumentProof{}, err } diff --git a/documents/handler_test.go b/documents/handler_test.go index 69d57d198..78808b7e3 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -16,7 +16,7 @@ import ( ) func TestGrpcHandler_CreateDocumentProof(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProof" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -28,7 +28,7 @@ func TestGrpcHandler_CreateDocumentProof(t *testing.T) { id, _ := hexutil.Decode(req.Identifier) doc := &documents.DocumentProof{} service.On("CreateProofs", id, req.Fields).Return(doc, nil) - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) retDoc, _ := grpcHandler.CreateDocumentProof(context.TODO(), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) @@ -36,7 +36,7 @@ func TestGrpcHandler_CreateDocumentProof(t *testing.T) { } func TestGrpcHandler_CreateDocumentProofUnableToLocateService(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofUnableToLocateService" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -45,14 +45,14 @@ func TestGrpcHandler_CreateDocumentProofUnableToLocateService(t *testing.T) { Type: "wrongService", Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") } func TestGrpcHandler_CreateDocumentProofInvalidHex(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofInvalidHex" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -61,14 +61,14 @@ func TestGrpcHandler_CreateDocumentProofInvalidHex(t *testing.T) { Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") } func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofForVersion" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -82,7 +82,7 @@ func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { version, _ := hexutil.Decode(req.Version) doc := &documents.DocumentProof{DocumentId: utils.RandomSlice(32)} service.On("CreateProofsForVersion", id, version, req.Fields).Return(doc, nil) - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) retDoc, _ := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) @@ -90,7 +90,7 @@ func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { } func TestGrpcHandler_CreateDocumentProofForVersionUnableToLocateService(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofForVersionUnableToLocateService" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -100,14 +100,14 @@ func TestGrpcHandler_CreateDocumentProofForVersionUnableToLocateService(t *testi Type: "wrongService", Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") } func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForId(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofForVersionInvalidHexForId" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -117,14 +117,14 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForId(t *testing.T) Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") } func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForVersion(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() serviceName := "CreateDocumentProofForVersionInvalidHexForVersion" service := &testingdocuments.MockService{} registry.Register(serviceName, service) @@ -134,7 +134,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForVersion(t *testin Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler() + grpcHandler := documents.GRPCHandler(registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 213901f66..c2ad627b0 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -17,25 +17,30 @@ import ( type Bootstrapper struct{} // Bootstrap sets the required storage and registers -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { +func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { + if _, ok := ctx[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } - p2pClient, ok := context[bootstrap.BootstrappedP2PClient].(p2p.Client) + p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") } + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("service registry not initialised") + } + // register service srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) - err := documents.GetRegistryInstance().Register(documenttypes.InvoiceDataTypeUrl, srv) + err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) } diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index c1e67eaff..24c6274b1 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -11,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" ) @@ -21,6 +22,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &storage.Bootstrapper{}, &anchors.Bootstrapper{}, + documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 1d2619469..dd005035f 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -22,13 +22,14 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler() (clientinvoicepb.DocumentServiceServer, error) { - invoiceService, err := documents.GetRegistryInstance().LocateService(documenttypes.InvoiceDataTypeUrl) +func GRPCHandler(registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { + srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) if err != nil { return nil, err } + return &grpcHandler{ - service: invoiceService.(Service), + service: srv.(Service), }, nil } diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 7cf34c5de..426c62f69 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -17,24 +17,29 @@ import ( type Bootstrapper struct { } -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { +func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { + if _, ok := ctx[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("could not initialize purchase order repository") } - p2pClient, ok := context[bootstrap.BootstrappedP2PClient].(p2p.Client) + p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") } + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("service registry not initialised") + } + // register service srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) - err := documents.GetRegistryInstance().Register(documenttypes.PurchaseOrderDataTypeUrl, srv) + err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") } diff --git a/documents/purchaseorder/bootstrapper_test.go b/documents/purchaseorder/bootstrapper_test.go index 3f2e4d280..c7368c503 100644 --- a/documents/purchaseorder/bootstrapper_test.go +++ b/documents/purchaseorder/bootstrapper_test.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" @@ -20,6 +21,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, } diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index d673cf00b..2c35b3b1f 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -22,8 +22,8 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler() (clientpurchaseorderpb.DocumentServiceServer, error) { - srv, err := documents.GetRegistryInstance().LocateService(documenttypes.PurchaseOrderDataTypeUrl) +func GRPCHandler(registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { + srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { return nil, fmt.Errorf("failed to fetch purchase order service") } diff --git a/documents/registry.go b/documents/registry.go index cae810d97..15ab2af69 100644 --- a/documents/registry.go +++ b/documents/registry.go @@ -11,17 +11,11 @@ type ServiceRegistry struct { mutex sync.RWMutex } -var registryInstance *ServiceRegistry -var registryOnce sync.Once - -// GetRegistryInstance returns current registry instance -func GetRegistryInstance() *ServiceRegistry { - registryOnce.Do(func() { - registryInstance = &ServiceRegistry{} - registryInstance.services = make(map[string]Service) - registryInstance.mutex = sync.RWMutex{} - }) - return registryInstance +// NewServiceRegistry returns a new instance of service registry +func NewServiceRegistry() *ServiceRegistry { + return &ServiceRegistry{ + services: make(map[string]Service), + } } // Register can register a service which implements the ModelDeriver interface diff --git a/documents/registry_test.go b/documents/registry_test.go index 49d3e31f8..5501b5154 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -12,21 +12,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRegistry_GetRegistryInstance(t *testing.T) { - registryFirst := documents.GetRegistryInstance() - registrySecond := documents.GetRegistryInstance() - assert.Equal(t, ®istryFirst, ®istrySecond, "only one instance of registry should exist") -} - - -/* - -testcase requires a mocked Exist method in every service registered -currently the registry is not independent from other test cases -other testcases add services without mocked Exist method to the registry - func TestServiceRegistry_FindService(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} b := &testingdocuments.MockService{} a.On("Exists").Return(true) @@ -36,13 +23,11 @@ func TestServiceRegistry_FindService(t *testing.T) { service, err := registry.FindService([]byte{}) assert.Nil(t, err, "findService should be successful") - assert.Equal(t, a, service, "service a should be returned") - -}*/ +} func TestRegistry_Register_LocateService_successful(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} coreDocument := testingcoredocument.GenerateCoreDocument() documentType, err := cd.GetTypeURL(coreDocument) @@ -57,7 +42,7 @@ func TestRegistry_Register_LocateService_successful(t *testing.T) { } func TestRegistry_Register_invalidId(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} coreDocument := testingcoredocument.GenerateCoreDocument() coreDocument.EmbeddedData.TypeUrl = "testID_1" @@ -73,7 +58,7 @@ func TestRegistry_Register_invalidId(t *testing.T) { } func TestRegistry_LocateService_invalid(t *testing.T) { - registry := documents.GetRegistryInstance() + registry := documents.NewServiceRegistry() coreDocument := testingcoredocument.GenerateCoreDocument() coreDocument.EmbeddedData.TypeUrl = "testID_2" documentType, err := cd.GetTypeURL(coreDocument) diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 29201cd4b..d1944919e 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -12,7 +12,7 @@ import ( // initialized ONLY for tests var testLevelDB Repository -func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { +func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } @@ -20,6 +20,6 @@ func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { return b.Bootstrap(context) } -func (*Bootstrapper) TestTearDown() error { +func (Bootstrapper) TestTearDown() error { return nil } diff --git a/keytools/generate_test.go b/keytools/generate_test.go index f720e9eca..0dd9c1a7c 100644 --- a/keytools/generate_test.go +++ b/keytools/generate_test.go @@ -18,54 +18,41 @@ const ( ) func GenerateKeyFilesForTest(t *testing.T, curve string) (publicKey, privateKey []byte) { - publicFileName := "publicKeyFile" privateFileName := "privateKeyFile" - GenerateSigningKeyPair(publicFileName, privateFileName, curve) _, err := os.Stat(publicFileName) - assert.False(t, err != nil, "public key file not generated") _, err = os.Stat(privateFileName) - assert.False(t, err != nil, "private key file not generated") publicKey, err = utils.ReadKeyFromPemFile(publicFileName, utils.PublicKey) - if err != nil { log.Fatal(err) } privateKey, err = utils.ReadKeyFromPemFile(privateFileName, utils.PrivateKey) - if err != nil { log.Fatal(err) } os.Remove(publicFileName) os.Remove(privateFileName) - - return - + return publicKey, privateKey } func TestGenerateSigningKeyPairSECP256K1(t *testing.T) { - curve := CurveSecp256K1 publicKey, privateKey := GenerateKeyFilesForTest(t, curve) - assert.Equal(t, len(publicKey), PublicKeySECP256K1Len, "public key length not correct") assert.Equal(t, len(privateKey), PrivateKeySECP256K1Len, "private key length not correct") - } func TestGenerateSigningKeyPairED25519(t *testing.T) { - curve := CurveEd25519 publicKey, privateKey := GenerateKeyFilesForTest(t, curve) - assert.Equal(t, len(publicKey), PublicKeyED25519Len, "public key length not correct") assert.Equal(t, len(privateKey), PrivateKeyED25519Len, "private key length not correct") } diff --git a/keytools/sign_test.go b/keytools/sign_test.go index f44583897..a4f392d85 100644 --- a/keytools/sign_test.go +++ b/keytools/sign_test.go @@ -32,7 +32,6 @@ func TestSignMessage(t *testing.T) { os.Remove(privateKeyFile) assert.True(t, correct, "signature or verification didn't work correctly") - } func TestSignAndVerifyMessageEthereum(t *testing.T) { @@ -65,5 +64,4 @@ func TestSignAndVerifyMessageEthereum(t *testing.T) { os.Remove(privateKeyFile) assert.True(t, correct, "signature or verification didn't work correctly") - } diff --git a/keytools/verify_test.go b/keytools/verify_test.go index 7a220d7c1..d87fec21d 100644 --- a/keytools/verify_test.go +++ b/keytools/verify_test.go @@ -11,7 +11,6 @@ import ( ) func TestVerifyMessageED25519(t *testing.T) { - publicKeyFile := "publicKey" privateKeyFile := "privateKey" testMsg := "test" @@ -23,7 +22,5 @@ func TestVerifyMessageED25519(t *testing.T) { assert.NotNil(t, err) os.Remove(publicKeyFile) os.Remove(privateKeyFile) - assert.True(t, len(signature) == 0, "verify ed25519 is not implemented yet and should not work") - } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index dd9d79909..255e7fc7a 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -2,9 +2,11 @@ package nft import ( "errors" + "fmt" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -14,16 +16,21 @@ type Bootstrapper struct { } // Bootstrap initializes the payment obligation contract -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { +func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { + if _, ok := ctx[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } - setPaymentObligation(NewEthereumPaymentObligation(identity.IDService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) - return queue.InstallQueuedTask(context, newMintingConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext)) + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("service registry not initialised") + } + + setPaymentObligation(NewEthereumPaymentObligation(registry, identity.IDService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) + return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext)) } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index ff8eea00e..0d4b49967 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -56,6 +56,7 @@ type ethereumPaymentObligationContract interface { // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum type ethereumPaymentObligation struct { + registry *documents.ServiceRegistry identityService identity.Service ethClient ethereum.Client config Config @@ -64,17 +65,20 @@ type ethereumPaymentObligation struct { } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func NewEthereumPaymentObligation(identityService identity.Service, ethClient ethereum.Client, config Config, +func NewEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, setupMintListener func(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { - return ðereumPaymentObligation{identityService: identityService, + return ðereumPaymentObligation{ + registry: registry, + identityService: identityService, ethClient: ethClient, config: config, setupMintListener: setupMintListener, - bindContract: bindContract} + bindContract: bindContract, + } } func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { - docService, err := getDocumentService(documentID) + docService, err := s.registry.FindService(documentID) if err != nil { return nil, err } @@ -312,14 +316,6 @@ func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { return property, nil } -func getDocumentService(documentID []byte) (documents.Service, error) { - docService, err := documents.GetRegistryInstance().FindService(documentID) - if err != nil { - return nil, err - } - return docService, nil -} - // getCollaborator returns the needed collaboratorField for a PaymentObligation NFT // In the current contract implementation the proofField for collaborator is a separated parameter // pattern: 'collaborators' + '[i]' diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 913be149a..156efd7e6 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -194,14 +194,16 @@ func TestPaymentObligationService(t *testing.T) { "", }, } + + registry := documents.NewServiceRegistry() for _, test := range tests { t.Run(test.name, func(t *testing.T) { // get mocks docService, paymentOb, idService, ethClient, config := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton - documents.GetRegistryInstance().Register(test.name, &docService) + registry.Register(test.name, &docService) confirmations := make(chan *WatchTokenMinted) - service := NewEthereumPaymentObligation(&idService, ðClient, &config, func(tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { + service := NewEthereumPaymentObligation(registry, &idService, ðClient, &config, func(tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { return confirmations, nil }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 653e9cd1f..e1f575c5d 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,8 +8,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/log" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" @@ -18,13 +16,17 @@ import ( "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/ethereum/go-ethereum/log" "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" ) +var registry *documents.ServiceRegistry + func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") - cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap() + registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) prevSignPubkey := config.Config().Get("keys.signing.publicKey") prevSignPrivkey := config.Config().Get("keys.signing.privateKey") prevEthPubkey := config.Config().Get("keys.ethauth.publicKey") @@ -48,7 +50,7 @@ func TestPaymentObligationService_mint(t *testing.T) { testingidentity.CreateIdentityWithKeys() // create invoice (anchor) - service, err := documents.GetRegistryInstance().LocateService(documenttypes.InvoiceDataTypeUrl) + service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") contextHeader, err := documents.NewContextHeader() assert.Nil(t, err) diff --git a/p2p/handler.go b/p2p/handler.go index f890a1ab0..2aa71b56a 100644 --- a/p2p/handler.go +++ b/p2p/handler.go @@ -14,7 +14,7 @@ import ( ) // getService looks up the specific registry, derives service from core document -func getServiceAndModel(cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { +func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { if cd == nil { return nil, nil, fmt.Errorf("nil core document") } @@ -23,7 +23,7 @@ func getServiceAndModel(cd *coredocumentpb.CoreDocument) (documents.Service, doc return nil, nil, fmt.Errorf("failed to get type of the document: %v", err) } - srv, err := documents.GetRegistryInstance().LocateService(docType) + srv, err := registry.LocateService(docType) if err != nil { return nil, nil, fmt.Errorf("failed to locate the service: %v", err) } @@ -36,20 +36,27 @@ func getServiceAndModel(cd *coredocumentpb.CoreDocument) (documents.Service, doc return srv, model, nil } -// Handler implements the grpc interface -type Handler struct{} +// handler implements the grpc interface +type handler struct { + registry *documents.ServiceRegistry +} + +// GRPCHandler returns an implementation of P2PServiceServer +func GRPCHandler(registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { + return handler{registry: registry} +} // RequestDocumentSignature signs the received document and returns the signature of the signingRoot // Document signing root will be recalculated and verified // Existing signatures on the document will be verified // Document will be stored to the repository for state management -func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { +func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { err := handshakeValidator().Validate(sigReq.Header) if err != nil { return nil, err } - svc, model, err := getServiceAndModel(sigReq.Document) + svc, model, err := getServiceAndModel(srv.registry, sigReq.Document) if err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -66,13 +73,13 @@ func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb. } // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB -func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (srv handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { err := handshakeValidator().Validate(docReq.Header) if err != nil { return nil, err } - svc, model, err := getServiceAndModel(docReq.Document) + svc, model, err := getServiceAndModel(srv.registry, docReq.Document) if err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 7acc2fd80..131f61e83 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/p2p" @@ -30,11 +31,13 @@ import ( "golang.org/x/crypto/ed25519" ) -var handler = p2p.Handler{} +var handler p2ppb.P2PServiceServer func TestMain(m *testing.M) { - cc.TestFunctionalEthereumBootstrap() flag.Parse() + ctx := cc.TestFunctionalEthereumBootstrap() + registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + handler = p2p.GRPCHandler(registry) config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/p2p/handler_test.go b/p2p/handler_test.go index e72450230..070ed6183 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -28,22 +28,25 @@ import ( ) var ( - handler = Handler{} + grpcHandler p2ppb.P2PServiceServer + registry *documents.ServiceRegistry + coreDoc = testingcoredocument.GenerateCoreDocument() + cfg *config.Configuration + testClient *p2pServer ) -var coreDoc = testingcoredocument.GenerateCoreDocument() -var ctx = map[string]interface{}{} -var cfg *config.Configuration -var testClient *p2pServer - func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + documents.Bootstrapper{}, } + ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + grpcHandler = GRPCHandler(registry) testClient = &p2pServer{config: cfg} result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -55,7 +58,7 @@ func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID(), }} - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) assert.Error(t, err, "must return error") assert.Nil(t, resp, "must be nil") } @@ -65,7 +68,7 @@ func TestHandler_RequestDocumentSignature_version_fail(t *testing.T) { CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: config.Config().GetNetworkID(), }} - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "Incompatible version") assert.Nil(t, resp, "must be nil") @@ -78,7 +81,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { NetworkIdentifier: config.Config().GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Document: coreDoc, Header: header} - res, err := handler.SendAnchoredDocument(context.Background(), &req) + res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) assert.Error(t, err) p2perr, _ := centerrors.FromError(err) assert.Contains(t, p2perr.Message(), strconv.Itoa(int(code.VersionMismatch))) @@ -87,7 +90,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { // Test invalid network header.NetworkIdentifier = config.Config().GetNetworkID() + 1 header.CentNodeVersion = version.GetVersion().String() - res, err = handler.SendAnchoredDocument(context.Background(), &req) + res, err = grpcHandler.SendAnchoredDocument(context.Background(), &req) assert.Error(t, err) p2perr, _ = centerrors.FromError(err) assert.Contains(t, p2perr.Message(), strconv.Itoa(int(code.NetworkMismatch))) @@ -100,7 +103,7 @@ func TestSendAnchoredDocument_NilDocument(t *testing.T) { NetworkIdentifier: config.Config().GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Header: header} - res, err := handler.SendAnchoredDocument(context.Background(), &req) + res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) assert.Error(t, err) assert.Nil(t, res) @@ -115,7 +118,7 @@ func TestHandler_SendAnchoredDocument_getServiceAndModel_fail(t *testing.T) { Document: coredocument.New(), } - res, err := handler.SendAnchoredDocument(context.Background(), req) + res, err := grpcHandler.SendAnchoredDocument(context.Background(), req) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get type of the document") assert.Nil(t, res) @@ -182,12 +185,12 @@ func (s mockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (do func Test_getServiceAndModel(t *testing.T) { // document nil fail - s, m, err := getServiceAndModel(nil) + s, m, err := getServiceAndModel(registry, nil) assert.Error(t, err) // docType fetch fail cd := coredocument.New() - s, m, err = getServiceAndModel(cd) + s, m, err = getServiceAndModel(registry, cd) assert.Error(t, err) assert.Nil(t, s) assert.Nil(t, m) @@ -198,19 +201,18 @@ func Test_getServiceAndModel(t *testing.T) { TypeUrl: "model_type_fail", Value: []byte("some data"), } - s, m, err = getServiceAndModel(cd) + s, m, err = getServiceAndModel(registry, cd) assert.Error(t, err) assert.Nil(t, s) assert.Nil(t, m) assert.Contains(t, err.Error(), "failed to locate the service") // derive fails - reg := documents.GetRegistryInstance() srv := mockService{} srv.On("DeriveFromCoreDocument", cd).Return(nil, fmt.Errorf("error")).Once() - err = reg.Register(cd.EmbeddedData.TypeUrl, srv) + err = registry.Register(cd.EmbeddedData.TypeUrl, srv) assert.Nil(t, err) - s, m, err = getServiceAndModel(cd) + s, m, err = getServiceAndModel(registry, cd) srv.AssertExpectations(t) assert.Error(t, err) assert.Nil(t, s) @@ -222,9 +224,9 @@ func Test_getServiceAndModel(t *testing.T) { cd.EmbeddedData.TypeUrl = "get_model_type" srv = mockService{} srv.On("DeriveFromCoreDocument", cd).Return(model, nil).Once() - err = reg.Register(cd.EmbeddedData.TypeUrl, srv) + err = registry.Register(cd.EmbeddedData.TypeUrl, srv) assert.Nil(t, err) - s, m, err = getServiceAndModel(cd) + s, m, err = getServiceAndModel(registry, cd) srv.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, s) diff --git a/p2p/server.go b/p2p/server.go index f5632973b..4ac3d42af 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -67,10 +67,13 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch // Set the grpc protocol handler on it s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) - p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), &Handler{}) - go func(proto *p2pgrpc.GRPCProtocol) { - proto.Serve() - }(s.protocol) + p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), &handler{}) + + serveErr := make(chan error) + go func() { + err := s.protocol.Serve() + serveErr <- err + }() s.host.Peerstore().AddAddr(s.host.ID(), s.host.Addrs()[0], pstore.TempAddrTTL) @@ -79,6 +82,11 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch for { select { + case err := <-serveErr: + log.Infof("GRPC server error: %v", err) + s.protocol.GetGRPCServer().GracefulStop() + log.Info("GRPC server stopped") + return case <-ctx.Done(): log.Info("Shutting down GRPC server") s.protocol.GetGRPCServer().GracefulStop() From 1f2df5722e780ff8effd83f9f1fb0cc2ae810f65 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 19 Nov 2018 11:25:44 +0100 Subject: [PATCH 030/220] Refactor stateful methods into identity.Service interface (#410) * Refactor stateful methods into ethereum.Client interface * State save tests fail * Fixing processor tests * More tests * Fix tests * Fix tests * Fix tests * Fix tests * Fix tests * Fix tests * Missing build tag --- anchors/bootstrapper.go | 2 +- anchors/ethereum_anchor_repository.go | 7 +- anchors/ethereum_anchor_repository_test.go | 8 +- api/server_test.go | 2 +- cmd/create_config.go | 6 +- cmd/manage_identities.go | 2 +- coredocument/coredocument_test.go | 1 - coredocument/processor.go | 13 +- coredocument/processor_test.go | 94 ++-- coredocument/validator.go | 23 +- coredocument/validator_test.go | 38 +- documents/invoice/bootstrapper.go | 2 +- documents/invoice/service.go | 14 +- documents/invoice/service_test.go | 9 +- documents/purchaseorder/bootstrapper.go | 2 +- documents/purchaseorder/service.go | 14 +- documents/purchaseorder/service_test.go | 7 +- ethereum/geth_client.go | 48 +- ethereum/geth_client_test.go | 2 +- identity/bootstrapper.go | 11 +- identity/ethereum_identity.go | 216 +++++++-- .../ethereum_identity_integration_test.go | 4 +- identity/ethereum_identity_test.go | 455 ++++++++++++++++++ identity/identity.go | 133 ++--- identity/identity_test.go | 240 --------- .../key_registration_confirmation_task.go | 14 +- p2p/client.go | 19 +- p2p/client_test.go | 6 +- p2p/handler_integration_test.go | 83 +--- signatures/signatures.go | 42 +- signatures/signatures_test.go | 52 +- testingutils/commons/mock_ethclient.go | 8 + testingutils/commons/mock_identity.go | 34 ++ 33 files changed, 896 insertions(+), 715 deletions(-) create mode 100644 identity/ethereum_identity_test.go diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 2ea3cc5a0..946762063 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -30,7 +30,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - anchorRepo := NewEthereumAnchorRepository(cfg, repositoryContract) + anchorRepo := NewEthereumAnchorRepository(cfg, repositoryContract, ethereum.GetClient) setAnchorRepository(anchorRepo) if err != nil { return err diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 74b060536..724c196db 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -39,16 +39,17 @@ type WatchAnchorCommitted interface { type EthereumAnchorRepository struct { config Config anchorRepositoryContract AnchorRepositoryContract + gethClientFinder func() ethereum.Client } -func NewEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorRepositoryContract) *EthereumAnchorRepository { - return &EthereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract} +func NewEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorRepositoryContract, gethClientFinder func() ethereum.Client) *EthereumAnchorRepository { + return &EthereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder} } // Commits takes an anchorID and returns the corresponding documentRoot from the chain func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetGethCallOpts() + opts, _ := ethRepository.gethClientFinder().GetGethCallOpts() return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) } diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index a71fa9f58..85691d4fd 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -7,8 +7,10 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/hexutil" @@ -77,7 +79,11 @@ func TestGetDocumentRootOf(t *testing.T) { anchorID, err := ToAnchorID(utils.RandomSlice(32)) assert.Nil(t, err) - ethRepo := NewEthereumAnchorRepository(config.Config(), repo) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetGethCallOpts").Return(nil) + ethRepo := NewEthereumAnchorRepository(config.Config(), repo, func() ethereum.Client { + return ethClient + }) docRoot := utils.RandomByte32() repo.On("Commits", mock.Anything, mock.Anything).Return(docRoot, nil) gotRoot, err := ethRepo.GetDocumentRootOf(anchorID) diff --git a/api/server_test.go b/api/server_test.go index 3ac568fb6..339e19ef7 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -48,7 +48,7 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil)) + registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil, nil)) capi := apiServer{config: cfg, registry: registry} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error) diff --git a/cmd/create_config.go b/cmd/create_config.go index 84fb61549..84d102fc2 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -39,15 +39,15 @@ func generateKeys() { } func addKeys() error { - err := identity.AddKeyFromConfig(identity.KeyPurposeP2P) + err := identity.IDService.AddKeyFromConfig(identity.KeyPurposeP2P) if err != nil { panic(err) } - err = identity.AddKeyFromConfig(identity.KeyPurposeSigning) + err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeSigning) if err != nil { panic(err) } - err = identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) if err != nil { panic(err) } diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 9363ef4e1..165e2a042 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -68,7 +68,7 @@ var addKeyCmd = &cobra.Command{ panic("Option not supported") } - err := identity.AddKeyFromConfig(purposeInt) + err := identity.IDService.AddKeyFromConfig(purposeInt) if err != nil { panic(err) } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 9ded8d43e..e0eab27ae 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -38,7 +38,6 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - dp = DefaultProcessor(nil, nil, nil, cfg).(defaultProcessor) flag.Parse() cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/coredocument/processor.go b/coredocument/processor.go index b346bd390..22ecdac12 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" logging "github.com/ipfs/go-log" @@ -40,7 +39,7 @@ type Processor interface { // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { OpenClient(target string) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // defaultProcessor implements Processor interface @@ -124,7 +123,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) er if err != nil { return fmt.Errorf("failed to get keys for signing: %v", err) } - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) @@ -149,7 +148,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model document return fmt.Errorf("failed to validate model for signature request: %v", err) } - err = dp.p2pClient.GetSignaturesForDocument(ctx, cd) + err = dp.p2pClient.GetSignaturesForDocument(ctx, dp.identityService, cd) if err != nil { return fmt.Errorf("failed to collect signatures from the collaborators: %v", err) } @@ -169,7 +168,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { return fmt.Errorf("failed to pack core document: %v", err) } - psv := PostSignatureRequestValidator() + psv := PostSignatureRequestValidator(dp.identityService) err = psv.Validate(nil, model) if err != nil { return fmt.Errorf("failed to validate signatures: %v", err) @@ -195,7 +194,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("failed to pack core document: %v", err) } - pav := PreAnchorValidator() + pav := PreAnchorValidator(dp.identityService) err = pav.Validate(nil, model) if err != nil { return fmt.Errorf("pre anchor validation failed: %v", err) @@ -250,7 +249,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Mod return fmt.Errorf("failed to pack core document: %v", err) } - av := PostAnchoredValidator(dp.anchorRepository) + av := PostAnchoredValidator(dp.identityService, dp.anchorRepository) err = av.Validate(nil, model) if err != nil { return fmt.Errorf("post anchor validations failed: %v", err) diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 7ae682728..6bdd2cbff 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -5,14 +5,12 @@ package coredocument import ( "context" "fmt" - "math/big" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/ptypes/any" @@ -21,9 +19,8 @@ import ( "golang.org/x/crypto/ed25519" ) -var dp defaultProcessor - func TestCoreDocumentProcessor_SendNilDocument(t *testing.T) { + dp := DefaultProcessor(nil, nil, nil, cfg) err := dp.Send(nil, nil, [identity.CentIDLength]byte{}) assert.Error(t, err, "should have thrown an error") } @@ -45,6 +42,8 @@ func (m mockModel) UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error { } func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { + srv := &testingcommons.MockIDService{} + dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() @@ -104,12 +103,14 @@ type p2pClient struct { client } -func (p p2pClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { +func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { args := p.Called(ctx, doc) return args.Error(0) } func TestDefaultProcessor_RequestSignatures(t *testing.T) { + srv := &testingcommons.MockIDService{} + dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed ctx := context.Background() model := mockModel{} @@ -180,6 +181,8 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { } func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { + srv := &testingcommons.MockIDService{} + dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() @@ -212,24 +215,14 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) - idkey := &identity.EthereumIdentityKey{ - Key: pubkey, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + dp = DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unpack core document") @@ -237,15 +230,9 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(nil).Once() - id = &testingcommons.MockID{} - srv = &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, cd.DocumentRoot) } @@ -268,6 +255,8 @@ func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.Document } func TestDefaultProcessor_AnchorDocument(t *testing.T) { + srv := &testingcommons.MockIDService{} + dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() @@ -298,27 +287,16 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Times(5) c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} assert.Nil(t, CalculateDocumentRoot(cd)) - pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) assert.Nil(t, err) - idkey := &identity.EthereumIdentityKey{ - Key: pubkey, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() oldID := cfg.GetString("identityId") cfg.Set("identityId", "wrong id") err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get self cent ID") cfg.Set("identityId", "0x0102030405060708") @@ -326,13 +304,11 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // wrong ID model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() + err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "centID invalid") cfg.Set("identityId", oldID) @@ -342,13 +318,11 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { cfg.Set("keys.ethauth.publicKey", "wrong path") model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() + err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get eth keys") cfg.Set("keys.ethauth.publicKey", oldPth) @@ -356,16 +330,14 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // failed anchor commit model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() + repo := mockRepo{} repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error")).Once() dp.anchorRepository = repo err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) repo.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to commit anchor") @@ -373,9 +345,8 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // success model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() + repo = mockRepo{} ch := make(chan *anchors.WatchCommit, 1) ch <- new(anchors.WatchCommit) @@ -384,12 +355,14 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { err = dp.AnchorDocument(model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) repo.AssertExpectations(t) assert.Nil(t, err) } func TestDefaultProcessor_SendDocument(t *testing.T) { + srv := &testingcommons.MockIDService{} + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() // pack failed @@ -423,21 +396,9 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Times(6) c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} assert.Nil(t, CalculateDocumentRoot(cd)) - pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) - assert.Nil(t, err) - idkey := &identity.EthereumIdentityKey{ - Key: pubkey, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) assert.Nil(t, err) repo := mockRepo{} @@ -446,7 +407,6 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { err = dp.SendDocument(ctx, model) model.AssertExpectations(t) srv.AssertExpectations(t) - id.AssertExpectations(t) repo.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") diff --git a/coredocument/validator.go b/coredocument/validator.go index b8fd95713..3d8ef63d3 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -217,7 +216,7 @@ func readyForSignaturesValidator() documents.Validator { return fmt.Errorf("failed to get keys for signature calculation: %v", err) } - s := signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { err = documents.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) @@ -239,7 +238,7 @@ func readyForSignaturesValidator() documents.Validator { // assumes signing root is verified // Note: can be used when during the signature request on collaborator side and post signature collection on sender side // Note: this will break the current flow where we proceed to anchor even signatures verification fails -func signaturesValidator() documents.Validator { +func signaturesValidator(idService identity.Service) documents.Validator { return documents.ValidatorFunc(func(_, model documents.Model) error { cd, err := getCoreDocument(model) if err != nil { @@ -251,7 +250,7 @@ func signaturesValidator() documents.Validator { } for _, sig := range cd.Signatures { - if errI := signatures.ValidateSignature(sig, cd.SigningRoot); errI != nil { + if errI := idService.ValidateSignature(sig, cd.SigningRoot); errI != nil { err = documents.AppendError( err, documents.NewError(fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), "signature verification failed")) @@ -299,8 +298,8 @@ func anchoredValidator(repo anchors.AnchorRepository) documents.Validator { // signing root validator // signatures validator // should be used when node receives a document requesting for signature -func SignatureRequestValidator() documents.ValidatorGroup { - return PostSignatureRequestValidator() +func SignatureRequestValidator(idService identity.Service) documents.ValidatorGroup { + return PostSignatureRequestValidator(idService) } // PreAnchorValidator is a validator group with following validators @@ -309,9 +308,9 @@ func SignatureRequestValidator() documents.ValidatorGroup { // document root validator // signatures validator // should be called before pre anchoring -func PreAnchorValidator() documents.ValidatorGroup { +func PreAnchorValidator(idService identity.Service) documents.ValidatorGroup { return documents.ValidatorGroup{ - PostSignatureRequestValidator(), + PostSignatureRequestValidator(idService), documentRootValidator(), } } @@ -320,9 +319,9 @@ func PreAnchorValidator() documents.ValidatorGroup { // PreAnchorValidator // anchoredValidator // should be called after anchoring the document/when received anchored document -func PostAnchoredValidator(repo anchors.AnchorRepository) documents.ValidatorGroup { +func PostAnchoredValidator(idService identity.Service, repo anchors.AnchorRepository) documents.ValidatorGroup { return documents.ValidatorGroup{ - PreAnchorValidator(), + PreAnchorValidator(idService), anchoredValidator(repo), } } @@ -345,10 +344,10 @@ func PreSignatureRequestValidator() documents.ValidatorGroup { // signingRootValidator // signaturesValidator // should be called after the signature collection/before preparing for anchoring -func PostSignatureRequestValidator() documents.ValidatorGroup { +func PostSignatureRequestValidator(idService identity.Service) documents.ValidatorGroup { return documents.ValidatorGroup{ baseValidator(), signingRootValidator(), - signaturesValidator(), + signaturesValidator(idService), } } diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index acb56aeee..0cc7e24f8 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -4,15 +4,15 @@ package coredocument import ( "fmt" - "math/big" "testing" + "errors" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/ptypes/any" @@ -244,7 +244,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { cd.SigningRoot = utils.RandomSlice(32) c, err := identity.GetIdentityConfig() assert.Nil(t, err) - s = signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() @@ -254,7 +254,8 @@ func TestValidator_selfSignatureValidator(t *testing.T) { } func TestValidator_signatureValidator(t *testing.T) { - ssv := signaturesValidator() + srv := &testingcommons.MockIDService{} + ssv := signaturesValidator(srv) // fail getCoreDoc model := mockModel{} @@ -276,6 +277,7 @@ func TestValidator_signatureValidator(t *testing.T) { // failed validation model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("fail")).Once() s := &coredocumentpb.Signature{EntityId: utils.RandomSlice(7)} cd.Signatures = append(cd.Signatures, s) err = ssv.Validate(nil, model) @@ -286,32 +288,18 @@ func TestValidator_signatureValidator(t *testing.T) { // success model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() cd.SigningRoot = utils.RandomSlice(32) - c, err := identity.GetIdentityConfig() - assert.Nil(t, err) - s = signatures.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} - pubkey, err := utils.SliceToByte32(c.Keys[identity.KeyPurposeSigning].PublicKey) - assert.Nil(t, err) - idkey := &identity.EthereumIdentityKey{ - Key: pubkey, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", c.ID).Return(id, nil).Once() - id.On("FetchKey", pubkey[:]).Return(idkey, nil).Once() - identity.IDService = srv + cd.Signatures = []*coredocumentpb.Signature{{}} + err = ssv.Validate(nil, model) model.AssertExpectations(t) - id.AssertExpectations(t) srv.AssertExpectations(t) assert.Nil(t, err) } func TestPreAnchorValidator(t *testing.T) { - pav := PreAnchorValidator() + pav := PreAnchorValidator(nil) assert.Len(t, pav, 2) } @@ -541,7 +529,7 @@ func TestValidate_baseValidator(t *testing.T) { } func TestPostAnchoredValidator(t *testing.T) { - pav := PostAnchoredValidator(nil) + pav := PostAnchoredValidator(nil, nil) assert.Len(t, pav, 2) } @@ -551,11 +539,11 @@ func TestPreSignatureRequestValidator(t *testing.T) { } func TestPostSignatureRequestValidator(t *testing.T) { - psv := PostSignatureRequestValidator() + psv := PostSignatureRequestValidator(nil) assert.Len(t, psv, 3) } func TestSignatureRequestValidator(t *testing.T) { - srv := SignatureRequestValidator() + srv := SignatureRequestValidator(nil) assert.Len(t, srv, 3) } diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index c2ad627b0..93d00d01f 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -39,7 +39,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository(), identity.IDService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index a2b4d5e56..9364d8ea0 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -18,7 +18,6 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -56,11 +55,12 @@ type service struct { coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository + identityService identity.Service } // DefaultService returns the default implementation of the service -func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository} +func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } // CreateProofs creates proofs for the latest version document given the fields @@ -90,7 +90,7 @@ func (s service) invoiceProof(model documents.Model, fields []string) (*document return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") } - if err := coredocument.PostAnchoredValidator(s.anchorRepository).Validate(nil, inv); err != nil { + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, inv); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } coreDoc, proofs, err := inv.createProofs(fields) @@ -328,7 +328,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP // RequestDocumentSignature Validates, Signs document received over the p2p layer and returs Signature func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentpb.Signature, error) { - if err := coredocument.SignatureRequestValidator().Validate(nil, model); err != nil { + if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -344,7 +344,7 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) } - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { @@ -362,7 +362,7 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp // ReceiveAnchoredDocument receives a new anchored document, validates and updates the document in DB func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { - if err := coredocument.PostAnchoredValidator(s.anchorRepository).Validate(nil, model); err != nil { + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return centerrors.New(code.DocumentInvalid, err.Error()) } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 02b148a32..7d801f7d8 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -16,7 +16,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -44,12 +43,14 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil) + srv := DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() Service { - return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + idService := &testingcommons.MockIDService{} + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func createMockDocument() (*Invoice, error) { @@ -436,7 +437,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { }, } - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) corDoc.Signatures = append(corDoc.Signatures, sig) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 426c62f69..0a9ca3182 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -38,7 +38,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository()) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository(), identity.IDService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 535e84a79..afed7b8f7 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -18,7 +18,6 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -56,11 +55,12 @@ type service struct { coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository + identityService identity.Service } // DefaultService returns the default implementation of the service -func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository} +func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } // DeriveFromCoreDocument takes a core document and returns a purchase order @@ -291,7 +291,7 @@ func (s service) purchaseOrderProof(model documents.Model, fields []string) (*do if !ok { return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") } - if err := coredocument.PostAnchoredValidator(s.anchorRepository).Validate(nil, po); err != nil { + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, po); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } coreDoc, proofs, err := po.createProofs(fields) @@ -327,7 +327,7 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentpb.Signature, error) { - if err := coredocument.SignatureRequestValidator().Validate(nil, model); err != nil { + if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -343,7 +343,7 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) } - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { @@ -363,7 +363,7 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { - if err := coredocument.PostAnchoredValidator(s.anchorRepository).Validate(nil, model); err != nil { + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return centerrors.New(code.DocumentInvalid, err.Error()) } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 9c954558d..86f116a4a 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -42,7 +41,9 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func getServiceWithMockedLayers() Service { - return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}) + idService := &testingcommons.MockIDService{} + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func TestService_Update(t *testing.T) { @@ -343,7 +344,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er }, } - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) corDoc.Signatures = append(corDoc.Signatures, sig) diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index fe88007b1..478db0eb3 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -35,12 +35,6 @@ func GetDefaultContextTimeout() time.Duration { return config.Config().GetEthereumContextWaitTimeout() } -// defaultReadContext returns context with timeout for read operations -func defaultReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { - toBeDone := time.Now().Add(config.Config().GetEthereumContextReadWaitTimeout()) - return context.WithDeadline(context.Background(), toBeDone) -} - // DefaultWaitForTransactionMiningContext returns context with timeout for write operations func DefaultWaitForTransactionMiningContext() (ctx context.Context, cancelFunc context.CancelFunc) { toBeDone := time.Now().Add(GetDefaultContextTimeout()) @@ -56,14 +50,32 @@ type Config interface { GetEthereumIntervalRetry() time.Duration GetEthereumMaxRetries() int GetTxPoolAccessEnabled() bool + GetEthereumContextReadWaitTimeout() time.Duration } // Client can be implemented by any chain client type Client interface { + + // GetEthClient returns the ethereum client GetEthClient() *ethclient.Client + + // GetNodeURL returns the node url GetNodeURL() *url.URL + + // GetTxOpts returns a cached options if available else creates and returns new options GetTxOpts(accountName string) (*bind.TransactOpts, error) + + // SubmitTransactionWithRetries submits transaction to the ethereum chain + // Blocking Function that sends transaction using reflection wrapped in a retrial block. It is based on the transactionUnderpriced error, + // meaning that a transaction is being attempted to run twice, and the logic is to override the existing one. As we have constant + // gas prices that means that a concurrent transaction race condition event has happened. + // - contractMethod: Contract Method that implements GenericEthereumAsset (usually autogenerated binding from abi) + // - params: Arbitrary number of parameters that are passed to the function fname call + // Note: contractMethod must always return "*types.Transaction, error" SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) + + // GetGethCallOpts returns the Call options with default + GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) } // gethClient implements Client for Ethereum @@ -118,6 +130,12 @@ func GetClient() Client { return gc } +// defaultReadContext returns context with timeout for read operations +func (gc *gethClient) defaultReadContext() (ctx context.Context, cancelFunc context.CancelFunc) { + toBeDone := time.Now().Add(gc.config.GetEthereumContextReadWaitTimeout()) + return context.WithDeadline(context.Background(), toBeDone) +} + // GetTxOpts returns a cached options if available else creates and returns new options func (gc *gethClient) GetTxOpts(accountName string) (*bind.TransactOpts, error) { gc.accMu.Lock() @@ -230,6 +248,15 @@ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, o } +// GetGethCallOpts returns the Call options with default +func (gc *gethClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { + // Assuring that pending transactions are taken into account by go-ethereum when asking for things like + // specific transactions and client's nonce + // with timeout context, in case eth node is not in sync + ctx, cancel := gc.defaultReadContext() + return &bind.CallOpts{Pending: true, Context: ctx}, cancel +} + // noncer defines functions to get the next nonce type noncer interface { PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) @@ -297,12 +324,3 @@ func incrementNonce(opts *bind.TransactOpts, txpoolAccessEnabled bool, noncer no return nil } - -// GetGethCallOpts returns the Call options with default -func GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { - // Assuring that pending transactions are taken into account by go-ethereum when asking for things like - // specific transactions and client's nonce - // with timeout context, in case eth node is not in sync - ctx, cancel := defaultReadContext() - return &bind.CallOpts{Pending: true, Context: ctx}, cancel -} diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index 32880c21d..0782a97b1 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -97,7 +97,7 @@ func TestInitTransactionWithRetries(t *testing.T) { } func TestGetGethCallOpts(t *testing.T) { - opts, cancel := GetGethCallOpts() + opts, cancel := GetClient().GetGethCallOpts() assert.NotNil(t, opts) assert.True(t, opts.Pending) assert.NotNil(t, cancel) diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 2b7cd68ca..e5ac454bd 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ) @@ -35,7 +36,10 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - IDService = NewEthereumIdentityService(cfg, idFactory, registryContract) + IDService = NewEthereumIdentityService(cfg, idFactory, registryContract, ethereum.GetClient, + func(address common.Address, backend bind.ContractBackend) (contract, error) { + return NewEthereumIdentityContract(address, backend) + }) err = queue.InstallQueuedTask(context, newIdRegistrationConfirmationTask(&idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) @@ -44,7 +48,10 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } err = queue.InstallQueuedTask(context, - newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg)) + newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg, ethereum.GetClient, + func(address common.Address, backend bind.ContractBackend) (contract, error) { + return NewEthereumIdentityContract(address, backend) + })) if err != nil { return err } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index eb81c0810..9080152c3 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -5,9 +5,14 @@ import ( "fmt" "math/big" + "bytes" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -23,8 +28,22 @@ type factory interface { CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) } +type registry interface { + GetIdentityByCentrifugeId(opts *bind.CallOpts, bigInt *big.Int) (common.Address, error) +} + type contract interface { AddKey(opts *bind.TransactOpts, _key [32]byte, _kPurpose *big.Int) (*types.Transaction, error) + + GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) + + GetKey(opts *bind.CallOpts, _key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }, error) + + FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) } type Config interface { @@ -61,13 +80,17 @@ func (idk *EthereumIdentityKey) String() string { type ethereumIdentity struct { centID CentID - contract *EthereumIdentityContract - registryContract *EthereumIdentityRegistryContract + contract contract + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) + registryContract registry config Config + gethClientFinder func() ethereum.Client } -func newEthereumIdentity(id CentID, registryContract *EthereumIdentityRegistryContract, config Config) *ethereumIdentity { - return ðereumIdentity{centID: id, registryContract: registryContract, config: config} +func newEthereumIdentity(id CentID, registryContract registry, config Config, + gethClientFinder func() ethereum.Client, + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) *ethereumIdentity { + return ðereumIdentity{centID: id, registryContract: registryContract, config: config, gethClientFinder: gethClientFinder, contractProvider: contractProvider} } // CentrifugeID sets the CentID to the Identity @@ -106,7 +129,7 @@ func (id *ethereumIdentity) FetchKey(key []byte) (Key, error) { return nil, err } // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetGethCallOpts() + opts, _ := id.gethClientFinder().GetGethCallOpts() key32, _ := utils.SliceToByte32(key) keyInstance, err := contract.GetKey(opts, key32) if err != nil { @@ -141,8 +164,9 @@ func (id *ethereumIdentity) findContract() (exists bool, err error) { return true, nil } + client := id.gethClientFinder() // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetGethCallOpts() + opts, _ := client.GetGethCallOpts() idAddress, err := id.registryContract.GetIdentityByCentrifugeId(opts, id.centID.BigInt()) if err != nil { return false, err @@ -151,8 +175,7 @@ func (id *ethereumIdentity) findContract() (exists bool, err error) { return false, errors.New("Identity not found by address provided") } - client := ethereum.GetClient() - idContract, err := NewEthereumIdentityContract(idAddress, client.GetEthClient()) + idContract, err := id.contractProvider(idAddress, client.GetEthClient()) if err == bind.ErrNoCode { return false, err } @@ -164,7 +187,7 @@ func (id *ethereumIdentity) findContract() (exists bool, err error) { return true, nil } -func (id *ethereumIdentity) getContract() (contract *EthereumIdentityContract, err error) { +func (id *ethereumIdentity) getContract() (contract contract, err error) { if id.contract == nil { _, err := id.findContract() if err != nil { @@ -175,11 +198,6 @@ func (id *ethereumIdentity) getContract() (contract *EthereumIdentityContract, e return id.contract, nil } -// CheckIdentityExists checks if the identity represented by id actually exists on ethereum -func (id *ethereumIdentity) CheckIdentityExists() (exists bool, err error) { - return id.findContract() -} - // AddKeyToIdentity adds key to the purpose on chain func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) { if utils.IsEmptyByteSlice(key) || len(key) > 32 { @@ -193,7 +211,7 @@ func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int return confirmations, err } - conn := ethereum.GetClient() + conn := id.gethClientFinder() opts, err := ethereum.GetClient().GetTxOpts(id.config.GetEthereumDefaultAccountName()) if err != nil { return confirmations, err @@ -229,7 +247,7 @@ func (id *ethereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdenti return nil, err } // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetGethCallOpts() + opts, _ := id.gethClientFinder().GetGethCallOpts() bigInt := big.NewInt(int64(keyPurpose)) keys, err := contract.GetKeysByPurpose(opts, bigInt) if err != nil { @@ -333,27 +351,48 @@ func waitAndRouteIdentityRegistrationEvent(asyncRes *gocelery.AsyncResult, confi // EthereumidentityService implements `Service` type EthereumIdentityService struct { config Config - factoryContract *EthereumIdentityFactoryContract - registryContract *EthereumIdentityRegistryContract + factoryContract factory + registryContract registry + gethClientFinder func() ethereum.Client + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) } // NewEthereumIdentityService creates a new NewEthereumIdentityService given the config and the smart contracts -func NewEthereumIdentityService(config Config, factoryContract *EthereumIdentityFactoryContract, registryContract *EthereumIdentityRegistryContract) Service { - return &EthereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract} +func NewEthereumIdentityService(config Config, factoryContract factory, registryContract registry, + gethClientFinder func() ethereum.Client, + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) Service { + return &EthereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider} } // CheckIdentityExists checks if the identity represented by id actually exists on ethereum func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (exists bool, err error) { - id := newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) - exists, err = id.CheckIdentityExists() - return + client := ids.gethClientFinder() + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := client.GetGethCallOpts() + idAddress, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centrifugeID.BigInt()) + if err != nil { + return false, err + } + if utils.IsEmptyByteSlice(idAddress.Bytes()) { + return false, errors.New("Identity not found by address provided") + } + + _, err = NewEthereumIdentityContract(idAddress, client.GetEthClient()) + if err == bind.ErrNoCode { + return false, err + } + if err != nil { + log.Errorf("Failed to instantiate the identity contract: %v", err) + return false, err + } + return true, nil } // CreateIdentity creates an identity representing the id on ethereum func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) - id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) - conn := ethereum.GetClient() + id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.gethClientFinder, ids.contractProvider) + conn := ids.gethClientFinder() opts, err := conn.GetTxOpts(ids.config.GetEthereumDefaultAccountName()) if err != nil { return nil, confirmations, err @@ -383,7 +422,7 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Address, error) { // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetGethCallOpts() + opts, _ := ethereum.GetClient().GetGethCallOpts() address, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centID.BigInt()) if err != nil { return common.Address{}, err @@ -397,15 +436,130 @@ func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Ad // LookupIdentityForID looks up if the identity for given CentID exists on ethereum func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Identity, error) { - id := newEthereumIdentity(centrifugeID, ids.registryContract, ids.config) - exists, err := id.CheckIdentityExists() + exists, err := ids.CheckIdentityExists(centrifugeID) if !exists { - return id, fmt.Errorf("identity [%s] does not exist with err [%v]", id.centID, err) + return nil, fmt.Errorf("identity [%s] does not exist with err [%v]", centrifugeID, err) + } + + if err != nil { + return nil, err + } + return newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.gethClientFinder, ids.contractProvider), nil +} + +// GetClientP2PURL returns the p2p url associated with the centID +func (ids *EthereumIdentityService) GetClientP2PURL(centID CentID) (url string, err error) { + target, err := ids.LookupIdentityForID(centID) + if err != nil { + return url, centerrors.Wrap(err, "error fetching receiver identity") + } + + p2pKey, err := target.CurrentP2PKey() + if err != nil { + return url, centerrors.Wrap(err, "error fetching p2p key") + } + + return fmt.Sprintf("/ipfs/%s", p2pKey), nil +} + +// GetClientsP2PURLs returns p2p urls associated with each centIDs +// will error out at first failure +func (ids *EthereumIdentityService) GetClientsP2PURLs(centIDs []CentID) ([]string, error) { + var p2pURLs []string + for _, id := range centIDs { + url, err := ids.GetClientP2PURL(id) + if err != nil { + return nil, err + } + + p2pURLs = append(p2pURLs, url) + } + + return p2pURLs, nil +} + +// GetIdentityKey returns the key for provided identity +func (ids *EthereumIdentityService) GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) { + id, err := ids.LookupIdentityForID(identity) + if err != nil { + return keyInfo, err + } + + key, err := id.FetchKey(pubKey) + if err != nil { + return keyInfo, err + } + + if utils.IsEmptyByte32(key.GetKey()) { + return keyInfo, fmt.Errorf(fmt.Sprintf("key not found for identity: %x", identity)) + } + + return key, nil +} + +// ValidateKey checks if a given key is valid for the given centrifugeID. +func (ids *EthereumIdentityService) ValidateKey(centrifugeId CentID, key []byte, purpose int) error { + idKey, err := ids.GetIdentityKey(centrifugeId, key) + if err != nil { + return err + } + + if !bytes.Equal(key, utils.Byte32ToSlice(idKey.GetKey())) { + return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't match", idKey.GetKey())) + } + + if !utils.ContainsBigIntInSlice(big.NewInt(int64(purpose)), idKey.GetPurposes()) { + return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't have purpose [%d]", idKey.GetKey(), purpose)) + } + + if idKey.GetRevokedAt().Cmp(big.NewInt(0)) != 0 { + return fmt.Errorf(fmt.Sprintf("[Key: %x] Key is currently revoked since block [%d]", idKey.GetKey(), idKey.GetRevokedAt())) + } + + return nil +} + +// AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file +func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { + identityConfig, err := GetIdentityConfig() + if err != nil { + return err + } + + id, err := ids.LookupIdentityForID(identityConfig.ID) + if err != nil { + return err } + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() + defer cancel() + confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) if err != nil { - return id, err + return err + } + watchAddedToIdentity := <-confirmations + + lastKey, errLocal := watchAddedToIdentity.Identity.LastKeyForPurpose(purpose) + if errLocal != nil { + return err + } + + log.Infof("Key [%v] with type [$s] Added to Identity [%s]", lastKey, purpose, watchAddedToIdentity.Identity) + + return nil +} + +// ValidateSignature validates a signature on a message based on identity data +func (ids *EthereumIdentityService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { + centID, err := ToCentID(signature.EntityId) + if err != nil { + return err + } + + err = ids.ValidateKey(centID, signature.PublicKey, KeyPurposeSigning) + if err != nil { + return err } - return id, nil + return signatures.VerifySignature(signature.PublicKey, message, signature.Signature) } diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 34cff58f2..84923bb4b 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -90,7 +90,7 @@ func TestAddKeyFromConfig(t *testing.T) { assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - err = identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") config.Config().Set("identityId", defaultCentrifugeId) @@ -103,7 +103,7 @@ func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - err := identity.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err := identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.NotNil(t, err, "should error out") config.Config().Set("identityId", defaultCentrifugeId) diff --git a/identity/ethereum_identity_test.go b/identity/ethereum_identity_test.go new file mode 100644 index 000000000..465679f20 --- /dev/null +++ b/identity/ethereum_identity_test.go @@ -0,0 +1,455 @@ +// +build unit + +package identity + +import ( + "context" + "math/big" + "net/url" + "testing" + + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/go-errors/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type MockConfig struct{} + +func (MockConfig) GetEthereumDefaultAccountName() string { + return "mockacc" +} + +type MockIDFactory struct { + mock.Mock +} + +func (f MockIDFactory) CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) { + args := f.Called(opts, _centrifugeId) + id := args.Get(0).(*types.Transaction) + return id, args.Error(1) +} + +type MockIDRegistry struct { + mock.Mock +} + +func (r MockIDRegistry) GetIdentityByCentrifugeId(opts *bind.CallOpts, bigInt *big.Int) (common.Address, error) { + args := r.Called(opts, bigInt) + id := args.Get(0).(common.Address) + return id, args.Error(1) +} + +type MockGethClient struct { + mock.Mock +} + +func (gc MockGethClient) GetEthClient() *ethclient.Client { + args := gc.Called() + return args.Get(0).(*ethclient.Client) +} + +func (gc MockGethClient) GetNodeURL() *url.URL { + args := gc.Called() + return args.Get(0).(*url.URL) +} + +func (gc MockGethClient) GetTxOpts(accountName string) (*bind.TransactOpts, error) { + args := gc.Called(accountName) + return args.Get(0).(*bind.TransactOpts), args.Error(1) +} + +func (gc MockGethClient) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) { + args := gc.Called(contractMethod, opts, params) + return args.Get(0).(*types.Transaction), args.Error(1) +} + +func (gc MockGethClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { + args := gc.Called() + return args.Get(0).(*bind.CallOpts), args.Get(1).(func()) +} + +type MockIDContract struct { + mock.Mock +} + +func (mic MockIDContract) AddKey(opts *bind.TransactOpts, _key [32]byte, _kPurpose *big.Int) (*types.Transaction, error) { + args := mic.Called(opts, _key, _kPurpose) + return args.Get(0).(*types.Transaction), args.Error(1) +} + +func (mic MockIDContract) GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) { + args := mic.Called(opts, _purpose) + return args.Get(0).([][32]byte), args.Error(1) +} + +func (mic MockIDContract) GetKey(opts *bind.CallOpts, _key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +}, error) { + args := mic.Called(opts, _key) + return args.Get(0).(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }), args.Error(1) +} + +func (mic MockIDContract) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) { + args := mic.Called(opts, key, purpose) + return args.Get(0).(*EthereumIdentityContractKeyAddedIterator), args.Error(1) +} + +func TestGetClientP2PURL_happy(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetClientP2PURL(centID) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.NotEmpty(t, p2p, "p2p url is empty") + assert.Nil(t, err, "error should be nil") +} + +func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) + i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetClientP2PURL(centID) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Empty(t, p2p, "p2p is not empty") + assert.Errorf(t, err, "error should not be nil") + assert.Contains(t, err.Error(), "ID lookup failed") +} + +func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, errors.New("p2p key error")) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetClientP2PURL(centID) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Empty(t, p2p, "p2p is not empty") + assert.Errorf(t, err, "error should not be nil") + assert.Contains(t, err.Error(), "p2p key error") +} + +func TestGetIdentityKey_fail_lookup(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetIdentityKey(centID, pubKey) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Empty(t, p2p, "p2p is not empty") + assert.Errorf(t, err, "error should not be nil") + assert.Contains(t, err.Error(), "ID lookup failed") +} + +func TestGetIdentityKey_fail_FetchKey(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + [32]byte{1}, + []*big.Int{big.NewInt(KeyPurposeP2P)}, + big.NewInt(1), + }, errors.New("p2p key error")) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetIdentityKey(centID, pubKey) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Empty(t, p2p, "p2p is not empty") + assert.Errorf(t, err, "error should not be nil") + assert.Contains(t, err.Error(), "p2p key error") +} + +func TestGetIdentityKey_fail_empty(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + [32]byte{}, + []*big.Int{big.NewInt(KeyPurposeP2P)}, + big.NewInt(1), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetIdentityKey(centID, pubKey) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Empty(t, p2p, "p2p is not empty") + assert.Errorf(t, err, "error should not be nil") + assert.Contains(t, err.Error(), "key not found for identity") +} + +func TestGetIdentityKey_Success(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + [32]byte{1}, + []*big.Int{big.NewInt(KeyPurposeP2P)}, + big.NewInt(1), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + p2p, err := srv.GetIdentityKey(centID, pubKey) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.NotEmpty(t, p2p, "p2p is empty") + assert.Nil(t, err, "error must be nil") +} + +func TestValidateKey_success(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + var key [32]byte + copy(key[:], pubKey) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + key, + []*big.Int{big.NewInt(KeyPurposeSigning)}, + big.NewInt(0), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Nil(t, err, "error must be nil") +} + +func TestValidateKey_fail_getId(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + var key [32]byte + copy(key[:], pubKey) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + key, + []*big.Int{big.NewInt(KeyPurposeSigning)}, + big.NewInt(0), + }, errors.New("Key error")) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Contains(t, err.Error(), "Key error") +} + +func TestValidateKey_fail_mismatch_key(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + [32]byte{1}, + []*big.Int{big.NewInt(KeyPurposeSigning)}, + big.NewInt(0), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Contains(t, err.Error(), "Key doesn't match") +} + +func TestValidateKey_fail_missing_purpose(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + var key [32]byte + copy(key[:], pubKey) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + key, + nil, + big.NewInt(0), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Contains(t, err.Error(), "Key doesn't have purpose") +} + +func TestValidateKey_fail_wrong_purpose(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + var key [32]byte + copy(key[:], pubKey) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + key, + []*big.Int{big.NewInt(KeyPurposeP2P)}, + big.NewInt(0), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Contains(t, err.Error(), "Key doesn't have purpose") +} + +func TestValidateKey_fail_revocation(t *testing.T) { + centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + pubKey := utils.RandomSlice(32) + var key [32]byte + copy(key[:], pubKey) + c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) + g.On("GetEthClient").Return(ðclient.Client{}) + r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) + i.On("GetKey", mock.Anything, mock.Anything).Return(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }{ + key, + []*big.Int{big.NewInt(KeyPurposeSigning)}, + big.NewInt(1), + }, nil) + srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + return g + }, func(address common.Address, backend bind.ContractBackend) (contract, error) { + return i, nil + }) + err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + f.AssertExpectations(t) + r.AssertExpectations(t) + g.AssertExpectations(t) + assert.Contains(t, err.Error(), "Key is currently revoked since block") +} diff --git a/identity/identity.go b/identity/identity.go index 08322090d..8be0c4a6c 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -1,17 +1,17 @@ package identity import ( - "bytes" "context" "errors" "fmt" "math/big" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -129,6 +129,26 @@ func RandomCentID() CentID { return ID } +// ValidateCentrifugeIDBytes validates a centrifuge ID given as bytes +func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { + centIDSignature, err := ToCentID(givenCentID) + if err != nil { + return err + } + + if !centrifugeID.Equal(centIDSignature) { + return errors.New("signature entity doesn't match provided centID") + } + + return nil +} + +// Sign the document with the private key and return the signature along with the public key for the verification +// assumes that signing root for the document is generated +func Sign(idConfig *IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { + return signatures.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) +} + // Equal checks if c == other func (c CentID) Equal(other CentID) bool { for i := range c { @@ -188,106 +208,23 @@ type Service interface { // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID GetIdentityAddress(centID CentID) (common.Address, error) -} - -// GetClientP2PURL returns the p2p url associated with the centID -func GetClientP2PURL(centID CentID) (url string, err error) { - target, err := IDService.LookupIdentityForID(centID) - if err != nil { - return url, centerrors.Wrap(err, "error fetching receiver identity") - } - - p2pKey, err := target.CurrentP2PKey() - if err != nil { - return url, centerrors.Wrap(err, "error fetching p2p key") - } - - return fmt.Sprintf("/ipfs/%s", p2pKey), nil -} - -// GetClientsP2PURLs returns p2p urls associated with each centIDs -// will error out at first failure -func GetClientsP2PURLs(centIDs []CentID) ([]string, error) { - var p2pURLs []string - for _, id := range centIDs { - url, err := GetClientP2PURL(id) - if err != nil { - return nil, err - } - p2pURLs = append(p2pURLs, url) - } + // GetClientP2PURL returns the p2p url associated with the centID + GetClientP2PURL(centID CentID) (url string, err error) - return p2pURLs, nil -} + // GetClientsP2PURLs returns p2p urls associated with each centIDs + // will error out at first failure + GetClientsP2PURLs(centIDs []CentID) ([]string, error) -// GetIdentityKey returns the key for provided identity -func GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) { - id, err := IDService.LookupIdentityForID(identity) - if err != nil { - return keyInfo, err - } + // GetIdentityKey returns the key for provided identity + GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) - key, err := id.FetchKey(pubKey) - if err != nil { - return keyInfo, err - } + // ValidateKey checks if a given key is valid for the given centrifugeID. + ValidateKey(centrifugeId CentID, key []byte, purpose int) error - if utils.IsEmptyByte32(key.GetKey()) { - return keyInfo, fmt.Errorf(fmt.Sprintf("key not found for identity: %x", identity)) - } + // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file + AddKeyFromConfig(purpose int) error - return key, nil -} - -// ValidateKey checks if a given key is valid for the given centrifugeID. -func ValidateKey(centrifugeId CentID, key []byte, purpose int) error { - idKey, err := GetIdentityKey(centrifugeId, key) - if err != nil { - return err - } - - if !bytes.Equal(key, utils.Byte32ToSlice(idKey.GetKey())) { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't match", idKey.GetKey())) - } - - if !utils.ContainsBigIntInSlice(big.NewInt(int64(purpose)), idKey.GetPurposes()) { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't have purpose [%d]", idKey.GetKey(), purpose)) - } - - if idKey.GetRevokedAt().Cmp(big.NewInt(0)) != 0 { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key is currently revoked since block [%d]", idKey.GetKey(), idKey.GetRevokedAt())) - } - - return nil -} - -// AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file -func AddKeyFromConfig(purpose int) error { - identityConfig, err := GetIdentityConfig() - if err != nil { - return err - } - - id, err := IDService.LookupIdentityForID(identityConfig.ID) - if err != nil { - return err - } - - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() - defer cancel() - confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) - if err != nil { - return err - } - watchAddedToIdentity := <-confirmations - - lastKey, errLocal := watchAddedToIdentity.Identity.LastKeyForPurpose(purpose) - if errLocal != nil { - return err - } - - log.Infof("Key [%v] with type [$s] Added to Identity [%s]", lastKey, purpose, watchAddedToIdentity.Identity) - - return nil + // ValidateSignature validates a signature on a message based on identity data + ValidateSignature(signature *coredocumentpb.Signature, message []byte) error } diff --git a/identity/identity_test.go b/identity/identity_test.go index 4359d8f12..5ac6e963b 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -5,7 +5,6 @@ package identity import ( "context" "fmt" - "math/big" "os" "testing" @@ -201,245 +200,6 @@ func TestNewCentIdEqual(t *testing.T) { assert.False(t, centrifugeIdA.Equal(centrifugeIdC), "centrifuge Id's should not be equal") } -func TestGetClientP2PURL_fail_service(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(nil, fmt.Errorf("failed service")).Once() - IDService = srv - p2p, err := GetClientP2PURL(centID) - srv.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "failed service") -} - -func TestGetClientP2PURL_fail_identity(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - srv := &mockIDService{} - id := &mockID{} - id.On("CurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - IDService = srv - p2p, err := GetClientP2PURL(centID) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "error identity") -} - -func TestGetClientP2PURL_Success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - srv := &mockIDService{} - id := &mockID{} - id.On("CurrentP2PKey").Return("target", nil).Once() - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - IDService = srv - p2p, err := GetClientP2PURL(centID) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Nil(t, err, "must be nil") - assert.Equal(t, p2p, "/ipfs/target") -} - -func TestGetClientsP2PURLs_fail(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - centIDs := []CentID{centID} - srv := &mockIDService{} - id := &mockID{} - id.On("CurrentP2PKey").Return("", fmt.Errorf("error identity")).Once() - srv.On("LookupIdentityForID", centIDs[0]).Return(id, nil).Once() - IDService = srv - p2pURLs, err := GetClientsP2PURLs(centIDs) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Empty(t, p2pURLs, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "error identity") -} - -func TestGetClientsP2PURLs_success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - centIDs := []CentID{centID} - id := &mockID{} - id.On("CurrentP2PKey").Return("target", nil).Once() - srv := &mockIDService{} - srv.On("LookupIdentityForID", centIDs[0]).Return(id, nil).Once() - IDService = srv - p2pURLs, err := GetClientsP2PURLs(centIDs) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Nil(t, err, "should be nil") - assert.NotEmpty(t, p2pURLs, "should not be empty") - assert.Equal(t, p2pURLs[0], "/ipfs/target") -} - -func TestGetIdentityKey_fail_lookup(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(nil, fmt.Errorf("lookup failed")).Once() - IDService = srv - id, err := GetIdentityKey(centID, utils.RandomSlice(32)) - srv.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "lookup failed") - assert.Nil(t, id, "must be nil") -} - -func TestGetIdentityKey_fail_FetchKey(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomSlice(32) - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(nil, fmt.Errorf("fetch key failed")).Once() - IDService = srv - key, err := GetIdentityKey(centID, pubKey) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "fetch key failed") - assert.Nil(t, key, "must be nil") -} - -func TestGetIdentityKey_fail_empty(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomSlice(32) - var emptyKey [32]byte - idkey := &EthereumIdentityKey{Key: emptyKey} - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - IDService = srv - key, err := GetIdentityKey(centID, pubKey) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "key not found for identity") - assert.Nil(t, key, "must be nil") -} - -func TestGetIdentityKey_Success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomSlice(32) - pkey := utils.RandomByte32() - idkey := &EthereumIdentityKey{Key: pkey} - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - IDService = srv - key, err := GetIdentityKey(centID, pubKey) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Nil(t, err, "error must be nil") - assert.NotNil(t, key, "must not be nil") - assert.Equal(t, key, idkey) -} - -func TestValidateKey_fail_getId(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomSlice(32) - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(nil, fmt.Errorf("failed at GetIdentity")).Once() - IDService = srv - err := ValidateKey(centID, pubKey, KeyPurposeSigning) - srv.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "failed at GetIdentity") -} - -func TestValidateKey_fail_mismatch_key(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomSlice(32) - idkey := &EthereumIdentityKey{Key: utils.RandomByte32()} - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - IDService = srv - err := ValidateKey(centID, pubKey, KeyPurposeSigning) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), " Key doesn't match") -} - -func TestValidateKey_fail_missing_purpose(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomByte32() - idkey := &EthereumIdentityKey{Key: pubKey} - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey[:]).Return(idkey, nil).Once() - IDService = srv - err := ValidateKey(centID, pubKey[:], KeyPurposeSigning) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "Key doesn't have purpose") -} - -func TestValidateKey_fail_wrong_purpose(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomByte32() - idkey := &EthereumIdentityKey{ - Key: pubKey, - Purposes: []*big.Int{big.NewInt(KeyPurposeEthMsgAuth)}, - } - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey[:]).Return(idkey, nil).Once() - IDService = srv - err := ValidateKey(centID, pubKey[:], KeyPurposeSigning) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "Key doesn't have purpose") -} - -func TestValidateKey_fail_revocation(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomByte32() - idkey := &EthereumIdentityKey{ - Key: pubKey, - Purposes: []*big.Int{big.NewInt(KeyPurposeSigning)}, - RevokedAt: big.NewInt(1), - } - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey[:]).Return(idkey, nil).Once() - IDService = srv - err := ValidateKey(centID, pubKey[:], KeyPurposeSigning) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Error(t, err, "must be not nil") - assert.Contains(t, err.Error(), "Key is currently revoked since block") -} - -func TestValidateKey_success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - pubKey := utils.RandomByte32() - idkey := &EthereumIdentityKey{ - Key: pubKey, - Purposes: []*big.Int{big.NewInt(KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &mockID{} - srv := &mockIDService{} - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", pubKey[:]).Return(idkey, nil).Once() - IDService = srv - err := ValidateKey(centID, pubKey[:], KeyPurposeSigning) - srv.AssertExpectations(t) - id.AssertExpectations(t) - assert.Nil(t, err, "must be nil") -} - func TestCentIDFromString(t *testing.T) { tests := []struct { id string diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index da1afd076..8da13782b 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -7,10 +7,12 @@ import ( "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" ) const ( @@ -35,17 +37,23 @@ type keyRegistrationConfirmationTask struct { filterer keyRegisteredFilterer contract *EthereumIdentityRegistryContract config Config + gethClientFinder func() ethereum.Client + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) } func newKeyRegistrationConfirmationTask( ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), registryContract *EthereumIdentityRegistryContract, config Config, + gethClientFinder func() ethereum.Client, + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error), ) *keyRegistrationConfirmationTask { return &keyRegistrationConfirmationTask{ contextInitializer: ethContextInitializer, contract: registryContract, config: config, + gethClientFinder: gethClientFinder, + contractProvider: contractProvider, } } @@ -71,7 +79,9 @@ func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) krct.ctx, krct.filterer, krct.contract, - krct.config}, nil + krct.config, + krct.gethClientFinder, + krct.contractProvider}, nil } // ParseKwargs parses the args into the task @@ -124,7 +134,7 @@ func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { krct.ctx, _ = krct.contextInitializer() } - id := ethereumIdentity{centID: krct.centID, registryContract: krct.contract, config: krct.config} + id := newEthereumIdentity(krct.centID, krct.contract, krct.config, krct.gethClientFinder, krct.contractProvider) contract, err := id.getContract() if err != nil { return nil, err diff --git a/p2p/client.go b/p2p/client.go index 0fb7d9ab3..75aa91831 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/version" "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" @@ -20,7 +19,7 @@ import ( type Client interface { OpenClient(target string) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // OpenClient returns P2PServiceClient to contact the remote peer @@ -62,7 +61,7 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *p2pServer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { senderId, err := s.config.GetIdentityID() if err != nil { return nil, err @@ -91,12 +90,12 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, doc coredocumen return nil, version.IncompatibleVersionError(resp.CentNodeVersion) } - err = signatures.ValidateCentrifugeID(resp.Signature, receiverCentId) + err = identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiverCentId) if err != nil { return nil, centerrors.New(code.AuthenticationFailed, err.Error()) } - err = signatures.ValidateSignature(resp.Signature, doc.SigningRoot) + err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) if err != nil { return nil, centerrors.New(code.AuthenticationFailed, "signature invalid") } @@ -111,8 +110,8 @@ type signatureResponseWrap struct { err error } -func (s *p2pServer) getSignatureAsync(ctx context.Context, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, doc, client, receiverCentId) +func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, identityService, doc, client, receiverCentId) out <- signatureResponseWrap{ resp: resp, err: err, @@ -120,7 +119,7 @@ func (s *p2pServer) getSignatureAsync(ctx context.Context, doc coredocumentpb.Co } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { +func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) @@ -135,7 +134,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, doc *coredocum if err != nil { return centerrors.Wrap(err, "failed to convert to CentID") } - target, err := identity.GetClientP2PURL(collaboratorID) + target, err := identityService.GetClientP2PURL(collaboratorID) if err != nil { return centerrors.Wrap(err, "failed to get P2P url") @@ -150,7 +149,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, doc *coredocum // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - go s.getSignatureAsync(ctx, *doc, client, collaboratorID, in) + go s.getSignatureAsync(ctx, identityService, *doc, client, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/p2p/client_test.go b/p2p/client_test.go index 5a594be50..d6630a78a 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -26,7 +26,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("signature failed")).Once() - resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -42,7 +42,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.Nil(t, err, "centrifugeId not initialized correctly ") client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(resp, nil).Once() - resp, err = testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -66,7 +66,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(sigResp, nil).Once() - resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, client, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Nil(t, resp, "must be nil") diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 131f61e83..a9fe67fb1 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -5,7 +5,6 @@ package p2p_test import ( "context" "flag" - "math/big" "os" "testing" @@ -20,9 +19,8 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/signatures" - "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" "github.com/centrifuge/precise-proofs/proofs" @@ -42,6 +40,7 @@ func TestMain(m *testing.M) { config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + testingidentity.CreateIdentityWithKeys() result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -58,126 +57,50 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { } func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { - savedService := identity.IDService - idConfig, err := identity.GetIdentityConfig() - assert.Nil(t, err) - pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey - b32Key, _ := utils.SliceToByte32(pubKey) - idkey := &identity.EthereumIdentityKey{ - Key: b32Key, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - identity.IDService = srv - doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) resp, err := handler.RequestDocumentSignature(context.Background(), req) - srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") - id = &testingcommons.MockID{} - srv = &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - identity.IDService = srv - req = getSignatureRequest(doc) resp, err = handler.RequestDocumentSignature(context.Background(), req) - srv.AssertExpectations(t) - id.AssertExpectations(t) assert.NotNil(t, err, "must not be nil") assert.Contains(t, err.Error(), "document already exists") - - identity.IDService = savedService } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { - savedService := identity.IDService - idConfig, err := identity.GetIdentityConfig() - assert.Nil(t, err) - pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey - b32Key, _ := utils.SliceToByte32(pubKey) - idkey := &identity.EthereumIdentityKey{ - Key: b32Key, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - identity.IDService = srv - doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) resp, err := handler.RequestDocumentSignature(context.Background(), req) - srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") - //Update document newDoc, err := coredocument.PrepareNewVersion(*doc, nil) assert.Nil(t, err) - id = &testingcommons.MockID{} - srv = &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - identity.IDService = srv - updateDocumentForP2Phandler(t, newDoc) newDoc = prepareDocumentForP2PHandler(t, newDoc) req = getSignatureRequest(newDoc) resp, err = handler.RequestDocumentSignature(context.Background(), req) - srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig = resp.Signature assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") - identity.IDService = savedService } func TestHandler_RequestDocumentSignature(t *testing.T) { - savedService := identity.IDService - idConfig, err := identity.GetIdentityConfig() - assert.Nil(t, err) - pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey - b32Key, _ := utils.SliceToByte32(pubKey) - idkey := &identity.EthereumIdentityKey{ - Key: b32Key, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - id := &testingcommons.MockID{} - srv := &testingcommons.MockIDService{} - srv.On("LookupIdentityForID", idConfig.ID).Return(id, nil).Once() - id.On("FetchKey", pubKey).Return(idkey, nil).Once() - identity.IDService = srv - doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) resp, err := handler.RequestDocumentSignature(context.Background(), req) - srv.AssertExpectations(t) - id.AssertExpectations(t) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") - - identity.IDService = savedService } func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { @@ -284,7 +207,7 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument } tree, _ := coredocument.GetDocumentSigningTree(doc) doc.SigningRoot = tree.RootHash() - sig := signatures.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) tree, _ = coredocument.GetDocumentRootTree(doc) doc.DocumentRoot = tree.RootHash() diff --git a/signatures/signatures.go b/signatures/signatures.go index 31ccdb559..d5929c30f 100644 --- a/signatures/signatures.go +++ b/signatures/signatures.go @@ -1,47 +1,16 @@ package signatures import ( - "errors" "fmt" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "golang.org/x/crypto/ed25519" ) -func ValidateCentrifugeID(signature *coredocumentpb.Signature, centrifugeId identity.CentID) error { - centIDSignature, err := identity.ToCentID(signature.EntityId) - if err != nil { - return err - } - - if !centrifugeId.Equal(centIDSignature) { - return errors.New("signature entity doesn't match provided centID") - } - - return nil - -} - -// ValidateSignature verifies the signature on the document -func ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { - centID, err := identity.ToCentID(signature.EntityId) - if err != nil { - return err - } - - err = identity.ValidateKey(centID, signature.PublicKey, identity.KeyPurposeSigning) - if err != nil { - return err - } - - return verifySignature(signature.PublicKey, message, signature.Signature) -} - -// verifySignature verifies the signature using ed25519 -func verifySignature(pubKey, message, signature []byte) error { +// VerifySignature verifies the signature using ed25519 +func VerifySignature(pubKey, message, signature []byte) error { valid := ed25519.Verify(pubKey, message, signature) if !valid { return fmt.Errorf("invalid signature") @@ -52,12 +21,11 @@ func verifySignature(pubKey, message, signature []byte) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated -func Sign(idConfig *identity.IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { - centIDBytes := idConfig.ID[:] +func Sign(centIDBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { return &coredocumentpb.Signature{ EntityId: centIDBytes, - PublicKey: idConfig.Keys[purpose].PublicKey, - Signature: ed25519.Sign(idConfig.Keys[purpose].PrivateKey, payload), + PublicKey: pubKey, + Signature: ed25519.Sign(privateKey, payload), Timestamp: utils.ToTimestamp(time.Now().UTC()), } } diff --git a/signatures/signatures_test.go b/signatures/signatures_test.go index 486ca69eb..5054e034c 100644 --- a/signatures/signatures_test.go +++ b/signatures/signatures_test.go @@ -3,13 +3,8 @@ package signatures import ( - "fmt" "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -22,21 +17,7 @@ var ( ) func TestSign(t *testing.T) { - coreDoc := testingcoredocument.GenerateCoreDocument() - coreDoc.SigningRoot = key1Pub - centID, err := identity.ToCentID(id1) - assert.Nil(t, err) - signKey := identity.IdentityKey{ - PublicKey: key1Pub, - PrivateKey: key1, - } - idConfig := &identity.IdentityConfig{ - ID: centID, - Keys: map[int]identity.IdentityKey{ - identity.KeyPurposeSigning: signKey, - }, - } - sig := Sign(idConfig, identity.KeyPurposeSigning, coreDoc.SigningRoot) + sig := Sign(id1, key1, key1Pub, key1Pub) assert.NotNil(t, sig) assert.Equal(t, sig.PublicKey, []byte(key1Pub)) assert.Equal(t, sig.EntityId, id1) @@ -46,23 +27,11 @@ func TestSign(t *testing.T) { assert.NotNil(t, sig.Timestamp, "must be non nil") } -func TestValidateSignature_invalid_key(t *testing.T) { - sig := &coredocumentpb.Signature{EntityId: utils.RandomSlice(identity.CentIDLength)} - srv := &testingcommons.MockIDService{} - centId, _ := identity.ToCentID(sig.EntityId) - srv.On("LookupIdentityForID", centId).Return(nil, fmt.Errorf("failed GetIdentity")).Once() - identity.IDService = srv - err := ValidateSignature(sig, key1Pub) - srv.AssertExpectations(t) - assert.NotNil(t, err, "must be not nil") - assert.Contains(t, err.Error(), "failed GetIdentity") -} - func TestValidateSignature_invalid_sig(t *testing.T) { pubKey := key1Pub message := key1Pub signature := utils.RandomSlice(32) - err := verifySignature(pubKey, message, signature) + err := VerifySignature(pubKey, message, signature) assert.NotNil(t, err, "must be not nil") assert.Contains(t, err.Error(), "invalid signature") } @@ -70,21 +39,6 @@ func TestValidateSignature_invalid_sig(t *testing.T) { func TestValidateSignature_success(t *testing.T) { pubKey := key1Pub message := key1Pub - err := verifySignature(pubKey, message, signature) + err := VerifySignature(pubKey, message, signature) assert.Nil(t, err, "must be nil") } - -func TestValidateCentrifugeId(t *testing.T) { - randomBytes := utils.RandomSlice(identity.CentIDLength) - centID, err := identity.ToCentID(randomBytes) - assert.Nil(t, err, "centID not initialized correctly ") - - sig := &coredocumentpb.Signature{EntityId: randomBytes} - err = ValidateCentrifugeID(sig, centID) - assert.Nil(t, err, "Validate centrifuge id didn't work correctly") - - randomBytes = utils.RandomSlice(identity.CentIDLength) - centID, err = identity.ToCentID(randomBytes) - err = ValidateCentrifugeID(sig, centID) - assert.NotNil(t, err, "Validate centrifuge id didn't work correctly") -} diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index b1f790135..7e3b1fdee 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -5,6 +5,8 @@ package testingcommons import ( "net/url" + "context" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -15,6 +17,12 @@ type MockEthClient struct { mock.Mock } +func (m *MockEthClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { + args := m.Called() + c, _ := args.Get(0).(*bind.CallOpts) + return c, func() {} +} + func (m *MockEthClient) GetEthClient() *ethclient.Client { args := m.Called() c, _ := args.Get(0).(*ethclient.Client) diff --git a/testingutils/commons/mock_identity.go b/testingutils/commons/mock_identity.go index 520fb90da..bcaf2d436 100644 --- a/testingutils/commons/mock_identity.go +++ b/testingutils/commons/mock_identity.go @@ -8,6 +8,7 @@ package testingcommons import ( "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" @@ -18,6 +19,39 @@ type MockIDService struct { mock.Mock } +func (srv *MockIDService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { + args := srv.Called(signature, message) + return args.Error(0) +} + +func (srv *MockIDService) GetClientP2PURL(centID identity.CentID) (url string, err error) { + args := srv.Called(centID) + addr := args.Get(0).(string) + return addr, args.Error(1) +} + +func (srv *MockIDService) GetClientsP2PURLs(centIDs []identity.CentID) ([]string, error) { + args := srv.Called(centIDs) + addr := args.Get(0).([]string) + return addr, args.Error(1) +} + +func (srv *MockIDService) GetIdentityKey(id identity.CentID, pubKey []byte) (keyInfo identity.Key, err error) { + args := srv.Called(id, pubKey) + addr := args.Get(0).(identity.Key) + return addr, args.Error(1) +} + +func (srv *MockIDService) ValidateKey(centrifugeId identity.CentID, key []byte, purpose int) error { + args := srv.Called(centrifugeId, key, purpose) + return args.Error(0) +} + +func (srv *MockIDService) AddKeyFromConfig(purpose int) error { + args := srv.Called(purpose) + return args.Error(0) +} + func (srv *MockIDService) GetIdentityAddress(centID identity.CentID) (common.Address, error) { args := srv.Called(centID) addr := args.Get(0).(common.Address) From 8e3eb907257f6972e43d22beeebbd62167931c35 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 19 Nov 2018 14:14:37 +0100 Subject: [PATCH 031/220] identity.go coverage (#463) * identity.go coverage * correct test --- identity/identity.go | 163 +++++++++++++++++++------------------- identity/identity_test.go | 27 +++++++ p2p/client_test.go | 2 +- 3 files changed, 110 insertions(+), 82 deletions(-) diff --git a/identity/identity.go b/identity/identity.go index 8be0c4a6c..30b2f6861 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -49,6 +49,87 @@ type IdentityKey struct { PrivateKey []byte } +// Equal checks if c == other +func (c CentID) Equal(other CentID) bool { + for i := range c { + if c[i] != other[i] { + return false + } + } + + return true +} + +// String returns the hex format of CentID +func (c CentID) String() string { + return hexutil.Encode(c[:]) +} + +// BigInt returns CentID in bigInt +func (c CentID) BigInt() *big.Int { + return utils.ByteSliceToBigInt(c[:]) +} + +// Identity defines an Identity on chain +type Identity interface { + fmt.Stringer + CentID() CentID + SetCentrifugeID(centID CentID) + CurrentP2PKey() (ret string, err error) + LastKeyForPurpose(keyPurpose int) (key []byte, err error) + AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) + FetchKey(key []byte) (Key, error) +} + +// Key defines a single ERC725 identity key +type Key interface { + GetKey() [32]byte + GetPurposes() []*big.Int + GetRevokedAt() *big.Int +} + +// WatchIdentity holds the identity received form chain event +type WatchIdentity struct { + Identity Identity + Error error +} + +// Service is used to interact with centrifuge identities +type Service interface { + + // LookupIdentityForID looks up if the identity for given CentID exists on ethereum + LookupIdentityForID(centrifugeID CentID) (id Identity, err error) + + // CreateIdentity creates an identity representing the id on ethereum + CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) + + // CheckIdentityExists checks if the identity represented by id actually exists on ethereum + CheckIdentityExists(centrifugeID CentID) (exists bool, err error) + + // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID + GetIdentityAddress(centID CentID) (common.Address, error) + + // GetClientP2PURL returns the p2p url associated with the centID + GetClientP2PURL(centID CentID) (url string, err error) + + // GetClientsP2PURLs returns p2p urls associated with each centIDs + // will error out at first failure + GetClientsP2PURLs(centIDs []CentID) ([]string, error) + + // GetIdentityKey returns the key for provided identity + GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) + + // ValidateKey checks if a given key is valid for the given centrifugeID. + ValidateKey(centrifugeId CentID, key []byte, purpose int) error + + // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file + AddKeyFromConfig(purpose int) error + + // ValidateSignature validates a signature on a message based on identity data + ValidateSignature(signature *coredocumentpb.Signature, message []byte) error +} + + // GetIdentityConfig returns the identity and keys associated with the node func GetIdentityConfig() (*IdentityConfig, error) { centIDBytes, err := config.Config().GetIdentityID() @@ -137,7 +218,7 @@ func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { } if !centrifugeID.Equal(centIDSignature) { - return errors.New("signature entity doesn't match provided centID") + return errors.New("provided bytes doesn't match centID") } return nil @@ -148,83 +229,3 @@ func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { func Sign(idConfig *IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { return signatures.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) } - -// Equal checks if c == other -func (c CentID) Equal(other CentID) bool { - for i := range c { - if c[i] != other[i] { - return false - } - } - - return true -} - -// String returns the hex format of CentID -func (c CentID) String() string { - return hexutil.Encode(c[:]) -} - -// BigInt returns CentID in bigInt -func (c CentID) BigInt() *big.Int { - return utils.ByteSliceToBigInt(c[:]) -} - -// Identity defines an Identity on chain -type Identity interface { - fmt.Stringer - CentID() CentID - SetCentrifugeID(centID CentID) - CurrentP2PKey() (ret string, err error) - LastKeyForPurpose(keyPurpose int) (key []byte, err error) - AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) - FetchKey(key []byte) (Key, error) -} - -// Key defines a single ERC725 identity key -type Key interface { - GetKey() [32]byte - GetPurposes() []*big.Int - GetRevokedAt() *big.Int -} - -// WatchIdentity holds the identity received form chain event -type WatchIdentity struct { - Identity Identity - Error error -} - -// Service is used to fetch identities -type Service interface { - - // LookupIdentityForID looks up if the identity for given CentID exists on ethereum - LookupIdentityForID(centrifugeID CentID) (id Identity, err error) - - // CreateIdentity creates an identity representing the id on ethereum - CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) - - // CheckIdentityExists checks if the identity represented by id actually exists on ethereum - CheckIdentityExists(centrifugeID CentID) (exists bool, err error) - - // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID - GetIdentityAddress(centID CentID) (common.Address, error) - - // GetClientP2PURL returns the p2p url associated with the centID - GetClientP2PURL(centID CentID) (url string, err error) - - // GetClientsP2PURLs returns p2p urls associated with each centIDs - // will error out at first failure - GetClientsP2PURLs(centIDs []CentID) ([]string, error) - - // GetIdentityKey returns the key for provided identity - GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) - - // ValidateKey checks if a given key is valid for the given centrifugeID. - ValidateKey(centrifugeId CentID, key []byte, purpose int) error - - // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file - AddKeyFromConfig(purpose int) error - - // ValidateSignature validates a signature on a message based on identity data - ValidateSignature(signature *coredocumentpb.Signature, message []byte) error -} diff --git a/identity/identity_test.go b/identity/identity_test.go index 5ac6e963b..1e4a27df9 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/centrifuge/go-centrifuge/signatures" ) func TestMain(m *testing.M) { @@ -253,3 +254,29 @@ func TestCentIDsFromStrings(t *testing.T) { assert.NotNil(t, cids) assert.Equal(t, cids, []CentID{{1, 2, 3, 4, 5, 6}, {2, 3, 1, 2, 3, 4}}) } + +func TestValidateCentrifugeIDBytes(t *testing.T) { + c := RandomCentID() + assert.True(t, ValidateCentrifugeIDBytes(c[:], c) == nil) + + err := ValidateCentrifugeIDBytes(utils.RandomSlice(20), c) + if assert.Error(t, err) { + assert.Equal(t, "invalid length byte slice provided for centID", err.Error()) + } + + err = ValidateCentrifugeIDBytes(utils.RandomSlice(6), c) + if assert.Error(t, err) { + assert.Equal(t, "provided bytes doesn't match centID", err.Error()) + } +} + +func TestSign(t *testing.T) { + key1Pub := []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 := []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + c := RandomCentID() + msg := utils.RandomSlice(100) + sig := Sign(&IdentityConfig{c , map[int]IdentityKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) + + err := signatures.VerifySignature(key1Pub, msg, sig.Signature) + assert.True(t, err == nil) +} \ No newline at end of file diff --git a/p2p/client_test.go b/p2p/client_test.go index d6630a78a..3c6588e79 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -71,6 +71,6 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { client.AssertExpectations(t) assert.Nil(t, resp, "must be nil") assert.Error(t, err, "must not be nil") - assert.Contains(t, err.Error(), "[5]signature entity doesn't match provided centID") + assert.Contains(t, err.Error(), "[5]provided bytes doesn't match centID") } From 9b132ec8ad46b4705ad62fa67d1eb14d3b03e7e3 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 19 Nov 2018 14:34:44 +0100 Subject: [PATCH 032/220] add status mapping in PO (#462) Fixes #455 --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- documents/purchaseorder/model.go | 116 +++++++++++++++---------------- 3 files changed, 58 insertions(+), 64 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 0836fa8e4..6c370f8d3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -45,7 +45,7 @@ revision = "d9a240d86d05350de86c26ed23d72b45562ae155" [[projects]] - digest = "1:e296ad994e618f237b1fd55450f99007017a8aedd981628d2bb3d09704deab3a" + digest = "1:d12e66a9500785cff8a8245bd8a138efff96ed3c1d0551b845cecdc25af57f90" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -57,7 +57,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "51fb5cf922b4a413a78397ad3707f755cfd48abf" + revision = "34ce7eaff0b89ac4a34e60654d34297747e5a7b4" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" diff --git a/Gopkg.toml b/Gopkg.toml index e1e36c10f..b4e3c9eaa 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "51fb5cf922b4a413a78397ad3707f755cfd48abf" + revision = "34ce7eaff0b89ac4a34e60654d34297747e5a7b4" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index ad057e6e2..9d1d2a8d5 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -24,46 +24,36 @@ import ( // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { - // purchase order number or reference number - PoNumber string - // name of the ordering company - OrderName string - // street and address details of the ordering company - OrderStreet string - OrderCity string - OrderZipcode string - // country ISO code of the ordering company of this purchase order - OrderCountry string - // name of the recipient company - RecipientName string - RecipientStreet string - RecipientCity string - RecipientZipcode string - // country ISO code of the receipient of this purchase order - RecipientCountry string - // ISO currency code - Currency string - // ordering gross amount including tax - OrderAmount int64 - // invoice amount excluding tax - NetAmount int64 - TaxAmount int64 - TaxRate int64 - Recipient *identity.CentID - Order []byte - // contact or requester or purchaser at the ordering company - OrderContact string - Comment string - // requested delivery date - DeliveryDate *timestamp.Timestamp - // purchase order date - DateCreated *timestamp.Timestamp - ExtraData []byte - + Status string // status of the Purchase Order + PoNumber string // purchase order number or reference number + OrderName string // name of the ordering company + OrderStreet string // street and address details of the ordering company + OrderCity string + OrderZipcode string + OrderCountry string // country ISO code of the ordering company of this purchase order + RecipientName string // name of the recipient company + RecipientStreet string + RecipientCity string + RecipientZipcode string + RecipientCountry string // country ISO code of the receipient of this purchase order + Currency string // ISO currency code + OrderAmount int64 // ordering gross amount including tax + NetAmount int64 // invoice amount excluding tax + TaxAmount int64 + TaxRate int64 + Recipient *identity.CentID + Order []byte + OrderContact string + Comment string + DeliveryDate *timestamp.Timestamp // requested delivery date + DateCreated *timestamp.Timestamp // purchase order date + ExtraData []byte PurchaseOrderSalt *purchaseorderpb.PurchaseOrderDataSalts CoreDocument *coredocumentpb.CoreDocument } +// ID returns the DocumentIdentifier for this document +// Note: this is not same as VersionIdentifier func (p *PurchaseOrder) ID() ([]byte, error) { coreDoc, err := p.PackCoreDocument() if err != nil { @@ -90,6 +80,7 @@ func (p *PurchaseOrder) getClientData() *clientpurchaseorderpb.PurchaseOrderData } return &clientpurchaseorderpb.PurchaseOrderData{ + PoStatus: p.Status, PoNumber: p.PoNumber, OrderName: p.OrderName, OrderStreet: p.OrderStreet, @@ -125,6 +116,7 @@ func (p *PurchaseOrder) createP2PProtobuf() *purchaseorderpb.PurchaseOrderData { } return &purchaseorderpb.PurchaseOrderData{ + PoStatus: p.Status, PoNumber: p.PoNumber, OrderName: p.OrderName, OrderStreet: p.OrderStreet, @@ -170,6 +162,7 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu // initPurchaseOrderFromData initialises purchase order from purchaseOrderData func (p *PurchaseOrder) initPurchaseOrderFromData(data *clientpurchaseorderpb.PurchaseOrderData) error { + p.Status = data.PoStatus p.PoNumber = data.PoNumber p.OrderName = data.OrderName p.OrderStreet = data.OrderStreet @@ -218,31 +211,32 @@ func (p *PurchaseOrder) initPurchaseOrderFromData(data *clientpurchaseorderpb.Pu } // loadFromP2PProtobuf loads the purcase order from centrifuge protobuf purchase order data -func (p *PurchaseOrder) loadFromP2PProtobuf(purchaseOrderData *purchaseorderpb.PurchaseOrderData) { - p.PoNumber = purchaseOrderData.PoNumber - p.OrderName = purchaseOrderData.OrderName - p.OrderStreet = purchaseOrderData.OrderStreet - p.OrderCity = purchaseOrderData.OrderCity - p.OrderZipcode = purchaseOrderData.OrderZipcode - p.OrderCountry = purchaseOrderData.OrderCountry - p.RecipientName = purchaseOrderData.RecipientName - p.RecipientStreet = purchaseOrderData.RecipientStreet - p.RecipientCity = purchaseOrderData.RecipientCity - p.RecipientZipcode = purchaseOrderData.RecipientZipcode - p.RecipientCountry = purchaseOrderData.RecipientCountry - p.Currency = purchaseOrderData.Currency - p.OrderAmount = purchaseOrderData.OrderAmount - p.NetAmount = purchaseOrderData.NetAmount - p.TaxAmount = purchaseOrderData.TaxAmount - p.TaxRate = purchaseOrderData.TaxRate - p.Order = purchaseOrderData.Order - p.OrderContact = purchaseOrderData.OrderContact - p.Comment = purchaseOrderData.Comment - p.DeliveryDate = purchaseOrderData.DeliveryDate - p.DateCreated = purchaseOrderData.DateCreated - p.ExtraData = purchaseOrderData.ExtraData - - if recipient, err := identity.ToCentID(purchaseOrderData.Recipient); err == nil { +func (p *PurchaseOrder) loadFromP2PProtobuf(data *purchaseorderpb.PurchaseOrderData) { + p.Status = data.PoStatus + p.PoNumber = data.PoNumber + p.OrderName = data.OrderName + p.OrderStreet = data.OrderStreet + p.OrderCity = data.OrderCity + p.OrderZipcode = data.OrderZipcode + p.OrderCountry = data.OrderCountry + p.RecipientName = data.RecipientName + p.RecipientStreet = data.RecipientStreet + p.RecipientCity = data.RecipientCity + p.RecipientZipcode = data.RecipientZipcode + p.RecipientCountry = data.RecipientCountry + p.Currency = data.Currency + p.OrderAmount = data.OrderAmount + p.NetAmount = data.NetAmount + p.TaxAmount = data.TaxAmount + p.TaxRate = data.TaxRate + p.Order = data.Order + p.OrderContact = data.OrderContact + p.Comment = data.Comment + p.DeliveryDate = data.DeliveryDate + p.DateCreated = data.DateCreated + p.ExtraData = data.ExtraData + + if recipient, err := identity.ToCentID(data.Recipient); err == nil { p.Recipient = &recipient } } From 0ece7f41dae9d6ce8868c4d417244b629150b413 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 19 Nov 2018 16:03:57 +0100 Subject: [PATCH 033/220] remove global anchor repo (#464) Fixes #459 --- anchors/anchor_repository.go | 43 ------------------- anchors/anchor_repository_integration_test.go | 16 ++++--- anchors/bootstrapper.go | 26 +++++------ anchors/test_bootstrapper.go | 12 ++---- api/server_test.go | 4 ++ bootstrap/bootstrapper.go | 15 +++---- context/bootstrapper.go | 4 +- context/testingbootstrap/testing_bootstrap.go | 4 +- documents/invoice/bootstrapper.go | 7 ++- documents/invoice/bootstrapper_test.go | 4 +- documents/purchaseorder/bootstrapper.go | 7 ++- documents/purchaseorder/bootstrapper_test.go | 4 ++ ethereum/bootstrapper.go | 5 +-- ethereum/test_bootstrapper.go | 4 +- p2p/handler_integration_test.go | 10 +++-- 15 files changed, 71 insertions(+), 94 deletions(-) diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index c0e07182a..d127c81ef 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -16,46 +16,3 @@ type AnchorRepository interface { CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) } - -// PreCommitAnchor initiates the PreCommit call on the smart contract -// with passed in variables and returns a channel for transaction confirmation -func PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) { - anchorRepository, _ := getConfiguredRepository() - - confirmations, err := anchorRepository.PreCommitAnchor(anchorID, signingRoot, centrifugeId, signature, expirationBlock) - if err != nil { - log.Errorf("Failed to pre-commit the anchor [id:%x, hash:%x ]: %v", anchorID, signingRoot, err) - } - return confirmations, err -} - -// CommitAnchor initiates the Commit call on smart contract -// with passed in variables and returns a channel for transaction confirmation -func CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) { - anchorRepository, _ := getConfiguredRepository() - - confirmations, err := anchorRepository.CommitAnchor(anchorID, documentRoot, centrifugeID, documentProofs, signature) - if err != nil { - log.Errorf("Failed to commit the anchor [id:%x, hash:%x ]: %v", anchorID, documentRoot, err) - } - return confirmations, err -} - -// anchorRepository is a singleton to keep track of the anchorRepository -var anchorRepository AnchorRepository - -// setAnchorRepository sets the passed in repository as default one -func setAnchorRepository(ar AnchorRepository) { - anchorRepository = ar -} - -// GetAnchorRepository returns default anchor repository -func GetAnchorRepository() AnchorRepository { - return anchorRepository -} - -// getConfiguredRepository will later pull a configured repository (if not only using Ethereum as the anchor repository) -// For now hard-coded to the Ethereum setup -func getConfiguredRepository() (AnchorRepository, error) { - return anchorRepository, nil -} diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 64ebaa954..6983f2338 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -17,10 +17,14 @@ import ( "github.com/stretchr/testify/assert" ) -var identityService identity.Service +var ( + identityService identity.Service + anchorRepo anchors.AnchorRepository +) func TestMain(m *testing.M) { - cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap() + anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) identityService = identity.IDService result := m.Run() cc.TestFunctionalEthereumTearDown() @@ -63,7 +67,7 @@ func TestCommitAnchor_Integration(t *testing.T) { messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) commitAnchor(t, anchorID, centrifugeId, documentRoot, signature, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) - gotDocRoot, err := anchors.GetAnchorRepository().GetDocumentRootOf(anchorIDTyped) + gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorIDTyped) assert.Nil(t, err) assert.Equal(t, docRootTyped, gotDocRoot) } @@ -73,7 +77,7 @@ func commitAnchor(t *testing.T, anchorID, centrifugeId, documentRoot, signature docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) centIdFixed, _ := identity.ToCentID(centrifugeId) - confirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) + confirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) } @@ -101,7 +105,7 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { h, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) assert.Nil(t, err, " error must be nil") commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) - confirmationList[ix], err = anchors.CommitAnchor(currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) + confirmationList[ix], err = anchorRepo.CommitAnchor(currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) } @@ -115,7 +119,7 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { assert.Equal(t, commitDataList[ix].DocumentRoot, watchSingleAnchor.CommitData.DocumentRoot, "Should have the document root that was passed into create function [%v]", watchSingleAnchor.CommitData.DocumentRoot) anchorID := commitDataList[ix].AnchorID docRoot := commitDataList[ix].DocumentRoot - gotDocRoot, err := anchors.GetAnchorRepository().GetDocumentRootOf(anchorID) + gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorID) assert.Nil(t, err) assert.Equal(t, docRoot, gotDocRoot) } diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 946762063..dc98ecbd5 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -9,18 +9,20 @@ import ( "github.com/centrifuge/go-centrifuge/queue" ) -type Bootstrapper struct { -} +// BootstrappedAnchorRepo is used as a key to map the configured anchor repository through context. +const BootstrappedAnchorRepo string = "BootstrappedAnchorRepo" + +type Bootstrapper struct{} // Bootstrap initializes the AnchorRepositoryContract as well as the anchorConfirmationTask that depends on it. -// the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { +// the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper. +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { + if _, ok := ctx[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -30,16 +32,14 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - anchorRepo := NewEthereumAnchorRepository(cfg, repositoryContract, ethereum.GetClient) - setAnchorRepository(anchorRepo) - if err != nil { - return err - } + var repo AnchorRepository + repo = NewEthereumAnchorRepository(cfg, repositoryContract, ethereum.GetClient) + ctx[BootstrappedAnchorRepo] = repo task := &anchorConfirmationTask{ AnchorCommittedFilterer: &repositoryContract.EthereumAnchorRepositoryContractFilterer, EthContextInitializer: ethereum.DefaultWaitForTransactionMiningContext, } - return queue.InstallQueuedTask(context, task) + return queue.InstallQueuedTask(ctx, task) } diff --git a/anchors/test_bootstrapper.go b/anchors/test_bootstrapper.go index 85becb065..edb06d1ad 100644 --- a/anchors/test_bootstrapper.go +++ b/anchors/test_bootstrapper.go @@ -8,20 +8,14 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" ) -func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { +func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - if repo, ok := context[bootstrap.BootstrappedAnchorRepository]; ok { - setAnchorRepository(repo.(AnchorRepository)) - } else { - b.Bootstrap(context) - } - - return nil + return b.Bootstrap(context) } -func (b *Bootstrapper) TestTearDown() error { +func (b Bootstrapper) TestTearDown() error { return nil } diff --git a/api/server_test.go b/api/server_test.go index 339e19ef7..9f580e96a 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -10,12 +10,14 @@ import ( "testing" "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" @@ -30,6 +32,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + ethereum.Bootstrapper{}, + anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 75a42d6f7..6a286eaec 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -3,14 +3,13 @@ package bootstrap // DO NOT PUT any app logic in this package to avoid any dependency cycles const ( - BootstrappedConfigFile string = "BootstrappedConfigFile" - BootstrappedConfig string = "BootstrappedConfig" - BootstrappedLevelDb string = "BootstrappedLevelDb" - BootstrappedEthereumClient string = "BootstrappedEthereumClient" - BootstrappedAnchorRepository string = "BootstrappedAnchorRepository" - BootstrappedP2PClient string = "BootstrappedP2PClient" - BootstrappedP2PServer string = "BootstrappedP2PServer" - BootstrappedAPIServer string = "BootstrappedAPIServer" + BootstrappedConfigFile string = "BootstrappedConfigFile" + BootstrappedConfig string = "BootstrappedConfig" + BootstrappedLevelDb string = "BootstrappedLevelDb" + BootstrappedEthereumClient string = "BootstrappedEthereumClient" + BootstrappedP2PClient string = "BootstrappedP2PClient" + BootstrappedP2PServer string = "BootstrappedP2PServer" + BootstrappedAPIServer string = "BootstrappedAPIServer" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/context/bootstrapper.go b/context/bootstrapper.go index bb14db7fd..a81f1f30f 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -30,8 +30,8 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - ðereum.Bootstrapper{}, - &anchors.Bootstrapper{}, + ethereum.Bootstrapper{}, + anchors.Bootstrapper{}, &identity.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index 9f8572677..a6b67e3bc 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -25,8 +25,8 @@ var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - ðereum.Bootstrapper{}, - &anchors.Bootstrapper{}, + ethereum.Bootstrapper{}, + anchors.Bootstrapper{}, &identity.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 93d00d01f..a108c680e 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -38,8 +38,13 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("service registry not initialised") } + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return fmt.Errorf("anchor repository not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository(), identity.IDService) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchorRepo, cfg), anchorRepo, identity.IDService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index 24c6274b1..ba17f1a06 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" ) @@ -21,7 +22,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - &anchors.Bootstrapper{}, + ethereum.Bootstrapper{}, + anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 0a9ca3182..1a441a474 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -37,8 +37,13 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("service registry not initialised") } + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return fmt.Errorf("anchor repository not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchors.GetAnchorRepository(), cfg), anchors.GetAnchorRepository(), identity.IDService) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchorRepo, cfg), anchorRepo, identity.IDService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/bootstrapper_test.go b/documents/purchaseorder/bootstrapper_test.go index c7368c503..caad770bc 100644 --- a/documents/purchaseorder/bootstrapper_test.go +++ b/documents/purchaseorder/bootstrapper_test.go @@ -7,10 +7,12 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" @@ -21,6 +23,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + ethereum.Bootstrapper{}, + anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 4359a4706..c90484257 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -7,10 +7,9 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) -type Bootstrapper struct { -} +type Bootstrapper struct{} -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { +func (Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } diff --git a/ethereum/test_bootstrapper.go b/ethereum/test_bootstrapper.go index df14ce082..9e9cb981d 100644 --- a/ethereum/test_bootstrapper.go +++ b/ethereum/test_bootstrapper.go @@ -2,10 +2,10 @@ package ethereum -func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { +func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { return b.Bootstrap(context) } -func (*Bootstrapper) TestTearDown() error { +func (Bootstrapper) TestTearDown() error { return nil } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index a9fe67fb1..490d49cd4 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -29,13 +29,17 @@ import ( "golang.org/x/crypto/ed25519" ) -var handler p2ppb.P2PServiceServer +var ( + handler p2ppb.P2PServiceServer + anchorRepo anchors.AnchorRepository +) func TestMain(m *testing.M) { flag.Parse() ctx := cc.TestFunctionalEthereumBootstrap() registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) handler = p2p.GRPCHandler(registry) + anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") @@ -114,7 +118,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations @@ -156,7 +160,7 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchors.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations From 3f9545cbd5007e6a73e0e355256612813cca8788 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 19 Nov 2018 16:18:18 +0100 Subject: [PATCH 034/220] add missing registry (#466) Fixes the functional tests --- p2p/bootstrapper.go | 12 +++++++++--- p2p/bootstrapper_test.go | 3 +++ p2p/server.go | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 3e3abdaef..b082a1bbd 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" ) // Bootstrapper implements Bootstrapper with p2p details @@ -12,12 +13,17 @@ type Bootstrapper struct{} // Bootstrap initiates p2p server and client into context func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + cfg, ok := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + if !ok { return fmt.Errorf("config not initialised") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) - srv := &p2pServer{config: cfg} + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("registry not initialised") + } + + srv := &p2pServer{config: cfg, registry: registry} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[bootstrap.BootstrappedP2PClient] = srv return nil diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 5527540f9..5ef408256 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,6 +5,8 @@ package p2p import ( "testing" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/node" @@ -22,6 +24,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config c := &config.Configuration{} m[bootstrap.BootstrappedConfig] = c + m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/server.go b/p2p/server.go index 4ac3d42af..be68bc06c 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -9,6 +9,7 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/documents" cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -40,6 +41,7 @@ type Config interface { type p2pServer struct { config Config host host.Host + registry *documents.ServiceRegistry protocol *p2pgrpc.GRPCProtocol } @@ -67,7 +69,7 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch // Set the grpc protocol handler on it s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) - p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), &handler{}) + p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), GRPCHandler(s.registry)) serveErr := make(chan error) go func() { From 7b9e354a6c9b0a531aa58db949a1f7c5e92a7dce Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 19 Nov 2018 18:44:46 +0100 Subject: [PATCH 035/220] Fix unit tests (#467) --- anchors/bootstrapper.go | 2 +- api/server_test.go | 11 +++++++++-- documents/invoice/bootstrapper_test.go | 11 +++++++---- documents/purchaseorder/bootstrapper_test.go | 11 +++++++---- identity/identity.go | 1 - identity/identity_test.go | 10 +++++----- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index dc98ecbd5..3c1b45bc6 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -25,8 +25,8 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { if _, ok := ctx[bootstrap.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } + client := ctx[bootstrap.BootstrappedEthereumClient].(ethereum.Client) - client := ethereum.GetClient() repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress("anchorRepository"), client.GetEthClient()) if err != nil { return err diff --git a/api/server_test.go b/api/server_test.go index 9f580e96a..45e05afd5 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -17,9 +17,9 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" ) @@ -32,7 +32,14 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - ethereum.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[bootstrap.BootstrappedEthereumClient] = ethClient + + ibootstappers = []bootstrap.TestBootstrapper{ anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index ba17f1a06..05010c70f 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -12,24 +12,27 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/commons" ) func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx := map[string]interface{}{ + bootstrap.BootstrappedEthereumClient: ethClient, + } ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - ethereum.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, } - - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) diff --git a/documents/purchaseorder/bootstrapper_test.go b/documents/purchaseorder/bootstrapper_test.go index caad770bc..05f5f7430 100644 --- a/documents/purchaseorder/bootstrapper_test.go +++ b/documents/purchaseorder/bootstrapper_test.go @@ -12,25 +12,28 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" ) func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx := map[string]interface{}{ + bootstrap.BootstrappedEthereumClient: ethClient, + } ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - ethereum.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, } - - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) diff --git a/identity/identity.go b/identity/identity.go index 30b2f6861..3cfc7a2f5 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -129,7 +129,6 @@ type Service interface { ValidateSignature(signature *coredocumentpb.Signature, message []byte) error } - // GetIdentityConfig returns the identity and keys associated with the node func GetIdentityConfig() (*IdentityConfig, error) { centIDBytes, err := config.Config().GetIdentityID() diff --git a/identity/identity_test.go b/identity/identity_test.go index 1e4a27df9..b20ef4174 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -10,11 +10,11 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/centrifuge/go-centrifuge/signatures" ) func TestMain(m *testing.M) { @@ -271,12 +271,12 @@ func TestValidateCentrifugeIDBytes(t *testing.T) { } func TestSign(t *testing.T) { - key1Pub := []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 := []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1Pub := []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 := []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} c := RandomCentID() msg := utils.RandomSlice(100) - sig := Sign(&IdentityConfig{c , map[int]IdentityKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) + sig := Sign(&IdentityConfig{c, map[int]IdentityKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) err := signatures.VerifySignature(key1Pub, msg, sig.Signature) assert.True(t, err == nil) -} \ No newline at end of file +} From 69259c39649bd0a3f750df09745bcc4a90fbc36c Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 20 Nov 2018 16:05:24 +0100 Subject: [PATCH 036/220] Remove global configuration usage (#460) * First Phase config * cleanup * global removal * added contextHeader * avoid cyclic deps * hell * hell 2 * pass duration param queue + fix unit tests * remove global config var * Remove global + queue timeout param * fix tests + config interface * comments * Fix unit tests * package Configs --- anchors/anchor.go | 9 + anchors/anchor_confirmation_task.go | 18 +- anchors/anchor_confirmation_task_test.go | 32 +++- anchors/anchor_repository_integration_test.go | 3 - anchors/anchor_test.go | 6 +- anchors/bootstrapper.go | 11 +- anchors/ethereum_anchor_repository.go | 19 +-- anchors/ethereum_anchor_repository_test.go | 3 +- anchors/test_bootstrapper.go | 6 +- api/bootstrapper.go | 2 +- api/bootstrapper_test.go | 2 +- api/server_test.go | 16 +- api/service.go | 9 +- bootstrap/bootstrapper.go | 9 +- cmd/create_config.go | 14 +- cmd/manage_identities.go | 2 - cmd/root.go | 15 +- config/bootstrapper.go | 11 +- config/configuration.go | 49 +++--- config/test_bootstrapper.go | 5 +- coredocument/coredocument.go | 8 +- coredocument/coredocument_test.go | 21 ++- coredocument/processor.go | 60 +++---- coredocument/processor_test.go | 89 +++++----- coredocument/validator.go | 14 +- coredocument/validator_test.go | 17 +- documents/anchor.go | 17 +- documents/invoice/bootstrapper.go | 12 +- documents/invoice/bootstrapper_test.go | 33 ---- documents/invoice/handler.go | 15 +- documents/invoice/handler_test.go | 23 ++- documents/invoice/model.go | 4 +- documents/invoice/model_test.go | 40 ++++- documents/invoice/service.go | 36 ++-- documents/invoice/service_test.go | 47 +++--- documents/invoice/validator_test.go | 5 +- documents/leveldb_test.go | 20 --- documents/model.go | 22 --- documents/model_test.go | 28 ++++ documents/purchaseorder/bootstrapper.go | 12 +- documents/purchaseorder/bootstrapper_test.go | 32 ---- documents/purchaseorder/handler.go | 11 +- documents/purchaseorder/handler_test.go | 43 +++-- documents/purchaseorder/model.go | 4 +- documents/purchaseorder/model_test.go | 40 ++++- documents/purchaseorder/service.go | 32 ++-- documents/purchaseorder/service_test.go | 43 ++--- documents/purchaseorder/validator_test.go | 5 +- documents/service.go | 3 +- documents/{ => test}/anchor_test.go | 49 ++++-- documents/test_bootstrapper.go | 6 +- ethereum/bootstrapper.go | 9 +- ethereum/geth_client.go | 23 +-- ethereum/geth_client_integration_test.go | 7 +- ethereum/geth_client_test.go | 17 +- header/context.go | 35 ++++ healthcheck/handler_test.go | 2 +- identity/bootstrapper.go | 9 +- identity/ethereum_identity.go | 40 +++-- .../ethereum_identity_integration_test.go | 28 ++-- identity/ethereum_identity_test.go | 33 ++-- identity/id_registration_confirmation_task.go | 23 ++- .../id_registration_confirmation_task_test.go | 7 +- identity/identity.go | 20 ++- identity/identity_test.go | 50 +++--- .../key_registration_confirmation_task.go | 21 ++- ...key_registration_confirmation_task_test.go | 42 ++++- identity/util.go | 15 +- keytools/ed25519/ed25519.go | 6 +- keytools/ed25519/ed25519_test.go | 24 +-- keytools/secp256k1/secp256k1.go | 6 +- keytools/secp256k1/secp256k1_test.go | 24 +-- nft/bootstrapper.go | 9 +- nft/ethereum_payment_obligation.go | 37 +++-- nft/ethereum_payment_obligation_test.go | 39 +---- nft/minting_confirmation_task.go | 33 ++-- nft/minting_confirmation_task_test.go | 15 +- nft/payment_obligation_integration_test.go | 35 ++-- p2p/bootstrapper.go | 8 +- p2p/bootstrapper_test.go | 6 +- p2p/client.go | 9 +- p2p/handler.go | 18 +- p2p/handler_integration_test.go | 28 ++-- p2p/handler_test.go | 28 ++-- p2p/server.go | 7 +- p2p/server_test.go | 12 +- p2p/validator.go | 11 +- p2p/validator_test.go | 11 +- queue/bootstrapper.go | 5 +- queue/queue.go | 30 ++++ storage/bootstrapper.go | 9 +- storage/test_bootstrapper.go | 12 +- testingutils/config/config.go | 154 ++++++++++++++++++ testingutils/coredocument/coredocument.go | 15 +- testingutils/documents/documents.go | 3 +- testingutils/identity/identity.go | 9 +- 96 files changed, 1181 insertions(+), 835 deletions(-) create mode 100644 documents/model_test.go rename documents/{ => test}/anchor_test.go (70%) create mode 100644 header/context.go create mode 100644 testingutils/config/config.go diff --git a/anchors/anchor.go b/anchors/anchor.go index ef90198b8..19f571f34 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -4,8 +4,11 @@ import ( "errors" "math/big" + "time" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -26,6 +29,12 @@ const ( // AnchorID type is byte array of length AnchorIDLength type AnchorID [AnchorIDLength]byte +type Config interface { + GetEthereumDefaultAccountName() string + GetEthereumContextWaitTimeout() time.Duration + GetContractAddress(address string) common.Address +} + // ToAnchorID convert the bytes into AnchorID type // returns an error if the bytes length != AnchorIDLength func ToAnchorID(bytes []byte) (AnchorID, error) { diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index 0a5272cf6..5dfe90e7e 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -40,9 +40,10 @@ type anchorConfirmationTask struct { AnchorID AnchorID CentrifugeID identity.CentID BlockHeight uint64 + Timeout time.Duration // state - EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + EthContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) EthContext context.Context AnchorCommittedFilterer anchorCommittedWatcher } @@ -65,6 +66,7 @@ func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { act.AnchorID, act.CentrifugeID, act.BlockHeight, + act.Timeout, act.EthContextInitializer, act.EthContext, act.AnchorCommittedFilterer, @@ -113,6 +115,7 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", AddressParam, err.Error()) } + act.From = addressTyped if bhi, ok := kwargs[BlockHeight]; ok { bhf, ok := bhi.(float64) @@ -121,7 +124,16 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er } } - act.From = addressTyped + // Override default timeout param + tdRaw, ok := kwargs[queue.TimeoutParam] + if ok { + td, err := queue.GetDuration(tdRaw) + if err != nil { + return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + } + act.Timeout = td + } + return nil } @@ -129,7 +141,7 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er func (act *anchorConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the anchorID [%x]", act.AnchorID) if act.EthContext == nil { - act.EthContext, _ = act.EthContextInitializer() + act.EthContext, _ = act.EthContextInitializer(act.Timeout) } fOpts := &bind.FilterOpts{ diff --git a/anchors/anchor_confirmation_task_test.go b/anchors/anchor_confirmation_task_test.go index 8c711b23c..b925261d3 100644 --- a/anchors/anchor_confirmation_task_test.go +++ b/anchors/anchor_confirmation_task_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -37,15 +38,17 @@ func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { address := common.BytesToAddress([]byte{1, 2, 3, 4}) centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - + timeout := float64(5000) kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, - AddressParam: address, - CentrifugeIDParam: centId, - BlockHeight: float64(0), + AnchorIDParam: anchorID, + AddressParam: address, + CentrifugeIDParam: centId, + BlockHeight: float64(0), + queue.TimeoutParam: timeout, }) err := act.ParseKwargs(kwargs) if err != nil { + assert.Nil(t, err) t.Fatalf("Could not parse %s or %s", AnchorIDParam, AddressParam) } @@ -53,6 +56,7 @@ func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { assert.Equal(t, anchorID, anchorID, "Resulting anchor Id should have the same ID as the input") assert.Equal(t, address, act.From, "Resulting address should have the same ID as the input") assert.Equal(t, centId, act.CentrifugeID, "Resulting centId should have the same centId as the input") + assert.Equal(t, time.Duration(timeout), act.Timeout, "Resulting timeout should have the same timeout as the input") } func TestAnchoringConfirmationTask_ParseKwargsAnchorNotPassed(t *testing.T) { @@ -102,6 +106,24 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAddress(t *testing.T) { assert.NotNil(t, err, "address should not have been parsed because it was of incorrect type") } +func TestAnchoringConfirmationTask_ParseKwargsInvalidTimeout(t *testing.T) { + act := anchorConfirmationTask{} + anchorID, _ := ToAnchorID(utils.RandomSlice(AnchorIDLength)) + address := common.BytesToAddress([]byte{1, 2, 3, 4}) + + centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + timeout := "int64" + kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ + AnchorIDParam: anchorID, + AddressParam: address, + CentrifugeIDParam: centId, + BlockHeight: float64(0), + queue.TimeoutParam: timeout, + }) + err := act.ParseKwargs(kwargs) + assert.NotNil(t, err, "timeout should not have been parsed because it was of incorrect type") +} + func TestAnchoringConfirmationTask_RunTaskIterError(t *testing.T) { anchorID := [32]byte{1, 2, 3} address := common.BytesToAddress([]byte{1, 2, 3, 4}) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 6983f2338..8acf2e871 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -32,14 +32,11 @@ func TestMain(m *testing.M) { } func createIdentityWithKeys(t *testing.T, centrifugeId []byte) []byte { - centIdTyped, _ := identity.ToCentID(centrifugeId) id, confirmations, err := identityService.CreateIdentity(centIdTyped) assert.Nil(t, err, "should not error out when creating identity") - watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - // LookupIdentityForId id, err = identityService.LookupIdentityForID(centIdTyped) assert.Nil(t, err, "should not error out when resolving identity") diff --git a/anchors/anchor_test.go b/anchors/anchor_test.go index b1f0ed076..a4ec28c71 100644 --- a/anchors/anchor_test.go +++ b/anchors/anchor_test.go @@ -12,11 +12,15 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg Config + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(Config) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 3c1b45bc6..629cc24bc 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -3,7 +3,6 @@ package anchors import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" @@ -17,15 +16,15 @@ type Bootstrapper struct{} // Bootstrap initializes the AnchorRepositoryContract as well as the anchorConfirmationTask that depends on it. // the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(Config) - if _, ok := ctx[bootstrap.BootstrappedEthereumClient]; !ok { + if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } - client := ctx[bootstrap.BootstrappedEthereumClient].(ethereum.Client) + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress("anchorRepository"), client.GetEthClient()) if err != nil { @@ -37,6 +36,8 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { ctx[BootstrappedAnchorRepo] = repo task := &anchorConfirmationTask{ + // Passing timeout as a common property for every request, if we need more fine-grain control per request then we will override by invoker + Timeout: cfg.GetEthereumContextWaitTimeout(), AnchorCommittedFilterer: &repositoryContract.EthereumAnchorRepositoryContractFilterer, EthContextInitializer: ethereum.DefaultWaitForTransactionMiningContext, } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 724c196db..1693724f5 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -4,6 +4,8 @@ import ( "context" "math/big" + "time" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -15,10 +17,6 @@ import ( "github.com/go-errors/errors" ) -type Config interface { - GetEthereumDefaultAccountName() string -} - type AnchorRepositoryContract interface { PreCommit(opts *bind.TransactOpts, anchorID *big.Int, signingRoot [32]byte, centrifugeId *big.Int, signature []byte, expirationBlock *big.Int) (*types.Transaction, error) Commit(opts *bind.TransactOpts, _anchorID *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) @@ -89,7 +87,7 @@ func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, d } cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, centrifugeId, documentProofs, signature) - confirmations, err = setUpCommitEventListener(opts.From, cd) + confirmations, err = setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) if err != nil { wError := errors.Wrap(err, 1) log.Errorf("Failed to set up event listener for commit transaction [id: %x, hash: %x]: %v", @@ -143,9 +141,10 @@ func sendCommitTransaction(contract AnchorRepositoryContract, opts *bind.Transac return } +// TODO: This method is only used by setUpPreCommitEventListener below, it will be changed soon so we can remove the hardcoded `time.Second` and use the global one func generateEventContext() (*bind.WatchOpts, context.CancelFunc) { //listen to this particular anchor being mined/event is triggered - ctx, cancelFunc := ethereum.DefaultWaitForTransactionMiningContext() + ctx, cancelFunc := ethereum.DefaultWaitForTransactionMiningContext(time.Second) watchOpts := &bind.WatchOpts{Context: ctx} return watchOpts, cancelFunc @@ -177,7 +176,7 @@ func setUpPreCommitEventListener(contractEvent WatchAnchorPreCommitted, from com // setUpCommitEventListener sets up the listened for the "AnchorCommitted" event to notify the upstream code // about successful mining/creation of a commit -func setUpCommitEventListener(from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { +func setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { confirmations = make(chan *WatchCommit) asyncRes, err := queue.Queue.DelayKwargs(AnchorRepositoryConfirmationTaskName, map[string]interface{}{ AnchorIDParam: commitData.AnchorID, @@ -189,7 +188,7 @@ func setUpCommitEventListener(from common.Address, commitData *CommitData) (conf return nil, err } - go waitAndRouteCommitEvent(asyncRes, confirmations, commitData) + go waitAndRouteCommitEvent(timeout, asyncRes, confirmations, commitData) return confirmations, nil } @@ -210,7 +209,7 @@ func waitAndRoutePreCommitEvent(conf <-chan *EthereumAnchorRepositoryContractAnc } // waitAndRouteCommitEvent notifies the confirmations channel whenever a commit is being noted as Ethereum event -func waitAndRouteCommitEvent(asyncResult *gocelery.AsyncResult, confirmations chan<- *WatchCommit, commitData *CommitData) { - _, err := asyncResult.Get(ethereum.GetDefaultContextTimeout()) +func waitAndRouteCommitEvent(timeout time.Duration, asyncResult *gocelery.AsyncResult, confirmations chan<- *WatchCommit, commitData *CommitData) { + _, err := asyncResult.Get(timeout) confirmations <- &WatchCommit{commitData, err} } diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 85691d4fd..144398578 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -6,7 +6,6 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" @@ -81,7 +80,7 @@ func TestGetDocumentRootOf(t *testing.T) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetGethCallOpts").Return(nil) - ethRepo := NewEthereumAnchorRepository(config.Config(), repo, func() ethereum.Client { + ethRepo := NewEthereumAnchorRepository(cfg, repo, func() ethereum.Client { return ethClient }) docRoot := utils.RandomByte32() diff --git a/anchors/test_bootstrapper.go b/anchors/test_bootstrapper.go index edb06d1ad..dda502e8f 100644 --- a/anchors/test_bootstrapper.go +++ b/anchors/test_bootstrapper.go @@ -5,11 +5,13 @@ package anchors import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" ) +const BootstrappedAnchorRepository string = "BootstrappedAnchorRepository" + func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 92337d70a..7cc012d54 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -13,7 +13,7 @@ type Bootstrapper struct{} // Bootstrap initiates api server func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg, ok := ctx[config.BootstrappedConfig].(Config) if !ok { return fmt.Errorf("config not initialised") } diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index b96b73158..b9873e422 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -22,7 +22,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config c := &config.Configuration{} - m[bootstrap.BootstrappedConfig] = c + m[config.BootstrappedConfig] = c m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/api/server_test.go b/api/server_test.go index 45e05afd5..256ff734f 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -17,6 +17,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -28,18 +29,14 @@ var cfg *config.Configuration var registry *documents.ServiceRegistry func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - - ethClient := &testingcommons.MockEthClient{} - ethClient.On("GetEthClient").Return(nil) - ctx[bootstrap.BootstrappedEthereumClient] = ethClient - - ibootstappers = []bootstrap.TestBootstrapper{ anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, @@ -47,7 +44,8 @@ func TestMain(m *testing.M) { &purchaseorder.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) flag.Parse() result := m.Run() diff --git a/api/service.go b/api/service.go index be88dad06..c4dfee8ca 100644 --- a/api/service.go +++ b/api/service.go @@ -3,6 +3,7 @@ package api import ( "fmt" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" @@ -19,7 +20,7 @@ import ( ) // registerServices registers all endpoints to the grpc server -func registerServices(ctx context.Context, config Config, registry *documents.ServiceRegistry, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { +func registerServices(ctx context.Context, cfg Config, registry *documents.ServiceRegistry, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { // documents (common) documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler(registry)) err := documentpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) @@ -28,7 +29,8 @@ func registerServices(ctx context.Context, config Config, registry *documents.Se } // invoice - handler, err := invoice.GRPCHandler(registry) + invCfg := cfg.(config.Config) + handler, err := invoice.GRPCHandler(invCfg, registry) if err != nil { return err } @@ -51,7 +53,8 @@ func registerServices(ctx context.Context, config Config, registry *documents.Se } // healthcheck - healthpb.RegisterHealthCheckServiceServer(grpcServer, healthcheck.GRPCHandler(config)) + hcCfg := cfg.(healthcheck.Config) + healthpb.RegisterHealthCheckServiceServer(grpcServer, healthcheck.GRPCHandler(hcCfg)) err = healthpb.RegisterHealthCheckServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 6a286eaec..dbee1406a 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -3,13 +3,8 @@ package bootstrap // DO NOT PUT any app logic in this package to avoid any dependency cycles const ( - BootstrappedConfigFile string = "BootstrappedConfigFile" - BootstrappedConfig string = "BootstrappedConfig" - BootstrappedLevelDb string = "BootstrappedLevelDb" - BootstrappedEthereumClient string = "BootstrappedEthereumClient" - BootstrappedP2PClient string = "BootstrappedP2PClient" - BootstrappedP2PServer string = "BootstrappedP2PServer" - BootstrappedAPIServer string = "BootstrappedAPIServer" + BootstrappedP2PServer string = "BootstrappedP2PServer" + BootstrappedAPIServer string = "BootstrappedAPIServer" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/cmd/create_config.go b/cmd/create_config.go index 84d102fc2..3bfbae2cc 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -30,9 +30,9 @@ func createIdentity() (identity.CentID, error) { return centrifugeId, nil } -func generateKeys() { - p2pPub, p2pPvt := config.Config().GetSigningKeyPair() - ethAuthPub, ethAuthPvt := config.Config().GetEthAuthKeyPair() +func generateKeys(config config.Config) { + p2pPub, p2pPvt := config.GetSigningKeyPair() + ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") @@ -84,8 +84,10 @@ func init() { } log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) - baseBootstrap(v.ConfigFileUsed()) - generateKeys() + ctx := baseBootstrap(v.ConfigFileUsed()) + cfg := ctx[config.BootstrappedConfig].(*config.Configuration) + generateKeys(cfg) + id, err := createIdentity() if err != nil { panic(err) @@ -96,7 +98,7 @@ func init() { if err != nil { log.Fatalf("error: %v", err) } - config.Config().Set("identityId", id.String()) + cfg.Set("identityId", id.String()) log.Infof("Identity created [%s] [%x]", id.String(), id) diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 165e2a042..0f7f26741 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -53,8 +53,6 @@ var addKeyCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file cfgFile = ensureConfigFile() - baseBootstrap(cfgFile) - var purposeInt int switch purpose { diff --git a/cmd/root.go b/cmd/root.go index aebf87b7f..21c648de1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/centrifuge/go-centrifuge/bootstrap" - cc "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" "github.com/mitchellh/go-homedir" @@ -86,10 +86,10 @@ func setCentrifugeLoggers() { } func runBootstrap(cfgFile string) { - mb := cc.MainBootstrapper{} + mb := context.MainBootstrapper{} mb.PopulateRunBootstrappers() ctx := map[string]interface{}{} - ctx[bootstrap.BootstrappedConfigFile] = cfgFile + ctx[config.BootstrappedConfigFile] = cfgFile err := mb.Bootstrap(ctx) if err != nil { // application must not continue to run @@ -97,14 +97,15 @@ func runBootstrap(cfgFile string) { } } -func baseBootstrap(cfgFile string) { - mb := cc.MainBootstrapper{} +func baseBootstrap(cfgFile string) map[string]interface{} { + mb := context.MainBootstrapper{} mb.PopulateBaseBootstrappers() ctx := map[string]interface{}{} - ctx[bootstrap.BootstrappedConfigFile] = cfgFile + ctx[config.BootstrappedConfigFile] = cfgFile err := mb.Bootstrap(ctx) if err != nil { // application must not continue to run panic(err) } + return ctx } diff --git a/config/bootstrapper.go b/config/bootstrapper.go index 8333652bc..ed30608a7 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -2,17 +2,20 @@ package config import ( "errors" +) - "github.com/centrifuge/go-centrifuge/bootstrap" +const ( + BootstrappedConfig string = "BootstrappedConfig" + BootstrappedConfigFile string = "BootstrappedConfigFile" ) type Bootstrapper struct{} func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfigFile]; !ok { + if _, ok := context[BootstrappedConfigFile]; !ok { return errors.New("config file hasn't been provided") } - cfgFile := context[bootstrap.BootstrappedConfigFile].(string) - context[bootstrap.BootstrappedConfig] = NewConfiguration(cfgFile) + cfgFile := context[BootstrappedConfigFile].(string) + context[BootstrappedConfig] = NewConfiguration(cfgFile) return nil } diff --git a/config/configuration.go b/config/configuration.go index 9a5a18e37..68112758c 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -27,24 +27,35 @@ import ( var log = logging.Logger("config") -// configMu protects the config from read/write -var configMu sync.RWMutex - -// config holds the current node config -var config *Configuration - -// Config returns the current loaded config -func Config() *Configuration { - configMu.RLock() - defer configMu.RUnlock() - return config -} - -// SetConfig sets the config -func SetConfig(c *Configuration) { - configMu.Lock() - defer configMu.Unlock() - config = c +type Config interface { + GetStoragePath() string + GetP2PPort() int + GetP2PExternalIP() string + GetP2PConnectionTimeout() time.Duration + GetReceiveEventNotificationEndpoint() string + GetServerPort() int + GetServerAddress() string + GetNumWorkers() int + GetWorkerWaitTimeMS() int + GetEthereumNodeURL() string + GetEthereumContextReadWaitTimeout() time.Duration + GetEthereumContextWaitTimeout() time.Duration + GetEthereumIntervalRetry() time.Duration + GetEthereumMaxRetries() int + GetEthereumGasPrice() *big.Int + GetEthereumGasLimit() uint64 + GetEthereumDefaultAccountName() string + GetEthereumAccount(accountName string) (account *AccountConfig, err error) + GetTxPoolAccessEnabled() bool + GetNetworkString() string + GetNetworkKey(k string) string + GetContractAddressString(address string) string + GetContractAddress(address string) common.Address + GetBootstrapPeers() []string + GetNetworkID() uint32 + GetIdentityID() ([]byte, error) + GetSigningKeyPair() (pub, priv string) + GetEthAuthKeyPair() (pub, priv string) } // Configuration holds the configuration details for the node @@ -267,8 +278,6 @@ func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { func NewConfiguration(configFile string) *Configuration { cfg := &Configuration{configFile: configFile, mu: sync.RWMutex{}} cfg.InitializeViper() - //TODO Will remove this soon, when we do not use global config variable - SetConfig(cfg) return cfg } diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 8a50149f3..07019b9e9 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -6,8 +6,6 @@ import ( "fmt" "path/filepath" "strings" - - "github.com/centrifuge/go-centrifuge/bootstrap" ) func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { @@ -24,11 +22,10 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { } } c := NewConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) - context[bootstrap.BootstrappedConfig] = c + context[BootstrappedConfig] = c return nil } func (b *Bootstrapper) TestTearDown() error { - SetConfig(nil) return nil } diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index c2c7eab37..c8d1e8893 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -209,19 +209,15 @@ func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, } // GetExternalCollaborators returns collaborators of a document without the own centID -func GetExternalCollaborators(doc *coredocumentpb.CoreDocument) ([][]byte, error) { +func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.CoreDocument) ([][]byte, error) { var collabs [][]byte - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return nil, fmt.Errorf("failed to get identity config: %v", err) - } for _, collab := range doc.Collaborators { collabID, err := identity.ToCentID(collab) if err != nil { return nil, fmt.Errorf("failed to convert to CentID: %v", err) } - if !idConfig.ID.Equal(collabID) { + if !selfCentID.Equal(collabID) { collabs = append(collabs, collab) } } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index e0eab27ae..015d2fee1 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -9,10 +9,13 @@ import ( "flag" "os" + "context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -37,7 +40,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) flag.Parse() cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") @@ -243,23 +246,23 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - collaborators, err := GetExternalCollaborators(cd) + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + collaborators, err := GetExternalCollaborators(ctxh.Self().ID, cd) assert.Nil(t, err) assert.NotNil(t, collaborators) assert.Equal(t, [][]byte{c1, c2}, collaborators) } -func TestGetExternalCollaborators_ErrorConfig(t *testing.T) { +func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { c1 := utils.RandomSlice(6) c2 := utils.RandomSlice(6) c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - currentKeyPath, _ := cfg.GetSigningKeyPair() - //Wrong path - cfg.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") - collaborators, err := GetExternalCollaborators(cd) + cd.Collaborators[1] = utils.RandomSlice(5) + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + _, err = GetExternalCollaborators(ctxh.Self().ID, cd) assert.NotNil(t, err) - assert.Nil(t, collaborators) - cfg.Set("keys.signing.publicKey", currentKeyPath) } diff --git a/coredocument/processor.go b/coredocument/processor.go index 22ecdac12..43a759eab 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -1,7 +1,6 @@ package coredocument import ( - "context" "fmt" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -9,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/utils" @@ -18,7 +18,6 @@ import ( var log = logging.Logger("coredocument") -// config defines functions to get processor details type Config interface { GetNetworkID() uint32 GetIdentityID() ([]byte, error) @@ -27,19 +26,19 @@ type Config interface { // Processor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type Processor interface { - Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) - PrepareForSignatureRequests(model documents.Model) error - RequestSignatures(ctx context.Context, model documents.Model) error + Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) + PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error + RequestSignatures(ctx *header.ContextHeader, model documents.Model) error PrepareForAnchoring(model documents.Model) error - AnchorDocument(model documents.Model) error - SendDocument(ctx context.Context, model documents.Model) error + AnchorDocument(ctx *header.ContextHeader, model documents.Model) error + SendDocument(ctx *header.ContextHeader, model documents.Model) error } // client defines the methods for p2pclient // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { OpenClient(target string) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // defaultProcessor implements Processor interface @@ -61,7 +60,7 @@ func DefaultProcessor(idService identity.Service, p2pClient client, repository a } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { if coreDocument == nil { return centerrors.NilError(coreDocument) } @@ -85,19 +84,15 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } log.Infof("Done opening connection against [%s]\n", lastB58Key) - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return centerrors.Wrap(err, "failed to get IDConfig") - } - + idConfig := ctx.Self() centIDBytes := idConfig.ID[:] - header := &p2ppb.CentrifugeHeader{ + p2pheader := &p2ppb.CentrifugeHeader{ SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: dp.config.GetNetworkID(), } - resp, err := client.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: header}) + resp, err := client.SendAnchoredDocument(ctx.Context(), &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) if err != nil || !resp.Accepted { return centerrors.Wrap(err, "failed to send document to the node") } @@ -106,7 +101,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature -func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) error { +func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return fmt.Errorf("failed to pack core document: %v", err) @@ -118,12 +113,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) er return fmt.Errorf("failed to calculate signing root: %v", err) } - // sign document with own key and append it to signatures - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return fmt.Errorf("failed to get keys for signing: %v", err) - } - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) + sig := identity.Sign(ctx.Self(), identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) @@ -136,13 +126,18 @@ func (dp defaultProcessor) PrepareForSignatureRequests(model documents.Model) er // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, -func (dp defaultProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) RequestSignatures(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return fmt.Errorf("failed to pack core document: %v", err) } - psv := PreSignatureRequestValidator() + idKeys, ok := ctx.Self().Keys[identity.KeyPurposeSigning] + if !ok { + return fmt.Errorf("missing keys for signing") + } + + psv := PreSignatureRequestValidator(ctx.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) err = psv.Validate(nil, model) if err != nil { return fmt.Errorf("failed to validate model for signature request: %v", err) @@ -188,7 +183,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { } // AnchorDocument validates the model, and anchors the document -func (dp defaultProcessor) AnchorDocument(model documents.Model) error { +func (dp defaultProcessor) AnchorDocument(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return fmt.Errorf("failed to pack core document: %v", err) @@ -215,18 +210,13 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { return fmt.Errorf("centID invalid: %v", err) } - // generate message authentication code for the anchor call - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return fmt.Errorf("failed to get eth keys: %v", err) - } - anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { return fmt.Errorf("failed to get anchor ID: %v", err) } - mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) + // generate message authentication code for the anchor call + mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), ctx.Self().Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { return fmt.Errorf("failed to generate ethereum MAC: %v", err) } @@ -243,7 +233,7 @@ func (dp defaultProcessor) AnchorDocument(model documents.Model) error { } // SendDocument does post anchor validations and sends the document to collaborators -func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) SendDocument(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return fmt.Errorf("failed to pack core document: %v", err) @@ -255,7 +245,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Mod return fmt.Errorf("post anchor validations failed: %v", err) } - extCollaborators, err := GetExternalCollaborators(cd) + extCollaborators, err := GetExternalCollaborators(ctx.Self().ID, cd) if err != nil { return fmt.Errorf("get external collaborators failed: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 6bdd2cbff..e58b69806 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -47,7 +48,9 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err := dp.PrepareForSignatureRequests(model) + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -67,17 +70,17 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - err = dp.PrepareForSignatureRequests(model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get keys for signing") + ctxh, err = header.NewContextHeader(context.Background(), cfg) + assert.NotNil(t, err) cfg.Set("keys.signing.publicKey", pub) + ctxh, err = header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) // failed unpack model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() - err = dp.PrepareForSignatureRequests(model) + err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unpack the core document") @@ -87,14 +90,13 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() - err = dp.PrepareForSignatureRequests(model) + err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, cd.Signatures) assert.Len(t, cd.Signatures, 1) sig := cd.Signatures[0] - id, err := identity.GetIdentityConfig() - assert.Nil(t, err) + id := ctxh.Self() assert.True(t, ed25519.Verify(id.Keys[identity.KeyPurposeSigning].PublicKey, cd.SigningRoot, sig.Signature)) } @@ -103,7 +105,7 @@ type p2pClient struct { client } -func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (p p2pClient) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { args := p.Called(ctx, doc) return args.Error(0) } @@ -111,11 +113,13 @@ func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - // pack failed ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) + // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err := dp.RequestSignatures(ctx, model) + err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -124,7 +128,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { cd := new(coredocumentpb.CoreDocument) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) - err = dp.RequestSignatures(ctx, model) + err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to validate model for signature request") @@ -140,15 +144,15 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() - err = dp.PrepareForSignatureRequests(model) + err = dp.PrepareForSignatureRequests(ctxh, model) assert.Nil(t, err) model.AssertExpectations(t) c := p2pClient{} - c.On("GetSignaturesForDocument", ctx, cd).Return(fmt.Errorf("error")).Once() + c.On("GetSignaturesForDocument", ctxh, cd).Return(fmt.Errorf("error")).Once() dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) - err = dp.RequestSignatures(ctx, model) + err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) assert.Error(t, err) @@ -156,12 +160,12 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // unpack fail c = p2pClient{} - c.On("GetSignaturesForDocument", ctx, cd).Return(nil).Once() + c.On("GetSignaturesForDocument", ctxh, cd).Return(nil).Once() dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() - err = dp.RequestSignatures(ctx, model) + err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) assert.Error(t, err) @@ -169,12 +173,12 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // success c = p2pClient{} - c.On("GetSignaturesForDocument", ctx, cd).Return(nil).Once() + c.On("GetSignaturesForDocument", ctxh, cd).Return(nil).Once() dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(nil).Once() - err = dp.RequestSignatures(ctx, model) + err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) assert.Nil(t, err) @@ -213,7 +217,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() - c, err := identity.GetIdentityConfig() + c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} @@ -257,10 +261,14 @@ func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.Document func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) + ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) + // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err := dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -269,7 +277,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { model = mockModel{} cd := new(coredocumentpb.CoreDocument) model.On("PackCoreDocument").Return(cd, nil).Times(5) - err = dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pre anchor validation failed") @@ -285,7 +293,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) - c, err := identity.GetIdentityConfig() + c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} @@ -294,7 +302,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() oldID := cfg.GetString("identityId") cfg.Set("identityId", "wrong id") - err = dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Error(t, err) @@ -306,27 +314,13 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Times(5) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - err = dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "centID invalid") cfg.Set("identityId", oldID) - // missing eth keys - oldPth := cfg.Get("keys.ethauth.publicKey") - cfg.Set("keys.ethauth.publicKey", "wrong path") - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - - err = dp.AnchorDocument(model) - model.AssertExpectations(t) - srv.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get eth keys") - cfg.Set("keys.ethauth.publicKey", oldPth) - // failed anchor commit model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) @@ -335,7 +329,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { repo := mockRepo{} repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error")).Once() dp.anchorRepository = repo - err = dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) repo.AssertExpectations(t) @@ -352,7 +346,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { ch <- new(anchors.WatchCommit) repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ch, nil).Once() dp.anchorRepository = repo - err = dp.AnchorDocument(model) + err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) repo.AssertExpectations(t) @@ -364,11 +358,12 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err := dp.SendDocument(ctx, model) + err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -377,7 +372,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model = mockModel{} cd := new(coredocumentpb.CoreDocument) model.On("PackCoreDocument").Return(cd, nil).Times(6) - err = dp.SendDocument(ctx, model) + err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "post anchor validations failed") @@ -394,7 +389,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Nil(t, CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(6) - c, err := identity.GetIdentityConfig() + c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} @@ -404,7 +399,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { repo := mockRepo{} repo.On("GetDocumentRootOf", mock.Anything).Return(docRoot, nil).Once() dp.anchorRepository = repo - err = dp.SendDocument(ctx, model) + err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) repo.AssertExpectations(t) diff --git a/coredocument/validator.go b/coredocument/validator.go index 3d8ef63d3..d8fd6f3d5 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -200,7 +201,7 @@ func documentRootValidator() documents.Validator { // re-calculates the signature and compares with existing one // assumes signing_root is already generated and verified // Note: this needs to used only before document is sent for signatures from the collaborators -func readyForSignaturesValidator() documents.Validator { +func readyForSignaturesValidator(centIDBytes, priv, pub []byte) documents.Validator { return documents.ValidatorFunc(func(_, model documents.Model) error { cd, err := getCoreDocument(model) if err != nil { @@ -211,12 +212,7 @@ func readyForSignaturesValidator() documents.Validator { return fmt.Errorf("expecting only one signature") } - c, err := identity.GetIdentityConfig() - if err != nil { - return fmt.Errorf("failed to get keys for signature calculation: %v", err) - } - - s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + s := signatures.Sign(centIDBytes, priv, pub, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { err = documents.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) @@ -331,11 +327,11 @@ func PostAnchoredValidator(idService identity.Service, repo anchors.AnchorReposi // signingRootValidator // readyForSignaturesValidator // should be called after sender signing the document and before requesting the document -func PreSignatureRequestValidator() documents.ValidatorGroup { +func PreSignatureRequestValidator(centIDBytes, priv, pub []byte) documents.ValidatorGroup { return documents.ValidatorGroup{ baseValidator(), signingRootValidator(), - readyForSignaturesValidator(), + readyForSignaturesValidator(centIDBytes, priv, pub), } } diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 0cc7e24f8..975ede063 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -8,10 +8,13 @@ import ( "errors" + "context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -206,12 +209,15 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - rfsv := readyForSignaturesValidator() + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] + rfsv := readyForSignaturesValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) // fail getCoreDoc model := mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() - err := rfsv.Validate(nil, model) + err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -242,7 +248,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { // success cd.SigningRoot = utils.RandomSlice(32) - c, err := identity.GetIdentityConfig() + c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} @@ -534,7 +540,10 @@ func TestPostAnchoredValidator(t *testing.T) { } func TestPreSignatureRequestValidator(t *testing.T) { - psv := PreSignatureRequestValidator() + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] + psv := PreSignatureRequestValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) assert.Len(t, psv, 3) } diff --git a/documents/anchor.go b/documents/anchor.go index 15a368b9a..0a70867fd 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -1,19 +1,20 @@ package documents import ( - "context" "fmt" + + "github.com/centrifuge/go-centrifuge/header" ) // anchorProcessor has same methods to coredoc processor // this is to avoid import cycles // this will disappear once we have queueing logic in place type anchorProcessor interface { - PrepareForSignatureRequests(model Model) error - RequestSignatures(ctx context.Context, model Model) error + PrepareForSignatureRequests(ctx *header.ContextHeader, model Model) error + RequestSignatures(ctx *header.ContextHeader, model Model) error PrepareForAnchoring(model Model) error - AnchorDocument(model Model) error - SendDocument(ctx context.Context, model Model) error + AnchorDocument(ctx *header.ContextHeader, model Model) error + SendDocument(ctx *header.ContextHeader, model Model) error } // updaterFunc is a wrapper that will be called to save the state of the model between processor steps @@ -21,14 +22,14 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators -func AnchorDocument(ctx context.Context, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { +func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { cd, err := model.PackCoreDocument() if err != nil { return nil, err } id := cd.CurrentVersion - err = proc.PrepareForSignatureRequests(model) + err = proc.PrepareForSignatureRequests(ctx, model) if err != nil { return nil, fmt.Errorf("failed to prepare document for signatures: %v", err) } @@ -58,7 +59,7 @@ func AnchorDocument(ctx context.Context, model Model, proc anchorProcessor, upda return nil, err } - err = proc.AnchorDocument(model) + err = proc.AnchorDocument(ctx, model) if err != nil { return nil, fmt.Errorf("failed to anchor document: %v", err) } diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index a108c680e..de83bc8c0 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -6,29 +6,29 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/storage" ) type Bootstrapper struct{} // Bootstrap sets the required storage and registers -func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[bootstrap.BootstrappedLevelDb]; !ok { + if _, ok := ctx[storage.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } - p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) + p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") } diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index 05010c70f..e299b8ead 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -3,42 +3,9 @@ package invoice import ( - "flag" - "os" "testing" - - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/testingutils/commons" ) -func TestMain(m *testing.M) { - ethClient := &testingcommons.MockEthClient{} - ethClient.On("GetEthClient").Return(nil) - ctx := map[string]interface{}{ - bootstrap.BootstrappedEthereumClient: ethClient, - } - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &storage.Bootstrapper{}, - anchors.Bootstrapper{}, - documents.Bootstrapper{}, - p2p.Bootstrapper{}, - &Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - flag.Parse() - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - func TestBootstrapper_Bootstrap(t *testing.T) { //err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) //assert.Error(t, err, "Should throw an error because of empty context") diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index dd005035f..9c6b9f65c 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -6,11 +6,14 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" "golang.org/x/net/context" + + "github.com/centrifuge/go-centrifuge/header" ) var apiLog = logging.Logger("invoice-api") @@ -19,10 +22,11 @@ var apiLog = logging.Logger("invoice-api") // anchoring, sending, finding stored invoice document type grpcHandler struct { service Service + config config.Config } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { +func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) if err != nil { return nil, err @@ -30,13 +34,14 @@ func GRPCHandler(registry *documents.ServiceRegistry) (clientinvoicepb.DocumentS return &grpcHandler{ service: srv.(Service), + config: config, }, nil } // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - ctxHeader, err := documents.NewContextHeader() + ctxHeader, err := header.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -49,7 +54,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr } // validate and persist - doc, err = h.service.Create(ctx, doc) + doc, err = h.service.Create(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, err @@ -61,7 +66,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := documents.NewContextHeader() + ctxHeader, err := header.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -73,7 +78,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi return nil, err } - doc, err = h.service.Update(ctx, doc) + doc, err = h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, err diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 9d662cbd4..aeb203270 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" @@ -20,13 +21,13 @@ type mockService struct { mock.Mock } -func (m *mockService) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { +func (m *mockService) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { args := m.Called(payload, contextHeader) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m *mockService) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (m *mockService) Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { args := m.Called(ctx, inv) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) @@ -56,20 +57,20 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, error) { +func (m *mockService) Update(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) doc1, _ := args.Get(0).(documents.Model) return doc1, args.Error(1) } -func (m *mockService) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { +func (m *mockService) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { args := m.Called(payload, contextHeader) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) } func getHandler() *grpcHandler { - return &grpcHandler{service: &mockService{}} + return &grpcHandler{service: &mockService{}, config: cfg} } func TestGRPCHandler_Create_derive_fail(t *testing.T) { @@ -236,9 +237,11 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(nil, fmt.Errorf("update error")).Once() + srv.On("Update", ctxh, model).Return(nil, fmt.Errorf("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -251,9 +254,11 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DeriveInvoiceResponse", model).Return(nil, fmt.Errorf("derive response error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) @@ -267,10 +272,12 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DeriveInvoiceResponse", model).Return(resp, nil).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 4c2ae2e07..d4cff36eb 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -11,7 +11,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/precise-proofs/proofs" @@ -156,7 +156,7 @@ func (i *Invoice) createP2PProtobuf() *invoicepb.InvoiceData { } // InitInvoiceInput initialize the model based on the received parameters from the rest api call -func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *documents.ContextHeader) error { +func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) error { err := i.initInvoiceFromData(payload.Data) if err != nil { return err diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 7dd54bcf1..802eff603 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -7,12 +7,24 @@ import ( "reflect" "testing" + "context" + "os" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -20,6 +32,30 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + +func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + anchors.Bootstrapper{}, + documents.Bootstrapper{}, + p2p.Bootstrapper{}, + &Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestInvoice_FromCoreDocuments_invalidParameter(t *testing.T) { invoiceModel := &Invoice{} @@ -144,7 +180,7 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // fail recipient data := &clientinvoicepb.InvoiceData{ @@ -204,7 +240,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - ctxHeader, err := documents.NewContextHeader() + ctxHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) m := new(Invoice) err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), ctxHeader) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 9364d8ea0..246198d99 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -2,7 +2,6 @@ package invoice import ( "bytes" - "context" "fmt" "time" @@ -15,9 +14,11 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -30,16 +31,16 @@ type Service interface { documents.Service // DeriverFromPayload derives Invoice from clientPayload - DeriveFromCreatePayload(*clientinvoicepb.InvoiceCreatePayload, *documents.ContextHeader) (documents.Model, error) + DeriveFromCreatePayload(*clientinvoicepb.InvoiceCreatePayload, *header.ContextHeader) (documents.Model, error) // DeriveFromUpdatePayload derives invoice model from update payload - DeriveFromUpdatePayload(*clientinvoicepb.InvoiceUpdatePayload, *documents.ContextHeader) (documents.Model, error) + DeriveFromUpdatePayload(*clientinvoicepb.InvoiceUpdatePayload, *header.ContextHeader) (documents.Model, error) // Create validates and persists invoice Model and returns a Updated model - Create(ctx context.Context, inv documents.Model) (documents.Model, error) + Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) // Update validates and updates the invoice model and return the updated model - Update(ctx context.Context, inv documents.Model) (documents.Model, error) + Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) // DeriveInvoiceData returns the invoice data as client data DeriveInvoiceData(inv documents.Model) (*clientinvoicepb.InvoiceData, error) @@ -59,8 +60,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} +func DefaultService(config config.Config, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config.(notification.Config)), anchorRepository: anchorRepository, identityService: identityService} } // CreateProofs creates proofs for the latest version document given the fields @@ -116,7 +117,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call -func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "input is nil") } @@ -159,7 +160,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { inv, err := s.calculateDataRoot(nil, inv, CreateValidator()) if err != nil { return nil, err @@ -174,7 +175,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { cd, err := inv.PackCoreDocument() if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) @@ -288,7 +289,7 @@ func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.Invoic } // DeriveFromUpdatePayload returns a new version of the old invoice identified by identifier in payload -func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *documents.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "invalid payload") } @@ -326,8 +327,8 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP return inv, nil } -// RequestDocumentSignature Validates, Signs document received over the p2p layer and returs Signature -func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentpb.Signature, error) { +// RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature +func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -339,12 +340,11 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) + idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + if !ok { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("missing signing key")) } - - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) + sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 7d801f7d8..ee17abd81 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -12,8 +12,10 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -43,14 +45,14 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) + srv := DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() Service { idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func createMockDocument() (*Invoice, error) { @@ -103,7 +105,7 @@ func TestService_DeriveFromPayload(t *testing.T) { _, err = invSrv.DeriveFromCreatePayload(&clientinvoicepb.InvoiceCreatePayload{}, nil) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) model, err = invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") @@ -209,13 +211,12 @@ func TestService_Exists(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) invSrv := service{repo: getRepository()} - ctx := context.Background() // calculate data root fails - m, err := invSrv.Create(context.Background(), &testingdocuments.MockModel{}) + m, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -226,7 +227,7 @@ func TestService_Create(t *testing.T) { proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() invSrv.coreDocProcessor = proc - m, err = invSrv.Create(ctx, po) + m, err = invSrv.Create(ctxh, po) proc.AssertExpectations(t) assert.Nil(t, m) assert.Error(t, err) @@ -237,12 +238,12 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() - proc.On("RequestSignatures", ctx, po).Return(nil).Once() + proc.On("RequestSignatures", ctxh, po).Return(nil).Once() proc.On("PrepareForAnchoring", po).Return(nil).Once() proc.On("AnchorDocument", po).Return(nil).Once() - proc.On("SendDocument", ctx, po).Return(nil).Once() + proc.On("SendDocument", ctxh, po).Return(nil).Once() invSrv.coreDocProcessor = proc - m, err = invSrv.Create(ctx, po) + m, err = invSrv.Create(ctxh, po) proc.AssertExpectations(t) assert.Nil(t, err) @@ -261,7 +262,7 @@ func TestService_DeriveInvoiceData(t *testing.T) { // success payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "must be non nil") @@ -274,7 +275,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // success invSrv := service{repo: getRepository()} payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv1, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "must be non nil") @@ -396,7 +397,8 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { idService := mockSignatureCheck(i, invSrv) setIdentityService(idService) i.CoreDocument.SigningRoot = nil - signature, err := invSrv.RequestDocumentSignature(i) + ctxh, err := header.NewContextHeader(context.Background(), cfg) + signature, err := invSrv.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.Contains(t, err.Error(), strconv.Itoa(int(code.DocumentInvalid))) assert.Contains(t, err.Error(), "signing root missing") @@ -511,7 +513,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) @@ -579,14 +581,13 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_Update(t *testing.T) { invSrv := service{repo: getRepository()} - ctx := context.Background() - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack failed model := &mockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("pack error")).Once() - _, err = invSrv.Update(ctx, model) + _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -595,7 +596,7 @@ func TestService_Update(t *testing.T) { model = &mockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = invSrv.Update(ctx, model) + _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -613,7 +614,7 @@ func TestService_Update(t *testing.T) { // calculate data root fails model = &mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = invSrv.Update(ctx, model) + _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -635,12 +636,12 @@ func TestService_Update(t *testing.T) { assert.Equal(t, data, newData) proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() - proc.On("RequestSignatures", ctx, newInv).Return(nil).Once() + proc.On("RequestSignatures", ctxh, newInv).Return(nil).Once() proc.On("PrepareForAnchoring", newInv).Return(nil).Once() proc.On("AnchorDocument", newInv).Return(nil).Once() - proc.On("SendDocument", ctx, newInv).Return(nil).Once() + proc.On("SendDocument", ctxh, newInv).Return(nil).Once() invSrv.coreDocProcessor = proc - inv, err = invSrv.Update(ctx, newInv) + inv, err = invSrv.Update(ctxh, newInv) proc.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, inv) @@ -659,7 +660,7 @@ func TestService_Update(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { invSrv := getServiceWithMockedLayers().(service) - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // type mismatch diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 579254d84..c3eb2ab74 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -6,8 +6,11 @@ import ( "fmt" "testing" + "context" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -79,7 +82,7 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv := new(Invoice) err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) diff --git a/documents/leveldb_test.go b/documents/leveldb_test.go index 3ea05f7ed..b287526da 100644 --- a/documents/leveldb_test.go +++ b/documents/leveldb_test.go @@ -4,35 +4,15 @@ package documents import ( "encoding/json" - "flag" "fmt" - "os" "reflect" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &storage.Bootstrapper{}, - &Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - flag.Parse() - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - type model struct { shouldError bool Data string `json:"data"` diff --git a/documents/model.go b/documents/model.go index da436c9c3..22e9146f1 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,11 +1,9 @@ package documents import ( - "fmt" "reflect" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/identity" ) // Model is an interface to abstract away model specificness like invoice or purchaseOrder @@ -32,23 +30,3 @@ type Model interface { // FromJSON initialize the model with a json FromJSON(json []byte) error } - -// Placeholder to pass custom request objects down the pipeline -type ContextHeader struct { - self *identity.IdentityConfig -} - -// NewContextHeader creates new instance of the request headers needed -func NewContextHeader() (*ContextHeader, error) { - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return nil, fmt.Errorf("failed to get id config: %v", err) - } - - return &ContextHeader{self: idConfig}, nil -} - -// Self returns Self CentID -func (h *ContextHeader) Self() *identity.IdentityConfig { - return h.self -} diff --git a/documents/model_test.go b/documents/model_test.go new file mode 100644 index 000000000..b3b149556 --- /dev/null +++ b/documents/model_test.go @@ -0,0 +1,28 @@ +package documents + +import ( + "os" + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/storage" +) + +var ctx = map[string]interface{}{} +var cfg *config.Configuration + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + &Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 1a441a474..b89e84247 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -6,28 +6,28 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/storage" ) type Bootstrapper struct { } -func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[bootstrap.BootstrappedLevelDb]; !ok { + if _, ok := ctx[storage.BootstrappedLevelDb]; !ok { return errors.New("could not initialize purchase order repository") } - p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) + p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") } diff --git a/documents/purchaseorder/bootstrapper_test.go b/documents/purchaseorder/bootstrapper_test.go index 05f5f7430..b6911430f 100644 --- a/documents/purchaseorder/bootstrapper_test.go +++ b/documents/purchaseorder/bootstrapper_test.go @@ -3,43 +3,11 @@ package purchaseorder import ( - "flag" - "os" "testing" - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" ) -func TestMain(m *testing.M) { - ethClient := &testingcommons.MockEthClient{} - ethClient.On("GetEthClient").Return(nil) - ctx := map[string]interface{}{ - bootstrap.BootstrappedEthereumClient: ethClient, - } - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &storage.Bootstrapper{}, - anchors.Bootstrapper{}, - documents.Bootstrapper{}, - p2p.Bootstrapper{}, - &Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - flag.Parse() - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - func TestBootstrapper_Bootstrap(t *testing.T) { err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) assert.Error(t, err, "Should throw an error because of empty context") diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 2c35b3b1f..116f228eb 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -6,7 +6,9 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" @@ -19,6 +21,7 @@ var apiLog = logging.Logger("purchaseorder-api") // anchoring, sending, finding stored purchase order document type grpcHandler struct { service Service + config config.Config } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer @@ -36,7 +39,7 @@ func GRPCHandler(registry *documents.ServiceRegistry) (clientpurchaseorderpb.Doc // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, err.Error()) @@ -49,7 +52,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc } // validate, persist, and anchor - doc, err = h.service.Create(ctx, doc) + doc, err = h.service.Create(ctxh, doc) if err != nil { apiLog.Error(err) return nil, err @@ -61,7 +64,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := documents.NewContextHeader() + ctxHeader, err := header.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -73,7 +76,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. return nil, err } - doc, err = h.service.Update(ctx, doc) + doc, err = h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, err diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 890ae1222..fa6a84024 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/ethereum/go-ethereum/common/hexutil" @@ -21,19 +22,19 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx context.Context, doc documents.Model) (documents.Model, error) { +func (m mockService) Create(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, error) { +func (m mockService) Update(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) DeriveFromCreatePayload(req *clientpopb.PurchaseOrderCreatePayload, ctxh *documents.ContextHeader) (documents.Model, error) { +func (m mockService) DeriveFromCreatePayload(req *clientpopb.PurchaseOrderCreatePayload, ctxh *header.ContextHeader) (documents.Model, error) { args := m.Called(req, ctxh) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) @@ -63,22 +64,22 @@ func (m mockService) DerivePurchaseOrderResponse(po documents.Model) (*clientpop return data, args.Error(1) } -func (m mockService) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *documents.ContextHeader) (documents.Model, error) { - args := m.Called(payload, ctxH) +func (m mockService) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxh *header.ContextHeader) (documents.Model, error) { + args := m.Called(payload, ctxh) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) } func TestGRPCHandler_Create(t *testing.T) { - h := grpcHandler{} + h := getHandler() req := testingdocuments.CreatePOPayload() ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(ctx, cfg) assert.Nil(t, err) // derive fails - srv := mockService{} + srv := h.service.(*mockService) srv.On("DeriveFromCreatePayload", req, ctxh).Return(nil, fmt.Errorf("derive failed")).Once() h.service = srv resp, err := h.Create(ctx, req) @@ -88,9 +89,8 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv = mockService{} srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Create", ctx, model).Return(nil, fmt.Errorf("create failed")).Once() + srv.On("Create", ctxh, model).Return(nil, fmt.Errorf("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -99,9 +99,8 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "create failed") // derive response fails - srv = mockService{} srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Create", ctx, model).Return(model, nil).Once() + srv.On("Create", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, fmt.Errorf("derive response fails")).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -112,9 +111,8 @@ func TestGRPCHandler_Create(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{} - srv = mockService{} srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Create", ctx, model).Return(model, nil).Once() + srv.On("Create", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -125,7 +123,7 @@ func TestGRPCHandler_Create(t *testing.T) { } func TestGrpcHandler_Update(t *testing.T) { - h := grpcHandler{} + h := getHandler() p := testingdocuments.CreatePOPayload() req := &clientpopb.PurchaseOrderUpdatePayload{ Data: p.Data, @@ -133,11 +131,11 @@ func TestGrpcHandler_Update(t *testing.T) { } ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(ctx, cfg) assert.Nil(t, err) // derive fails - srv := mockService{} + srv := h.service.(*mockService) srv.On("DeriveFromUpdatePayload", req, ctxh).Return(nil, fmt.Errorf("derive failed")).Once() h.service = srv resp, err := h.Update(ctx, req) @@ -147,9 +145,8 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv = mockService{} srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(nil, fmt.Errorf("update failed")).Once() + srv.On("Update", ctxh, model).Return(nil, fmt.Errorf("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -158,9 +155,8 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "update failed") // derive response fails - srv = mockService{} srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, fmt.Errorf("derive response fails")).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -171,9 +167,8 @@ func TestGrpcHandler_Update(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{} - srv = mockService{} srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Update", ctx, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -190,7 +185,7 @@ type mockModel struct { } func getHandler() *grpcHandler { - return &grpcHandler{service: &mockService{}} + return &grpcHandler{service: &mockService{}, config: cfg} } func TestGrpcHandler_Get(t *testing.T) { diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 9d1d2a8d5..d3080bb13 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -11,7 +11,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/precise-proofs/proofs" @@ -145,7 +145,7 @@ func (p *PurchaseOrder) createP2PProtobuf() *purchaseorderpb.PurchaseOrderData { } // InitPurchaseOrderInput initialize the model based on the received parameters from the rest api call -func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, contextHeader *documents.ContextHeader) error { +func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, contextHeader *header.ContextHeader) error { err := p.initPurchaseOrderFromData(payload.Data) if err != nil { return err diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index c9caf4d32..136599e5e 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -7,12 +7,24 @@ import ( "reflect" "testing" + "context" + "os" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -20,6 +32,30 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + +func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + anchors.Bootstrapper{}, + documents.Bootstrapper{}, + p2p.Bootstrapper{}, + &Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestPO_FromCoreDocuments_invalidParameter(t *testing.T) { poModel := &PurchaseOrder{} @@ -140,7 +176,7 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ @@ -178,7 +214,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { } func TestPOModel_calculateDataRoot(t *testing.T) { - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) poModel := new(PurchaseOrder) err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index afed7b8f7..f3cf606a6 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -2,7 +2,6 @@ package purchaseorder import ( "bytes" - "context" "fmt" "time" @@ -15,9 +14,11 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/signatures" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -30,16 +31,16 @@ type Service interface { documents.Service // DeriverFromPayload derives purchase order from clientPayload - DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, hdr *documents.ContextHeader) (documents.Model, error) + DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, hdr *header.ContextHeader) (documents.Model, error) // DeriveFromUpdatePayload derives purchase order from update payload - DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, hdr *documents.ContextHeader) (documents.Model, error) + DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, hdr *header.ContextHeader) (documents.Model, error) // Create validates and persists purchase order and returns a Updated model - Create(ctx context.Context, po documents.Model) (documents.Model, error) + Create(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) // Update validates and updates the purchase order and return the updated model - Update(ctx context.Context, po documents.Model) (documents.Model, error) + Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) // DerivePurchaseOrderData returns the purchase order data as client data DerivePurchaseOrderData(po documents.Model) (*clientpopb.PurchaseOrderData, error) @@ -59,7 +60,7 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config *config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { +func DefaultService(config config.Config, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } @@ -103,7 +104,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, error) { +func (s service) Create(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { po, err := s.calculateDataRoot(nil, po, CreateValidator()) if err != nil { return nil, err @@ -118,7 +119,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, error) { +func (s service) Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { cd, err := po.PackCoreDocument() if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) @@ -143,7 +144,7 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode } // DeriveFromCreatePayload derives purchase order from create payload -func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *documents.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "input is nil") } @@ -158,7 +159,7 @@ func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreate } // DeriveFromUpdatePayload derives purchase order from update payload -func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *documents.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, centerrors.New(code.DocumentInvalid, "invalid payload") } @@ -326,7 +327,7 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str // RequestDocumentSignature validates the document and returns the signature // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service -func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } @@ -338,12 +339,11 @@ func (s service) RequestDocumentSignature(model documents.Model) (*coredocumentp srvLog.Infof("coredoc received %x with signing root %x", cd.DocumentIdentifier, cd.SigningRoot) - idConfig, err := identity.GetIdentityConfig() - if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get ID Config: %v", err)) + idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + if !ok { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("missing signing key")) } - - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) + sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 86f116a4a..d6d9828fc 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -48,14 +49,13 @@ func getServiceWithMockedLayers() Service { func TestService_Update(t *testing.T) { poSrv := service{repo: getRepository()} - ctx := context.Background() - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack failed model := &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(nil, fmt.Errorf("pack error")).Once() - _, err = poSrv.Update(ctx, model) + _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -64,7 +64,7 @@ func TestService_Update(t *testing.T) { model = &testingdocuments.MockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = poSrv.Update(ctx, model) + _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -82,7 +82,7 @@ func TestService_Update(t *testing.T) { // calculate data root fails model = &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = poSrv.Update(ctx, model) + _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -104,12 +104,12 @@ func TestService_Update(t *testing.T) { assert.Equal(t, data, newData) proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() - proc.On("RequestSignatures", ctx, newInv).Return(nil).Once() + proc.On("RequestSignatures", ctxh, newInv).Return(nil).Once() proc.On("PrepareForAnchoring", newInv).Return(nil).Once() proc.On("AnchorDocument", newInv).Return(nil).Once() - proc.On("SendDocument", ctx, newInv).Return(nil).Once() + proc.On("SendDocument", ctxh, newInv).Return(nil).Once() poSrv.coreDocProcessor = proc - po, err = poSrv.Update(ctx, newInv) + po, err = poSrv.Update(ctxh, newInv) proc.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, po) @@ -141,7 +141,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) @@ -207,7 +207,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_DeriveFromCreatePayload(t *testing.T) { poSrv := service{} - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // nil payload @@ -262,13 +262,12 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) poSrv := service{repo: getRepository()} - ctx := context.Background() // calculate data root fails - m, err := poSrv.Create(context.Background(), &testingdocuments.MockModel{}) + m, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -279,7 +278,7 @@ func TestService_Create(t *testing.T) { proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() poSrv.coreDocProcessor = proc - m, err = poSrv.Create(ctx, po) + m, err = poSrv.Create(ctxh, po) proc.AssertExpectations(t) assert.Nil(t, m) assert.Error(t, err) @@ -290,12 +289,12 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() - proc.On("RequestSignatures", ctx, po).Return(nil).Once() + proc.On("RequestSignatures", ctxh, po).Return(nil).Once() proc.On("PrepareForAnchoring", po).Return(nil).Once() proc.On("AnchorDocument", po).Return(nil).Once() - proc.On("SendDocument", ctx, po).Return(nil).Once() + proc.On("SendDocument", ctxh, po).Return(nil).Once() poSrv.coreDocProcessor = proc - m, err = poSrv.Create(ctx, po) + m, err = poSrv.Create(ctxh, po) proc.AssertExpectations(t) assert.Nil(t, err) assert.NotNil(t, m) @@ -501,7 +500,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model poSrv := getServiceWithMockedLayers() - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // unknown type @@ -522,7 +521,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { func TestService_DerivePurchaseOrderResponse(t *testing.T) { poSrv := service{} - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack fails @@ -686,15 +685,17 @@ func TestService_ReceiveAnchoredDocument(t *testing.T) { } func TestService_RequestDocumentSignature(t *testing.T) { + ctxh, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) poSrv := service{} - s, err := poSrv.RequestDocumentSignature(nil) + s, err := poSrv.RequestDocumentSignature(ctxh, nil) assert.Nil(t, s) assert.Error(t, err) } func TestService_calculateDataRoot(t *testing.T) { poSrv := service{repo: getRepository()} - ctxh, err := documents.NewContextHeader() + ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // type mismatch diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 343ae641b..4f39ab007 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -6,8 +6,11 @@ import ( "fmt" "testing" + "context" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -46,7 +49,7 @@ func TestFieldValidator_Validate(t *testing.T) { func TestDataRootValidation_Validate(t *testing.T) { drv := dataRootValidator() - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // nil error diff --git a/documents/service.go b/documents/service.go index a9a539ab6..44ab0d809 100644 --- a/documents/service.go +++ b/documents/service.go @@ -3,6 +3,7 @@ package documents import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -36,7 +37,7 @@ type Service interface { CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) // RequestDocumentSignature Validates and Signs document received over the p2p layer - RequestDocumentSignature(model Model) (*coredocumentpb.Signature, error) + RequestDocumentSignature(contextHeader *header.ContextHeader, model Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error diff --git a/documents/anchor_test.go b/documents/test/anchor_test.go similarity index 70% rename from documents/anchor_test.go rename to documents/test/anchor_test.go index 630adf0d9..6973e20aa 100644 --- a/documents/anchor_test.go +++ b/documents/test/anchor_test.go @@ -7,15 +7,36 @@ import ( "fmt" "testing" + "os" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &config.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestAnchorDocument(t *testing.T) { ctx := context.Background() + ctxh, err := header.NewContextHeader(ctx, cfg) + assert.Nil(t, err) updater := func(id []byte, model documents.Model) error { return nil } @@ -23,7 +44,7 @@ func TestAnchorDocument(t *testing.T) { // pack fails m := &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(nil, fmt.Errorf("pack failed")).Once() - model, err := documents.AnchorDocument(ctx, m, nil, updater) + model, err := documents.AnchorDocument(ctxh, m, nil, updater) m.AssertExpectations(t) assert.Nil(t, model) assert.Error(t, err) @@ -35,7 +56,7 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(fmt.Errorf("error")).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -47,8 +68,8 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctx, m).Return(fmt.Errorf("error")).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + proc.On("RequestSignatures", ctxh, m).Return(fmt.Errorf("error")).Once() + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -60,9 +81,9 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctx, m).Return(nil).Once() + proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(fmt.Errorf("error")).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -74,10 +95,10 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctx, m).Return(nil).Once() + proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() proc.On("AnchorDocument", m).Return(fmt.Errorf("error")).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -89,11 +110,11 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctx, m).Return(nil).Once() + proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() proc.On("AnchorDocument", m).Return(nil).Once() - proc.On("SendDocument", ctx, m).Return(fmt.Errorf("error")).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + proc.On("SendDocument", ctxh, m).Return(fmt.Errorf("error")).Once() + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -105,11 +126,11 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctx, m).Return(nil).Once() + proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() proc.On("AnchorDocument", m).Return(nil).Once() - proc.On("SendDocument", ctx, m).Return(nil).Once() - model, err = documents.AnchorDocument(ctx, m, proc, updater) + proc.On("SendDocument", ctxh, m).Return(nil).Once() + model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, err) diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index d1944919e..131576650 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -5,7 +5,7 @@ package documents import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" ) @@ -13,10 +13,10 @@ import ( var testLevelDB Repository func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedLevelDb]; !ok { + if _, ok := context[storage.BootstrappedLevelDb]; !ok { return errors.New("initializing LevelDB repository failed") } - testLevelDB = LevelDBRepository{LevelDB: context[bootstrap.BootstrappedLevelDb].(*leveldb.DB)} + testLevelDB = LevelDBRepository{LevelDB: context[storage.BootstrappedLevelDb].(*leveldb.DB)} return b.Bootstrap(context) } diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index c90484257..473b8679b 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -3,22 +3,23 @@ package ethereum import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" ) +const BootstrappedEthereumClient string = "BootstrappedEthereumClient" + type Bootstrapper struct{} func (Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(Config) client, err := NewGethClient(cfg) if err != nil { return err } SetClient(client) - context[bootstrap.BootstrappedEthereumClient] = client + context[BootstrappedEthereumClient] = client return nil } diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 478db0eb3..b0a1e0a87 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -30,17 +30,6 @@ var log = logging.Logger("geth-client") var gc Client var gcMu sync.RWMutex -// GetDefaultContextTimeout retrieves the default duration before an Ethereum write call context should time out -func GetDefaultContextTimeout() time.Duration { - return config.Config().GetEthereumContextWaitTimeout() -} - -// DefaultWaitForTransactionMiningContext returns context with timeout for write operations -func DefaultWaitForTransactionMiningContext() (ctx context.Context, cancelFunc context.CancelFunc) { - toBeDone := time.Now().Add(GetDefaultContextTimeout()) - return context.WithDeadline(context.Background(), toBeDone) -} - // Config defines functions to get ethereum details type Config interface { GetEthereumGasPrice() *big.Int @@ -53,6 +42,12 @@ type Config interface { GetEthereumContextReadWaitTimeout() time.Duration } +// DefaultWaitForTransactionMiningContext returns context with timeout for write operations +func DefaultWaitForTransactionMiningContext(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) { + toBeDone := time.Now().Add(d) + return context.WithDeadline(context.Background(), toBeDone) +} + // Client can be implemented by any chain client type Client interface { @@ -208,7 +203,7 @@ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, o } current++ - err = incrementNonce(opts, gc.config.GetTxPoolAccessEnabled(), gc.client, gc.rpcClient) + err = gc.incrementNonce(opts, gc.config.GetTxPoolAccessEnabled(), gc.client, gc.rpcClient) if err != nil { return nil, fmt.Errorf("failed to increment nonce: %v", err) } @@ -272,7 +267,7 @@ type callContexter interface { // then we check the txpool to see if there any new transactions from the address that are not included in any block // If there are no pending transactions in txpool, we use the current nonce + 1 // else we increment the greater of current nonce or the nonce derived from txpool -func incrementNonce(opts *bind.TransactOpts, txpoolAccessEnabled bool, noncer noncer, cc callContexter) error { +func (gc *gethClient) incrementNonce(opts *bind.TransactOpts, txpoolAccessEnabled bool, noncer noncer, cc callContexter) error { // check if the txpool access is enabled if !txpoolAccessEnabled { log.Warningf("Ethereum Client doesn't support txpool API, may cause transactions failures") @@ -280,7 +275,7 @@ func incrementNonce(opts *bind.TransactOpts, txpoolAccessEnabled bool, noncer no return nil } - ctx, cancel := context.WithTimeout(context.Background(), GetDefaultContextTimeout()) + ctx, cancel := gc.defaultReadContext() defer cancel() // get current nonce diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index a797caba6..b806bad7a 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -12,8 +12,11 @@ import ( "github.com/stretchr/testify/assert" ) +var cfg *config.Configuration + func TestMain(m *testing.M) { - cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap() + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -34,7 +37,7 @@ func TestGetConnection_returnsSameConnection(t *testing.T) { } func TestNewGethClient(t *testing.T) { - gc, err := ethereum.NewGethClient(config.Config()) + gc, err := ethereum.NewGethClient(cfg) assert.Nil(t, err) assert.NotNil(t, gc) } diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index 0782a97b1..a88309585 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -31,7 +31,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) cfg.Set("ethereum.txPoolAccessEnabled", false) cfg.Set("ethereum.intervalRetry", time.Millisecond*100) result := m.Run() @@ -126,16 +126,19 @@ func (m *mockNoncer) CallContext(ctx context.Context, result interface{}, method func Test_incrementNonce(t *testing.T) { opts := &bind.TransactOpts{From: common.HexToAddress("0x45B9c4798999FFa52e1ff1eFce9d3e45819E4158")} + gc := &gethClient{ + config: cfg, + } // txpool access disabled - err := incrementNonce(opts, false, nil, nil) + err := gc.incrementNonce(opts, false, nil, nil) assert.Nil(t, err) assert.Nil(t, opts.Nonce) // noncer failed n := new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(0, fmt.Errorf("error")).Once() - err = incrementNonce(opts, true, n, nil) + err = gc.incrementNonce(opts, true, n, nil) n.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get chain nonce") @@ -144,7 +147,7 @@ func Test_incrementNonce(t *testing.T) { n = new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(100), nil).Once() n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, fmt.Errorf("error")).Once() - err = incrementNonce(opts, true, n, n) + err = gc.incrementNonce(opts, true, n, n) n.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get txpool data") @@ -154,7 +157,7 @@ func Test_incrementNonce(t *testing.T) { n = new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, nil).Once() - err = incrementNonce(opts, true, n, n) + err = gc.incrementNonce(opts, true, n, n) n.AssertExpectations(t) assert.Nil(t, err) assert.Equal(t, "1000", opts.Nonce.String()) @@ -170,7 +173,7 @@ func Test_incrementNonce(t *testing.T) { n = new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(res, nil).Once() - err = incrementNonce(opts, true, n, n) + err = gc.incrementNonce(opts, true, n, n) n.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to convert nonce") @@ -189,7 +192,7 @@ func Test_incrementNonce(t *testing.T) { n = new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(1000), nil).Once() n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(res, nil).Once() - err = incrementNonce(opts, true, n, n) + err = gc.incrementNonce(opts, true, n, n) n.AssertExpectations(t) assert.Nil(t, err) assert.Equal(t, "1004", opts.Nonce.String()) diff --git a/header/context.go b/header/context.go new file mode 100644 index 000000000..ee83cc2da --- /dev/null +++ b/header/context.go @@ -0,0 +1,35 @@ +package header + +import ( + "context" + "fmt" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" +) + +// Placeholder to pass custom request objects down the pipeline +type ContextHeader struct { + context context.Context + self *identity.IdentityConfig +} + +// NewContextHeader creates new instance of the request headers needed +func NewContextHeader(context context.Context, config config.Config) (*ContextHeader, error) { + idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) + if err != nil { + return nil, fmt.Errorf("failed to get id config: %v", err) + } + + return &ContextHeader{self: idConfig, context: context}, nil +} + +// Self returns Self CentID +func (h *ContextHeader) Self() *identity.IdentityConfig { + return h.self +} + +// Context returns context.Context of the request +func (h *ContextHeader) Context() context.Context { + return h.context +} diff --git a/healthcheck/handler_test.go b/healthcheck/handler_test.go index fb8c9f559..86f15c10b 100644 --- a/healthcheck/handler_test.go +++ b/healthcheck/handler_test.go @@ -22,7 +22,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index e5ac454bd..70e7234fd 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -3,7 +3,6 @@ package identity import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" @@ -17,12 +16,12 @@ type Bootstrapper struct { // Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. // the idRegistrationConfirmationTask is added to be registered on the Queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(Config) - if _, ok := context[bootstrap.BootstrappedEthereumClient]; !ok { + if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -42,7 +41,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { }) err = queue.InstallQueuedTask(context, - newIdRegistrationConfirmationTask(&idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) + newIdRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) if err != nil { return err } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index 9080152c3..6992d14f9 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -7,6 +7,8 @@ import ( "bytes" + "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -46,10 +48,6 @@ type contract interface { FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) } -type Config interface { - GetEthereumDefaultAccountName() string -} - // EthereumIdentityKey holds the identity related details type EthereumIdentityKey struct { Key [32]byte @@ -224,7 +222,7 @@ func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int var keyFixed [32]byte copy(keyFixed[:], key) - confirmations, err = setUpKeyRegisteredEventListener(id, keyPurpose, keyFixed, h.Number.Uint64()) + confirmations, err = setUpKeyRegisteredEventListener(id.config, id, keyPurpose, keyFixed, h.Number.Uint64()) if err != nil { wError := errors.Wrap(err, 1) log.Errorf("Failed to set up event listener for identity [id: %s]: %v", id, wError) @@ -300,7 +298,7 @@ func sendIdentityCreationTransaction(identityFactory factory, opts *bind.Transac } // setUpKeyRegisteredEventListener listens for Identity creation -func setUpKeyRegisteredEventListener(identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { +func setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) centId := identity.CentID() if err != nil { @@ -308,43 +306,43 @@ func setUpKeyRegisteredEventListener(identity Identity, keyPurpose int, key [32] } asyncRes, err := queue.Queue.DelayKwargs(keyRegistrationConfirmationTaskName, map[string]interface{}{ - centIDParam: centId, - keyParam: key, - keyPurposeParam: keyPurpose, - blockHeightParam: bh, + centIDParam: centId, + keyParam: key, + keyPurposeParam: keyPurpose, + queue.BlockHeightParam: bh, }) if err != nil { return nil, err } - go waitAndRouteKeyRegistrationEvent(asyncRes, confirmations, identity) + go waitAndRouteKeyRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, identity) return confirmations, nil } // setUpRegistrationEventListener sets up the listened for the "IdentityCreated" event to notify the upstream code about successful mining/creation // of the identity. -func setUpRegistrationEventListener(identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { +func setUpRegistrationEventListener(config Config, identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) bCentId := identityToBeCreated.CentID() if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, blockHeightParam: blockHeight}) + asyncRes, err := queue.Queue.DelayKwargs(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, queue.BlockHeightParam: blockHeight}) if err != nil { return nil, err } - go waitAndRouteIdentityRegistrationEvent(asyncRes, confirmations, identityToBeCreated) + go waitAndRouteIdentityRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, identityToBeCreated) return confirmations, nil } // waitAndRouteKeyRegistrationEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteKeyRegistrationEvent(asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { - _, err := asyncRes.Get(ethereum.GetDefaultContextTimeout()) +func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { + _, err := asyncRes.Get(timeout) confirmations <- &WatchIdentity{Identity: pushThisIdentity, Error: err} } // waitAndRouteIdentityRegistrationEvent notifies the confirmations channel whenever the identity creation is being noted as Ethereum event -func waitAndRouteIdentityRegistrationEvent(asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { - _, err := asyncRes.Get(ethereum.GetDefaultContextTimeout()) +func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { + _, err := asyncRes.Get(timeout) confirmations <- &WatchIdentity{pushThisIdentity, err} } @@ -403,7 +401,7 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden return nil, confirmations, err } - confirmations, err = setUpRegistrationEventListener(id, h.Number.Uint64()) + confirmations, err = setUpRegistrationEventListener(ids.config, id, h.Number.Uint64()) if err != nil { wError := errors.Wrap(err, 1) log.Infof("Failed to set up event listener for identity [mockID: %s]: %v", id, wError) @@ -521,7 +519,7 @@ func (ids *EthereumIdentityService) ValidateKey(centrifugeId CentID, key []byte, // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { - identityConfig, err := GetIdentityConfig() + identityConfig, err := GetIdentityConfig(ids.config) if err != nil { return err } @@ -531,7 +529,7 @@ func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { return err } - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(ids.config.GetEthereumContextWaitTimeout()) defer cancel() confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) if err != nil { diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 84923bb4b..3918845de 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -17,14 +17,16 @@ import ( ) var identityService identity.Service +var cfg *config.Configuration func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) - cc.TestFunctionalEthereumBootstrap() - config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + ctx := cc.TestFunctionalEthereumBootstrap() + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") identityService = identity.IDService result := m.Run() @@ -79,10 +81,10 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { func TestAddKeyFromConfig(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := config.Config().GetString("identityId") - config.Config().Set("identityId", centrifugeId.String()) - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + defaultCentrifugeId := cfg.GetString("identityId") + cfg.Set("identityId", centrifugeId.String()) + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") _, confirmations, err := identityService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") @@ -93,20 +95,20 @@ func TestAddKeyFromConfig(t *testing.T) { err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") - config.Config().Set("identityId", defaultCentrifugeId) + cfg.Set("identityId", defaultCentrifugeId) } func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := config.Config().GetString("identityId") - config.Config().Set("identityId", centrifugeId.String()) - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + defaultCentrifugeId := cfg.GetString("identityId") + cfg.Set("identityId", centrifugeId.String()) + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") err := identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.NotNil(t, err, "should error out") - config.Config().Set("identityId", defaultCentrifugeId) + cfg.Set("identityId", defaultCentrifugeId) } func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { diff --git a/identity/ethereum_identity_test.go b/identity/ethereum_identity_test.go index 465679f20..48e818c69 100644 --- a/identity/ethereum_identity_test.go +++ b/identity/ethereum_identity_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -19,12 +20,6 @@ import ( "github.com/stretchr/testify/mock" ) -type MockConfig struct{} - -func (MockConfig) GetEthereumDefaultAccountName() string { - return "mockacc" -} - type MockIDFactory struct { mock.Mock } @@ -108,7 +103,7 @@ func (mic MockIDContract) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, func TestGetClientP2PURL_happy(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -128,7 +123,7 @@ func TestGetClientP2PURL_happy(t *testing.T) { func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) @@ -148,7 +143,7 @@ func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -170,7 +165,7 @@ func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { func TestGetIdentityKey_fail_lookup(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { @@ -190,7 +185,7 @@ func TestGetIdentityKey_fail_lookup(t *testing.T) { func TestGetIdentityKey_fail_FetchKey(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -220,7 +215,7 @@ func TestGetIdentityKey_fail_FetchKey(t *testing.T) { func TestGetIdentityKey_fail_empty(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -250,7 +245,7 @@ func TestGetIdentityKey_fail_empty(t *testing.T) { func TestGetIdentityKey_Success(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -281,7 +276,7 @@ func TestValidateKey_success(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -311,7 +306,7 @@ func TestValidateKey_fail_getId(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -339,7 +334,7 @@ func TestValidateKey_fail_getId(t *testing.T) { func TestValidateKey_fail_mismatch_key(t *testing.T) { centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -369,7 +364,7 @@ func TestValidateKey_fail_missing_purpose(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -399,7 +394,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -429,7 +424,7 @@ func TestValidateKey_fail_revocation(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) diff --git a/identity/id_registration_confirmation_task.go b/identity/id_registration_confirmation_task.go index 887a790fd..370d5fab3 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/id_registration_confirmation_task.go @@ -26,16 +26,19 @@ type identitiesCreatedFilterer interface { type idRegistrationConfirmationTask struct { centID CentID blockHeight uint64 - contextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + timeout time.Duration + contextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) ctx context.Context filterer identitiesCreatedFilterer } func newIdRegistrationConfirmationTask( + timeout time.Duration, identityCreatedWatcher identitiesCreatedFilterer, - ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), ) *idRegistrationConfirmationTask { return &idRegistrationConfirmationTask{ + timeout: timeout, filterer: identityCreatedWatcher, contextInitializer: ethContextInitializer, } @@ -57,6 +60,7 @@ func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &idRegistrationConfirmationTask{ rct.centID, rct.blockHeight, + rct.timeout, rct.contextInitializer, rct.ctx, rct.filterer}, nil @@ -74,10 +78,21 @@ func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interfa } rct.centID = centIdTyped - rct.blockHeight, err = parseBlockHeight(kwargs) + rct.blockHeight, err = queue.ParseBlockHeight(kwargs) if err != nil { return err } + + // override timeout param if provided + tdRaw, ok := kwargs[queue.TimeoutParam] + if ok { + td, err := queue.GetDuration(tdRaw) + if err != nil { + return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + } + rct.timeout = td + } + return nil } @@ -85,7 +100,7 @@ func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interfa func (rct *idRegistrationConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the ID [%x]", rct.centID) if rct.ctx == nil { - rct.ctx, _ = rct.contextInitializer() + rct.ctx, _ = rct.contextInitializer(rct.timeout) } fOpts := &bind.FilterOpts{ diff --git a/identity/id_registration_confirmation_task_test.go b/identity/id_registration_confirmation_task_test.go index a8c2a394a..d21f2b9b9 100644 --- a/identity/id_registration_confirmation_task_test.go +++ b/identity/id_registration_confirmation_task_test.go @@ -5,6 +5,7 @@ package identity import ( "testing" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -13,10 +14,12 @@ func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { rct := idRegistrationConfirmationTask{} id := utils.RandomSlice(CentIDLength) blockHeight := uint64(3132) + timeout := float64(3000) idBytes, _ := ToCentID(id) kwargs := map[string]interface{}{ - centIDParam: idBytes, - blockHeightParam: blockHeight, + centIDParam: idBytes, + queue.BlockHeightParam: blockHeight, + queue.TimeoutParam: timeout, } decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) diff --git a/identity/identity.go b/identity/identity.go index 3cfc7a2f5..9095633fb 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -6,9 +6,10 @@ import ( "fmt" "math/big" + "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/signatures" @@ -70,6 +71,15 @@ func (c CentID) BigInt() *big.Int { return utils.ByteSliceToBigInt(c[:]) } +type Config interface { + GetEthereumDefaultAccountName() string + GetIdentityID() ([]byte, error) + GetSigningKeyPair() (pub, priv string) + GetEthAuthKeyPair() (pub, priv string) + GetEthereumContextWaitTimeout() time.Duration + GetContractAddress(address string) common.Address +} + // Identity defines an Identity on chain type Identity interface { fmt.Stringer @@ -130,8 +140,8 @@ type Service interface { } // GetIdentityConfig returns the identity and keys associated with the node -func GetIdentityConfig() (*IdentityConfig, error) { - centIDBytes, err := config.Config().GetIdentityID() +func GetIdentityConfig(config Config) (*IdentityConfig, error) { + centIDBytes, err := config.GetIdentityID() if err != nil { return nil, err } @@ -142,7 +152,7 @@ func GetIdentityConfig() (*IdentityConfig, error) { //ed25519 keys keys := map[int]IdentityKey{} - pk, sk, err := ed25519.GetSigningKeyPairFromConfig() + pk, sk, err := ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) if err != nil { return nil, err } @@ -150,7 +160,7 @@ func GetIdentityConfig() (*IdentityConfig, error) { keys[KeyPurposeSigning] = IdentityKey{PublicKey: pk, PrivateKey: sk} //secp256k1 keys - pk, sk, err = secp256k1.GetEthAuthKeyFromConfig() + pk, sk, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) if err != nil { return nil, err } diff --git a/identity/identity_test.go b/identity/identity_test.go index b20ef4174..7fddd29bd 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -17,15 +17,19 @@ import ( "github.com/stretchr/testify/mock" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) - config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -109,10 +113,10 @@ func (srv *mockIDService) CheckIdentityExists(centID CentID) (exists bool, err e } func TestGetIdentityConfig_Success(t *testing.T) { - idConfig, err := GetIdentityConfig() + idConfig, err := GetIdentityConfig(cfg) assert.Nil(t, err) assert.NotNil(t, idConfig) - configId, err := config.Config().GetIdentityID() + configId, err := cfg.GetIdentityID() assert.Nil(t, err) idBytes := idConfig.ID[:] assert.Equal(t, idBytes, configId) @@ -121,40 +125,40 @@ func TestGetIdentityConfig_Success(t *testing.T) { func TestGetIdentityConfig_Error(t *testing.T) { //Wrong Hex - currentId := config.Config().GetString("identityId") - config.Config().Set("identityId", "ABCD") - idConfig, err := GetIdentityConfig() + currentId := cfg.GetString("identityId") + cfg.Set("identityId", "ABCD") + idConfig, err := GetIdentityConfig(cfg) assert.NotNil(t, err) assert.Contains(t, err.Error(), "hex string without 0x prefix") assert.Nil(t, idConfig) - config.Config().Set("identityId", currentId) + cfg.Set("identityId", currentId) //Wrong length - currentId = config.Config().GetString("identityId") - config.Config().Set("identityId", "0x0101010101") - idConfig, err = GetIdentityConfig() + currentId = cfg.GetString("identityId") + cfg.Set("identityId", "0x0101010101") + idConfig, err = GetIdentityConfig(cfg) assert.NotNil(t, err) assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") assert.Nil(t, idConfig) - config.Config().Set("identityId", currentId) + cfg.Set("identityId", currentId) //Wrong public signing key path - currentKeyPath, _ := config.Config().GetSigningKeyPair() - config.Config().Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") - idConfig, err = GetIdentityConfig() + currentKeyPath, _ := cfg.GetSigningKeyPair() + cfg.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") + idConfig, err = GetIdentityConfig(cfg) assert.NotNil(t, err) assert.Contains(t, err.Error(), "no such file or directory") assert.Nil(t, idConfig) - config.Config().Set("keys.signing.publicKey", currentKeyPath) + cfg.Set("keys.signing.publicKey", currentKeyPath) //Wrong public ethauth key path - currentKeyPath, _ = config.Config().GetEthAuthKeyPair() - config.Config().Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") - idConfig, err = GetIdentityConfig() + currentKeyPath, _ = cfg.GetEthAuthKeyPair() + cfg.Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") + idConfig, err = GetIdentityConfig(cfg) assert.NotNil(t, err) assert.Contains(t, err.Error(), "no such file or directory") assert.Nil(t, idConfig) - config.Config().Set("keys.ethauth.publicKey", currentKeyPath) + cfg.Set("keys.ethauth.publicKey", currentKeyPath) } func TestToCentId(t *testing.T) { diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index 8da13782b..5003f773f 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -32,7 +32,8 @@ type keyRegistrationConfirmationTask struct { key [32]byte keyPurpose int blockHeight uint64 - contextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + timeout time.Duration + contextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) ctx context.Context filterer keyRegisteredFilterer contract *EthereumIdentityRegistryContract @@ -42,7 +43,7 @@ type keyRegistrationConfirmationTask struct { } func newKeyRegistrationConfirmationTask( - ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), registryContract *EthereumIdentityRegistryContract, config Config, gethClientFinder func() ethereum.Client, @@ -52,6 +53,7 @@ func newKeyRegistrationConfirmationTask( contextInitializer: ethContextInitializer, contract: registryContract, config: config, + timeout: config.GetEthereumContextWaitTimeout(), gethClientFinder: gethClientFinder, contractProvider: contractProvider, } @@ -75,6 +77,7 @@ func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) krct.key, krct.keyPurpose, krct.blockHeight, + krct.timeout, krct.contextInitializer, krct.ctx, krct.filterer, @@ -120,10 +123,20 @@ func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]inter } // block height parsing - krct.blockHeight, err = parseBlockHeight(kwargs) + krct.blockHeight, err = queue.ParseBlockHeight(kwargs) if err != nil { return err } + + tdRaw, ok := kwargs[queue.TimeoutParam] + if ok { + td, err := queue.GetDuration(tdRaw) + if err != nil { + return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + } + krct.timeout = td + } + return nil } @@ -131,7 +144,7 @@ func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]inter func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the Key [%x]", krct.key) if krct.ctx == nil { - krct.ctx, _ = krct.contextInitializer() + krct.ctx, _ = krct.contextInitializer(krct.timeout) } id := newEthereumIdentity(krct.centID, krct.contract, krct.config, krct.gethClientFinder, krct.contractProvider) diff --git a/identity/key_registration_confirmation_task_test.go b/identity/key_registration_confirmation_task_test.go index 6932c314b..f1e013259 100644 --- a/identity/key_registration_confirmation_task_test.go +++ b/identity/key_registration_confirmation_task_test.go @@ -5,12 +5,41 @@ package identity import ( "testing" + "time" + + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { - rct := keyRegistrationConfirmationTask{} + rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} + id := utils.RandomSlice(CentIDLength) + key := utils.RandomSlice(32) + var keyFixed [32]byte + copy(keyFixed[:], key) + keyPurpose := KeyPurposeSigning + bh := uint64(12) + idBytes, _ := ToCentID(id) + kwargs := map[string]interface{}{ + centIDParam: idBytes, + keyParam: keyFixed, + keyPurposeParam: keyPurpose, + queue.BlockHeightParam: bh, + } + decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + err = rct.ParseKwargs(decoded) + if err != nil { + t.Errorf("parse error %s", err.Error()) + } + assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") + assert.Equal(t, keyFixed, rct.key, "Resulting key should be same as the input") + assert.Equal(t, keyPurpose, rct.keyPurpose, "Resulting keyPurpose should be same as the input") + assert.Equal(t, bh, rct.blockHeight, "Resulting blockheight should be same as the input") +} + +func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPathOverrideTimeout(t *testing.T) { + rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} id := utils.RandomSlice(CentIDLength) key := utils.RandomSlice(32) var keyFixed [32]byte @@ -18,11 +47,13 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { keyPurpose := KeyPurposeSigning bh := uint64(12) idBytes, _ := ToCentID(id) + overrideTimeout := float64(time.Second * 3) kwargs := map[string]interface{}{ - centIDParam: idBytes, - keyParam: keyFixed, - keyPurposeParam: keyPurpose, - blockHeightParam: bh, + centIDParam: idBytes, + keyParam: keyFixed, + keyPurposeParam: keyPurpose, + queue.BlockHeightParam: bh, + queue.TimeoutParam: overrideTimeout, } decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) @@ -33,6 +64,7 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { assert.Equal(t, keyFixed, rct.key, "Resulting key should be same as the input") assert.Equal(t, keyPurpose, rct.keyPurpose, "Resulting keyPurpose should be same as the input") assert.Equal(t, bh, rct.blockHeight, "Resulting blockheight should be same as the input") + assert.Equal(t, time.Duration(overrideTimeout).Seconds(), rct.timeout.Seconds(), "Resulting timeout should be overwritten by kwargs") } func TestKeyRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { diff --git a/identity/util.go b/identity/util.go index c45b6f643..663a19f3f 100644 --- a/identity/util.go +++ b/identity/util.go @@ -3,8 +3,7 @@ package identity import "errors" const ( - centIDParam string = "CentID" - blockHeightParam string = "BlockHeight" + centIDParam string = "CentID" ) func getBytes32(key interface{}) ([32]byte, error) { @@ -34,15 +33,3 @@ func getCentID(key interface{}) (CentID, error) { } return fixed, nil } - -func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[blockHeightParam]; ok { - bhf, ok := bhi.(float64) - if ok { - return uint64(bhf), nil - } else { - return 0, errors.New("value can not be parsed") - } - } - return 0, errors.New("value can not be parsed") -} diff --git a/keytools/ed25519/ed25519.go b/keytools/ed25519/ed25519.go index 863f2e5aa..dea7dfe17 100644 --- a/keytools/ed25519/ed25519.go +++ b/keytools/ed25519/ed25519.go @@ -3,7 +3,6 @@ package ed25519 import ( "fmt" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-crypto" @@ -33,9 +32,8 @@ func GetPrivateSigningKey(fileName string) (privateKey ed25519.PrivateKey, err e return ed25519.PrivateKey(key), nil } -// GetSigningKeyPairFromConfig returns the public and private key pair from the config -func GetSigningKeyPairFromConfig() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) { - pub, priv := config.Config().GetSigningKeyPair() +// GetSigningKeyPair returns the public and private key pair +func GetSigningKeyPair(pub, priv string) (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) { publicKey, err = GetPublicSigningKey(pub) if err != nil { return nil, nil, fmt.Errorf("failed to read public key: %v", err) diff --git a/keytools/ed25519/ed25519_test.go b/keytools/ed25519/ed25519_test.go index 92b7b50e2..6245d8cf5 100644 --- a/keytools/ed25519/ed25519_test.go +++ b/keytools/ed25519/ed25519_test.go @@ -11,11 +11,15 @@ import ( "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) result := m.Run() os.Exit(result) } @@ -34,29 +38,29 @@ func TestPublicKeyToP2PKey(t *testing.T) { } func TestGetSigningKeyPairFromConfig(t *testing.T) { - pub := config.Config().Get("keys.signing.publicKey") - pri := config.Config().Get("keys.signing.privateKey") + pub := cfg.Get("keys.signing.publicKey") + pri := cfg.Get("keys.signing.privateKey") // bad public key path - config.Config().Set("keys.signing.publicKey", "bad path") - pubK, priK, err := GetSigningKeyPairFromConfig() + cfg.Set("keys.signing.publicKey", "bad path") + pubK, priK, err := GetSigningKeyPair(cfg.GetSigningKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read public key") - config.Config().Set("keys.signing.publicKey", pub) + cfg.Set("keys.signing.publicKey", pub) // bad private key path - config.Config().Set("keys.signing.privateKey", "bad path") - pubK, priK, err = GetSigningKeyPairFromConfig() + cfg.Set("keys.signing.privateKey", "bad path") + pubK, priK, err = GetSigningKeyPair(cfg.GetSigningKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read private key") - config.Config().Set("keys.signing.privateKey", pri) + cfg.Set("keys.signing.privateKey", pri) // success - pubK, priK, err = GetSigningKeyPairFromConfig() + pubK, priK, err = GetSigningKeyPair(cfg.GetSigningKeyPair()) assert.Nil(t, err) assert.NotNil(t, pubK) assert.NotNil(t, priK) diff --git a/keytools/secp256k1/secp256k1.go b/keytools/secp256k1/secp256k1.go index 67f8ef838..e041a565f 100644 --- a/keytools/secp256k1/secp256k1.go +++ b/keytools/secp256k1/secp256k1.go @@ -6,7 +6,6 @@ import ( "crypto/rand" "fmt" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -115,9 +114,8 @@ func VerifySignature(publicKey, message, signature []byte) bool { } -// GetEthAuthKeyFromConfig returns the public and private keys as byte array -func GetEthAuthKeyFromConfig() (public, private []byte, err error) { - pub, priv := config.Config().GetEthAuthKeyPair() +// GetEthAuthKey returns the public and private keys as byte array +func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { privateKey, err := GetPrivateEthAuthKey(priv) if err != nil { return nil, nil, fmt.Errorf("failed to read private key: %v", err) diff --git a/keytools/secp256k1/secp256k1_test.go b/keytools/secp256k1/secp256k1_test.go index bae94c4fd..bab265b97 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/keytools/secp256k1/secp256k1_test.go @@ -16,12 +16,16 @@ import ( const MaxMsgLen = 32 +var ctx = map[string]interface{}{} +var cfg *config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, &testlogging.TestLoggingBootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) result := m.Run() os.Exit(result) } @@ -203,29 +207,29 @@ func TestGetAddress(t *testing.T) { } func TestGetEthAuthKeyFromConfig(t *testing.T) { - pub := config.Config().Get("keys.ethauth.publicKey") - pri := config.Config().Get("keys.ethauth.privateKey") + pub := cfg.Get("keys.ethauth.publicKey") + pri := cfg.Get("keys.ethauth.privateKey") // bad public key path - config.Config().Set("keys.ethauth.publicKey", "bad path") - pubK, priK, err := GetEthAuthKeyFromConfig() + cfg.Set("keys.ethauth.publicKey", "bad path") + pubK, priK, err := GetEthAuthKey(cfg.GetEthAuthKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read public key") - config.Config().Set("keys.ethauth.publicKey", pub) + cfg.Set("keys.ethauth.publicKey", pub) // bad private key path - config.Config().Set("keys.ethauth.privateKey", "bad path") - pubK, priK, err = GetEthAuthKeyFromConfig() + cfg.Set("keys.ethauth.privateKey", "bad path") + pubK, priK, err = GetEthAuthKey(cfg.GetEthAuthKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) assert.Contains(t, err.Error(), "failed to read private key") - config.Config().Set("keys.ethauth.privateKey", pri) + cfg.Set("keys.ethauth.privateKey", pri) // success - pubK, priK, err = GetEthAuthKeyFromConfig() + pubK, priK, err = GetEthAuthKey(cfg.GetEthAuthKeyPair()) assert.Nil(t, err) assert.NotNil(t, pubK) assert.NotNil(t, priK) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 255e7fc7a..f4ac5c9c9 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -17,12 +16,12 @@ type Bootstrapper struct { // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { + if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(Config) - if _, ok := ctx[bootstrap.BootstrappedEthereumClient]; !ok { + if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -32,5 +31,5 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } setPaymentObligation(NewEthereumPaymentObligation(registry, identity.IDService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) - return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext)) + return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext)) } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 0d4b49967..68ccd8d20 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -21,6 +21,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "time" + logging "github.com/ipfs/go-log" ) @@ -32,6 +34,14 @@ const amountOfProofs = 5 var regexCollaborators, _ = regexp.Compile("collaborators\\[[0-9]+\\]") +// Config is an interface to configurations required by nft package +type Config interface { + GetIdentityID() ([]byte, error) + GetEthereumDefaultAccountName() string + GetContractAddress(address string) common.Address + GetEthereumContextWaitTimeout() time.Duration +} + func setPaymentObligation(s *ethereumPaymentObligation) { po = s } @@ -40,13 +50,6 @@ func GetPaymentObligation() *ethereumPaymentObligation { return po } -// Config is an interface to configurations required by nft package -type Config interface { - GetIdentityID() ([]byte, error) - GetEthereumDefaultAccountName() string - GetContractAddress(address string) common.Address -} - // ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out type ethereumPaymentObligationContract interface { @@ -60,13 +63,13 @@ type ethereumPaymentObligation struct { identityService identity.Service ethClient ethereum.Client config Config - setupMintListener func(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) + setupMintListener func(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters func NewEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, - setupMintListener func(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { + setupMintListener func(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ registry: registry, identityService: identityService, @@ -146,7 +149,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, return nil, err } - watch, err := s.setupMintListener(requestData.TokenID, registryAddress) + watch, err := s.setupMintListener(s.config, requestData.TokenID, registryAddress) if err != nil { return nil, err } @@ -161,7 +164,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, // setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code // about successful minting of an NFt -func setupMintListener(tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { +func setupMintListener(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { confirmations = make(chan *WatchTokenMinted) conn := ethereum.GetClient() @@ -170,21 +173,21 @@ func setupMintListener(tokenID *big.Int, registryAddress string) (confirmations return nil, err } asyncRes, err := queue.Queue.DelayKwargs(mintingConfirmationTaskName, map[string]interface{}{ - tokenIDParam: hex.EncodeToString(tokenID.Bytes()), - blockHeightParam: h.Number.Uint64(), - registryAddressParam: registryAddress, + tokenIDParam: hex.EncodeToString(tokenID.Bytes()), + queue.BlockHeightParam: h.Number.Uint64(), + registryAddressParam: registryAddress, }) if err != nil { return nil, err } - go waitAndRouteNFTApprovedEvent(asyncRes, tokenID, confirmations) + go waitAndRouteNFTApprovedEvent(config.GetEthereumContextWaitTimeout(), asyncRes, tokenID, confirmations) return confirmations, nil } // waitAndRouteNFTApprovedEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteNFTApprovedEvent(asyncRes *gocelery.AsyncResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { - _, err := asyncRes.Get(ethereum.GetDefaultContextTimeout()) +func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { + _, err := asyncRes.Get(timeout) confirmations <- &WatchTokenMinted{tokenID, err} } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 156efd7e6..21b581ec8 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -9,14 +9,13 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -132,41 +131,17 @@ func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address return args.Get(0).(*types.Transaction), args.Error(1) } -type MockConfig struct { - mock.Mock -} - -func (m *MockConfig) GetIdentityID() ([]byte, error) { - args := m.Called() - return args.Get(0).([]byte), args.Error(1) -} - -func (m *MockConfig) GetEthereumDefaultAccountName() string { - args := m.Called() - return args.Get(0).(string) -} - -func (m *MockConfig) Config() *config.Configuration { - args := m.Called() - return args.Get(0).(*config.Configuration) -} - -func (m *MockConfig) GetContractAddress(address string) common.Address { - args := m.Called() - return args.Get(0).(common.Address) -} - func TestPaymentObligationService(t *testing.T) { tests := []struct { name string - mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, MockConfig) + mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig) request *nftpb.NFTMintRequest err error result string }{ { "happypath", - func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, MockConfig) { + func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig) { coreDoc := coredocument.New() coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) @@ -183,7 +158,7 @@ func TestPaymentObligationService(t *testing.T) { mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, ).Return(&types.Transaction{}, nil) - configMock := MockConfig{} + configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") configMock.On("GetContractAddress").Return(common.HexToAddress("0xd0dbc72ae5e71382b3cc9cfdc53f6952a085db6d")) @@ -199,11 +174,11 @@ func TestPaymentObligationService(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { // get mocks - docService, paymentOb, idService, ethClient, config := test.mocker() + docService, paymentOb, idService, ethClient, mockCfg := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) confirmations := make(chan *WatchTokenMinted) - service := NewEthereumPaymentObligation(registry, &idService, ðClient, &config, func(tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { + service := NewEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, func(config Config, tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { return confirmations, nil }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil @@ -218,7 +193,7 @@ func TestPaymentObligationService(t *testing.T) { paymentOb.AssertExpectations(t) idService.AssertExpectations(t) ethClient.AssertExpectations(t) - config.AssertExpectations(t) + mockCfg.AssertExpectations(t) }) } } diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index cf0d41126..25d4ca2cf 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -2,7 +2,6 @@ package nft import ( "context" - "errors" "fmt" "time" @@ -21,7 +20,6 @@ import ( const ( mintingConfirmationTaskName string = "MintingConfirmationTaskName" tokenIDParam string = "TokenIDParam" - blockHeightParam string = "BlockHeightParam" registryAddressParam string = "RegistryAddressParam" ) @@ -38,16 +36,18 @@ type mintingConfirmationTask struct { TokenID string BlockHeight uint64 RegistryAddress string + Timeout time.Duration //state - EthContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc) + EthContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) } func newMintingConfirmationTask( - ethContextInitializer func() (ctx context.Context, cancelFunc context.CancelFunc), + timeout time.Duration, + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), ) *mintingConfirmationTask { return &mintingConfirmationTask{ - + Timeout: timeout, EthContextInitializer: ethContextInitializer, } } @@ -69,6 +69,7 @@ func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { nftc.TokenID, nftc.BlockHeight, nftc.RegistryAddress, + nftc.Timeout, nftc.EthContextInitializer, }, nil } @@ -86,7 +87,7 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) } // parse BlockHeight - nftc.BlockHeight, err = parseBlockHeight(kwargs) + nftc.BlockHeight, err = queue.ParseBlockHeight(kwargs) if err != nil { return err } @@ -102,24 +103,24 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) return fmt.Errorf("malformed kwarg [%s]", registryAddressParam) } - return nil -} - -func parseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[blockHeightParam]; ok { - bhf, ok := bhi.(float64) - if ok { - return uint64(bhf), nil + // override TimeoutParam if provided + tdRaw, ok := kwargs[queue.TimeoutParam] + if ok { + td, err := queue.GetDuration(tdRaw) + if err != nil { + return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } + nftc.Timeout = td } - return 0, errors.New("value can not be parsed") + + return nil } // RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.TokenID) - ethContext, _ := nftc.EthContextInitializer() + ethContext, _ := nftc.EthContextInitializer(nftc.Timeout) fOpts := &bind.FilterOpts{ Context: ethContext, diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go index 8811f0435..20a6061c8 100644 --- a/nft/minting_confirmation_task_test.go +++ b/nft/minting_confirmation_task_test.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "testing" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -17,9 +18,9 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { registryAddress := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" kwargs := map[string]interface{}{ - tokenIDParam: tokenId, - blockHeightParam: blockHeight, - registryAddressParam: registryAddress, + tokenIDParam: tokenId, + queue.BlockHeightParam: blockHeight, + registryAddressParam: registryAddress, } decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) @@ -37,16 +38,16 @@ func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { task := mintingConfirmationTask{} tests := []map[string]interface{}{ { - blockHeightParam: uint64(12), - registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", + queue.BlockHeightParam: uint64(12), + registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", }, { tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", }, { - tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), - blockHeightParam: uint64(12), + tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), + queue.BlockHeightParam: uint64(12), }, { //empty map diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index e1f575c5d..f9f0b43b8 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -13,6 +13,7 @@ import ( cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/identity" @@ -22,24 +23,26 @@ import ( ) var registry *documents.ServiceRegistry +var cfg *config.Configuration func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - prevSignPubkey := config.Config().Get("keys.signing.publicKey") - prevSignPrivkey := config.Config().Get("keys.signing.privateKey") - prevEthPubkey := config.Config().Get("keys.ethauth.publicKey") - prevEthPrivkey := config.Config().Get("keys.ethauth.privateKey") - config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + prevSignPubkey := cfg.Get("keys.signing.publicKey") + prevSignPrivkey := cfg.Get("keys.signing.privateKey") + prevEthPubkey := cfg.Get("keys.ethauth.publicKey") + prevEthPrivkey := cfg.Get("keys.ethauth.privateKey") + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() - config.Config().Set("keys.signing.publicKey", prevSignPubkey) - config.Config().Set("keys.signing.privateKey", prevSignPrivkey) - config.Config().Set("keys.ethauth.publicKey", prevEthPubkey) - config.Config().Set("keys.ethauth.privateKey", prevEthPrivkey) + cfg.Set("keys.signing.publicKey", prevSignPubkey) + cfg.Set("keys.signing.privateKey", prevSignPrivkey) + cfg.Set("keys.ethauth.publicKey", prevEthPubkey) + cfg.Set("keys.ethauth.privateKey", prevEthPrivkey) cc.TestFunctionalEthereumTearDown() os.Exit(result) } @@ -47,12 +50,12 @@ func TestMain(m *testing.M) { func TestPaymentObligationService_mint(t *testing.T) { // create identity log.Debug("Create Identity for Testing") - testingidentity.CreateIdentityWithKeys() + testingidentity.CreateIdentityWithKeys(cfg) // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader, err := documents.NewContextHeader() + contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) @@ -68,7 +71,7 @@ func TestPaymentObligationService_mint(t *testing.T) { }, }, contextHeader) assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, err := invoiceService.Create(context.Background(), model) + modelUpdated, err := invoiceService.Create(contextHeader, model) // get ID ID, err := modelUpdated.ID() @@ -77,7 +80,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // assert no error confirmations, err := nft.GetPaymentObligation().MintNFT( ID, - config.Config().GetContractAddress("paymentObligation").String(), + cfg.GetContractAddress("paymentObligation").String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", []string{"gross_amount", "currency", "due_date", "document_type", "collaborators[0]"}, ) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index b082a1bbd..48e1e3352 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -8,12 +8,14 @@ import ( "github.com/centrifuge/go-centrifuge/documents" ) +const BootstrappedP2PClient string = "BootstrappedP2PClient" + // Bootstrapper implements Bootstrapper with p2p details type Bootstrapper struct{} // Bootstrap initiates p2p server and client into context func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg, ok := ctx[config.BootstrappedConfig].(*config.Configuration) if !ok { return fmt.Errorf("config not initialised") } @@ -23,8 +25,8 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("registry not initialised") } - srv := &p2pServer{config: cfg, registry: registry} + srv := &p2pServer{config: cfg, registry: registry, handler: GRPCHandler(cfg, registry)} ctx[bootstrap.BootstrappedP2PServer] = srv - ctx[bootstrap.BootstrappedP2PClient] = srv + ctx[BootstrappedP2PClient] = srv return nil } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 5ef408256..383722f4f 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -23,7 +23,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config c := &config.Configuration{} - m[bootstrap.BootstrappedConfig] = c + m[config.BootstrappedConfig] = c m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) @@ -32,7 +32,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { _, ok := m[bootstrap.BootstrappedP2PServer].(node.Server) assert.True(t, ok) - assert.NotNil(t, m[bootstrap.BootstrappedP2PClient]) - _, ok = m[bootstrap.BootstrappedP2PClient].(Client) + assert.NotNil(t, m[BootstrappedP2PClient]) + _, ok = m[BootstrappedP2PClient].(Client) assert.True(t, ok) } diff --git a/p2p/client.go b/p2p/client.go index 75aa91831..fc515ea2c 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/version" "github.com/libp2p/go-libp2p-peer" @@ -19,7 +20,7 @@ import ( type Client interface { OpenClient(target string) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // OpenClient returns P2PServiceClient to contact the remote peer @@ -119,11 +120,11 @@ func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService ident } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (s *p2pServer) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) - extCollaborators, err := coredocument.GetExternalCollaborators(doc) + extCollaborators, err := coredocument.GetExternalCollaborators(ctx.Self().ID, doc) if err != nil { return centerrors.Wrap(err, "failed to get external collaborators") } @@ -149,7 +150,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityServic // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - go s.getSignatureAsync(ctx, identityService, *doc, client, collaboratorID, in) + go s.getSignatureAsync(ctx.Context(), identityService, *doc, client, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/p2p/handler.go b/p2p/handler.go index 2aa71b56a..c18031693 100644 --- a/p2p/handler.go +++ b/p2p/handler.go @@ -8,8 +8,10 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/version" ) @@ -39,11 +41,12 @@ func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb. // handler implements the grpc interface type handler struct { registry *documents.ServiceRegistry + config config.Config } // GRPCHandler returns an implementation of P2PServiceServer -func GRPCHandler(registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { - return handler{registry: registry} +func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { + return handler{registry: registry, config: config} } // RequestDocumentSignature signs the received document and returns the signature of the signingRoot @@ -51,7 +54,12 @@ func GRPCHandler(registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - err := handshakeValidator().Validate(sigReq.Header) + ctxHeader, err := header.NewContextHeader(ctx, srv.config) + if err != nil { + log.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + err = handshakeValidator(srv.config.GetNetworkID()).Validate(sigReq.Header) if err != nil { return nil, err } @@ -61,7 +69,7 @@ func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.S return nil, centerrors.New(code.DocumentInvalid, err.Error()) } - signature, err := svc.RequestDocumentSignature(model) + signature, err := svc.RequestDocumentSignature(ctxHeader, model) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -74,7 +82,7 @@ func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.S // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { - err := handshakeValidator().Validate(docReq.Header) + err := handshakeValidator(srv.config.GetNetworkID()).Validate(docReq.Header) if err != nil { return nil, err } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 490d49cd4..b400a241e 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -32,19 +32,21 @@ import ( var ( handler p2ppb.P2PServiceServer anchorRepo anchors.AnchorRepository + cfg *config.Configuration ) func TestMain(m *testing.M) { flag.Parse() ctx := cc.TestFunctionalEthereumBootstrap() registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - handler = p2p.GRPCHandler(registry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - config.Config().Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - config.Config().Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - config.Config().Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - config.Config().Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - testingidentity.CreateIdentityWithKeys() + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + handler = p2p.GRPCHandler(cfg, registry) + testingidentity.CreateIdentityWithKeys(cfg) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -113,7 +115,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) // Anchor document - idConfig, err := identity.GetIdentityConfig() + idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) @@ -155,7 +157,7 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { doc.DocumentRoot = tree.RootHash() // Anchor document - idConfig, err := identity.GetIdentityConfig() + idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) @@ -177,14 +179,14 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { func createIdentity(t *testing.T) identity.CentID { // Create Identity centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - config.Config().Set("identityId", centrifugeId.String()) + cfg.Set("identityId", centrifugeId.String()) id, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - idConfig, err := identity.GetIdentityConfig() + idConfig, err := identity.GetIdentityConfig(cfg) // Add Keys pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeSigning, pubKey) @@ -204,7 +206,7 @@ func createIdentity(t *testing.T) identity.CentID { } func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument) *coredocumentpb.CoreDocument { - idConfig, err := identity.GetIdentityConfig() + idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) if doc == nil { doc = testingcoredocument.GenerateCoreDocument() @@ -236,13 +238,13 @@ func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentR return &p2ppb.AnchorDocumentRequest{ Header: &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: cfg.GetNetworkID(), }, Document: doc, } } func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureRequest { return &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID(), + CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID(), }, Document: doc} } diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 070ed6183..e02938916 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -44,9 +44,13 @@ func TestMain(m *testing.M) { } ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - grpcHandler = GRPCHandler(registry) + grpcHandler = GRPCHandler(cfg, registry) testClient = &p2pServer{config: cfg} result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -55,7 +59,7 @@ func TestMain(m *testing.M) { func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID(), + CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID(), }} resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) @@ -65,7 +69,7 @@ func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { func TestHandler_RequestDocumentSignature_version_fail(t *testing.T) { req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: config.Config().GetNetworkID(), + CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: cfg.GetNetworkID(), }} resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) @@ -78,7 +82,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { // Test invalid version header := &p2ppb.CentrifugeHeader{ CentNodeVersion: "1000.0.0-invalid", - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: cfg.GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Document: coreDoc, Header: header} res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) @@ -88,7 +92,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { assert.Nil(t, res) // Test invalid network - header.NetworkIdentifier = config.Config().GetNetworkID() + 1 + header.NetworkIdentifier = cfg.GetNetworkID() + 1 header.CentNodeVersion = version.GetVersion().String() res, err = grpcHandler.SendAnchoredDocument(context.Background(), &req) assert.Error(t, err) @@ -100,7 +104,7 @@ func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { func TestSendAnchoredDocument_NilDocument(t *testing.T) { header := &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: cfg.GetNetworkID(), } req := p2ppb.AnchorDocumentRequest{Header: header} res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) @@ -113,7 +117,7 @@ func TestHandler_SendAnchoredDocument_getServiceAndModel_fail(t *testing.T) { req := &p2ppb.AnchorDocumentRequest{ Header: &p2ppb.CentrifugeHeader{ CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: config.Config().GetNetworkID(), + NetworkIdentifier: cfg.GetNetworkID(), }, Document: coredocument.New(), } @@ -131,21 +135,21 @@ func TestP2PService_basicChecks(t *testing.T) { }{ { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "someversion", NetworkIdentifier: 12}, - err: documents.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(config.Config().GetNetworkID(), 12)), + err: documents.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), }, { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "0.0.1", NetworkIdentifier: 12}, - err: documents.AppendError(incompatibleNetworkError(config.Config().GetNetworkID(), 12), nil), + err: documents.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), }, { - header: &p2ppb.CentrifugeHeader{CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: config.Config().GetNetworkID()}, + header: &p2ppb.CentrifugeHeader{CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}, }, } for _, c := range tests { - err := handshakeValidator().Validate(c.header) + err := handshakeValidator(cfg.GetNetworkID()).Validate(c.header) if err != nil { if c.err == nil { t.Fatalf("unexpected error: %v\n", err) diff --git a/p2p/server.go b/p2p/server.go index be68bc06c..da119b1ec 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -1,4 +1,3 @@ -// PLEASE DO NOT call any config.* stuff here as it creates dependencies that can't be injected easily when testing package p2p import ( @@ -35,6 +34,7 @@ type Config interface { GetP2PConnectionTimeout() time.Duration GetNetworkID() uint32 GetIdentityID() ([]byte, error) + GetSigningKeyPair() (pub, priv string) } // p2pServer implements api.Server @@ -43,6 +43,7 @@ type p2pServer struct { host host.Host registry *documents.ServiceRegistry protocol *p2pgrpc.GRPCProtocol + handler p2ppb.P2PServiceServer } // Name returns the P2PServer @@ -69,7 +70,7 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch // Set the grpc protocol handler on it s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) - p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), GRPCHandler(s.registry)) + p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), s.handler) serveErr := make(chan error) go func() { @@ -229,7 +230,7 @@ func (s *p2pServer) makeBasicHost(listenPort int) (host.Host, error) { func (s *p2pServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { // Create the signing key for the host - publicKey, privateKey, err := cented25519.GetSigningKeyPairFromConfig() + publicKey, privateKey, err := cented25519.GetSigningKeyPair(s.config.GetSigningKeyPair()) if err != nil { return nil, nil, fmt.Errorf("failed to get keys: %v", err) } diff --git a/p2p/server_test.go b/p2p/server_test.go index b9669da8f..698ea7bb0 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -19,9 +19,7 @@ func TestCentP2PServer_Start(t *testing.T) { func TestCentP2PServer_StartContextCancel(t *testing.T) { cfg.Set("p2p.port", 38203) - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cp2p := &p2pServer{config: cfg} + cp2p := &p2pServer{config: cfg, handler: GRPCHandler(cfg, nil)} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) var wg sync.WaitGroup @@ -35,8 +33,6 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { } func TestCentP2PServer_StartListenError(t *testing.T) { - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") // cause an error by using an invalid port cfg.Set("p2p.port", 100000000) cp2p := &p2pServer{config: cfg} @@ -53,8 +49,6 @@ func TestCentP2PServer_StartListenError(t *testing.T) { func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { listenPort := 38202 - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) cp2p := &p2pServer{config: cfg} @@ -66,8 +60,6 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) cfg.Set("p2p.externalIP", externalIP) cp2p := &p2pServer{config: cfg} @@ -83,8 +75,6 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("p2p.port", listenPort) cfg.Set("p2p.externalIP", externalIP) cp2p := &p2pServer{config: cfg} diff --git a/p2p/validator.go b/p2p/validator.go index ef353f351..5ea6f35ab 100644 --- a/p2p/validator.go +++ b/p2p/validator.go @@ -6,7 +6,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/version" ) @@ -51,22 +50,22 @@ func versionValidator() Validator { }) } -func networkValidator() Validator { +func networkValidator(networkID uint32) Validator { return ValidatorFunc(func(header *p2ppb.CentrifugeHeader) error { if header == nil { return fmt.Errorf("nil header") } - if config.Config().GetNetworkID() != header.NetworkIdentifier { - return incompatibleNetworkError(config.Config().GetNetworkID(), header.NetworkIdentifier) + if networkID != header.NetworkIdentifier { + return incompatibleNetworkError(networkID, header.NetworkIdentifier) } return nil }) } -func handshakeValidator() ValidatorGroup { +func handshakeValidator(networkID uint32) ValidatorGroup { return ValidatorGroup{ versionValidator(), - networkValidator(), + networkValidator(networkID), } } diff --git a/p2p/validator_test.go b/p2p/validator_test.go index b2e052e6c..84289a802 100644 --- a/p2p/validator_test.go +++ b/p2p/validator_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" ) @@ -40,7 +39,7 @@ func TestValidate_versionValidator(t *testing.T) { } func TestValidate_networkValidator(t *testing.T) { - nv := networkValidator() + nv := networkValidator(cfg.GetNetworkID()) // Nil header err := nv.Validate(nil) @@ -56,13 +55,13 @@ func TestValidate_networkValidator(t *testing.T) { assert.NotNil(t, err) // Compatible network - header.NetworkIdentifier = config.Config().GetNetworkID() + header.NetworkIdentifier = cfg.GetNetworkID() err = nv.Validate(header) assert.Nil(t, err) } func TestValidate_handshakeValidator(t *testing.T) { - hv := handshakeValidator() + hv := handshakeValidator(cfg.GetNetworkID()) // Incompatible version and network header := &p2ppb.CentrifugeHeader{ @@ -73,7 +72,7 @@ func TestValidate_handshakeValidator(t *testing.T) { assert.NotNil(t, err) // Incompatible version, correct network - header.NetworkIdentifier = config.Config().GetNetworkID() + header.NetworkIdentifier = cfg.GetNetworkID() err = hv.Validate(header) assert.NotNil(t, err) @@ -84,7 +83,7 @@ func TestValidate_handshakeValidator(t *testing.T) { assert.NotNil(t, err) // Compatible version and network - header.NetworkIdentifier = config.Config().GetNetworkID() + header.NetworkIdentifier = cfg.GetNetworkID() err = hv.Validate(header) assert.Nil(t, err) } diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index 88dc72caf..dbe3d4106 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -3,7 +3,6 @@ package queue import ( "errors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" ) @@ -13,10 +12,10 @@ type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(*config.Configuration) // to see how BootstrappedQueuedTasks get populated check usages of InstallQueuedTask if queuedTasks, ok := context[BootstrappedQueuedTasks]; ok { if queuedTasksTyped, ok := queuedTasks.([]QueuedTask); ok { diff --git a/queue/queue.go b/queue/queue.go index cd950b62c..a80cf887e 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -3,9 +3,17 @@ package queue import ( "sync" + "errors" + "time" + "github.com/centrifuge/gocelery" ) +const ( + BlockHeightParam string = "BlockHeight" + TimeoutParam string = "Timeout" +) + var Queue *gocelery.CeleryClient var queueInit sync.Once @@ -37,3 +45,25 @@ func InitQueue(tasks []QueuedTask, numWorkers, workerWaitTime int) { func StopQueue() { Queue.StopWorker() } + +// GetDuration parses key parameter to time.Duration type +func GetDuration(key interface{}) (time.Duration, error) { + f64, ok := key.(float64) + if !ok { + return time.Duration(0), errors.New("Could not parse interface to float64") + } + return time.Duration(f64), nil +} + +// ParseBlockHeight parses blockHeight interface param to uint64 +func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { + if bhi, ok := valMap[BlockHeightParam]; ok { + bhf, ok := bhi.(float64) + if ok { + return uint64(bhf), nil + } else { + return 0, errors.New("value can not be parsed") + } + } + return 0, errors.New("value can not be parsed") +} diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index 7f5dbc165..c0dc0aa98 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -4,24 +4,25 @@ import ( "errors" "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" ) +const BootstrappedLevelDb string = "BootstrappedLevelDb" + type Bootstrapper struct { } func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config not initialised") } - cfg := context[bootstrap.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(*config.Configuration) levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } - context[bootstrap.BootstrappedLevelDb] = levelDB + context[BootstrappedLevelDb] = levelDB return nil } diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index bc5812f91..858d6dd44 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -5,7 +5,6 @@ package storage import ( "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" ) @@ -14,15 +13,16 @@ const testStoragePath = "/tmp/centrifuge_data.leveldb_TESTING" func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { rs := getRandomTestStoragePath() - config.Config().SetDefault("storage.Path", rs) - log.Info("Set storage.Path to:", config.Config().GetStoragePath()) - levelDB, err := NewLevelDBStorage(config.Config().GetStoragePath()) + cfg := context[config.BootstrappedConfig].(*config.Configuration) + cfg.SetDefault("storage.Path", rs) + log.Info("Set storage.Path to:", cfg.GetStoragePath()) + levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } - log.Infof("Setting levelDb at: %s", config.Config().GetStoragePath()) - context[bootstrap.BootstrappedLevelDb] = levelDB + log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) + context[BootstrappedLevelDb] = levelDB return nil } diff --git a/testingutils/config/config.go b/testingutils/config/config.go new file mode 100644 index 000000000..1ddb55ea7 --- /dev/null +++ b/testingutils/config/config.go @@ -0,0 +1,154 @@ +package testingconfig + +import ( + "math/big" + "time" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" +) + +type MockConfig struct { + mock.Mock +} + +func (m *MockConfig) GetStoragePath() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetP2PPort() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetP2PExternalIP() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetP2PConnectionTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetReceiveEventNotificationEndpoint() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetServerPort() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetServerAddress() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetNumWorkers() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetWorkerWaitTimeMS() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetEthereumNodeURL() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetEthereumContextReadWaitTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumContextWaitTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumIntervalRetry() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumMaxRetries() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetEthereumGasPrice() *big.Int { + args := m.Called() + return args.Get(0).(*big.Int) +} + +func (m *MockConfig) GetEthereumGasLimit() uint64 { + args := m.Called() + return args.Get(0).(uint64) +} + +func (m *MockConfig) GetEthereumDefaultAccountName() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetEthereumAccount(accountName string) (account *config.AccountConfig, err error) { + args := m.Called() + return args.Get(0).(*config.AccountConfig), args.Error(1) +} + +func (m *MockConfig) GetTxPoolAccessEnabled() bool { + args := m.Called() + return args.Get(0).(bool) +} + +func (m *MockConfig) GetNetworkString() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetNetworkKey(k string) string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetContractAddressString(address string) string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetContractAddress(address string) common.Address { + args := m.Called() + return args.Get(0).(common.Address) +} + +func (m *MockConfig) GetBootstrapPeers() []string { + args := m.Called() + return args.Get(0).([]string) +} + +func (m *MockConfig) GetNetworkID() uint32 { + args := m.Called() + return args.Get(0).(uint32) +} + +func (m *MockConfig) GetIdentityID() ([]byte, error) { + args := m.Called() + return args.Get(0).([]byte), args.Error(1) +} + +func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} + +func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index bd98c48c2..0fbb25007 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -3,11 +3,10 @@ package testingcoredocument import ( - "context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -39,13 +38,13 @@ type MockCoreDocumentProcessor struct { mock.Mock } -func (m *MockCoreDocumentProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (m *MockCoreDocumentProcessor) Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { args := m.Called(coreDocument, ctx, recipient) return args.Error(0) } func (m *MockCoreDocumentProcessor) Anchor( - ctx context.Context, + ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, saveState func(*coredocumentpb.CoreDocument) error) (err error) { args := m.Called(ctx, coreDocument, saveState) @@ -58,12 +57,12 @@ func (m *MockCoreDocumentProcessor) Anchor( return args.Error(0) } -func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(model documents.Model) error { +func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { +func (m *MockCoreDocumentProcessor) RequestSignatures(ctx *header.ContextHeader, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } @@ -73,12 +72,12 @@ func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) e return args.Error(0) } -func (m *MockCoreDocumentProcessor) AnchorDocument(model documents.Model) error { +func (m *MockCoreDocumentProcessor) AnchorDocument(ctx *header.ContextHeader, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) SendDocument(ctx context.Context, model documents.Model) error { +func (m *MockCoreDocumentProcessor) SendDocument(ctx *header.ContextHeader, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 08c5e22b5..6e31a3c9d 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -6,6 +6,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/header" "github.com/stretchr/testify/mock" ) @@ -38,7 +39,7 @@ func (m *MockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (d return args.Get(0).(documents.Model), args.Error(1) } -func (m *MockService) RequestDocumentSignature(model documents.Model) (*coredocumentpb.Signature, error) { +func (m *MockService) RequestDocumentSignature(ctx *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { args := m.Called() return args.Get(0).(*coredocumentpb.Signature), args.Error(1) } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 55e71dd2c..33a3e49da 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -3,12 +3,13 @@ package testingidentity import ( + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" ) -func CreateIdentityWithKeys() identity.CentID { - idConfig, _ := identity.GetIdentityConfig() +func CreateIdentityWithKeys(cfg config.Config) identity.CentID { + idConfig, _ := identity.GetIdentityConfig(cfg) // only create identity if it doesn't exist id, err := identity.IDService.LookupIdentityForID(idConfig.ID) if err != nil { @@ -20,14 +21,14 @@ func CreateIdentityWithKeys() identity.CentID { // only add key if it doesn't exist _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext() + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(cfg.GetEthereumContextWaitTimeout()) defer cancel() if err != nil { confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) <-confirmations } _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) - ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext() + ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext(cfg.GetEthereumContextWaitTimeout()) defer cancel() if err != nil { confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) From 24c2408ce39fec970f17cb61177e9d41fd9f1232 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 20 Nov 2018 17:17:26 +0100 Subject: [PATCH 037/220] fix missing po config (#470) --- api/service.go | 3 ++- documents/purchaseorder/handler.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/api/service.go b/api/service.go index c4dfee8ca..550a3cd17 100644 --- a/api/service.go +++ b/api/service.go @@ -41,7 +41,8 @@ func registerServices(ctx context.Context, cfg Config, registry *documents.Servi } // purchase orders - srv, err := purchaseorder.GRPCHandler(registry) + poCfg := cfg.(config.Config) + srv, err := purchaseorder.GRPCHandler(poCfg, registry) if err != nil { return fmt.Errorf("failed to get purchase order handler: %v", err) } diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 116f228eb..d50e81b5c 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -25,7 +25,7 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler(registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { +func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { return nil, fmt.Errorf("failed to fetch purchase order service") @@ -33,6 +33,7 @@ func GRPCHandler(registry *documents.ServiceRegistry) (clientpurchaseorderpb.Doc return grpcHandler{ service: srv.(Service), + config: config, }, nil } From d0f089a523adb5c8808de8a61bf1093b72983c65 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 21 Nov 2018 15:53:38 +0100 Subject: [PATCH 038/220] Kovan/fixes (#471) Changes: - Create default config for Kovan - Minor changes to createconfig to support txpoolaccess option - logging fixes - Use go-ethereum with kovan fixes Fixes https://github.com/centrifuge/roadmap/issues/61 --- Gopkg.lock | 15 +++++++++++++-- Gopkg.toml | 4 ++-- build/configs/default_config.yaml | 18 +++++++++++++++++- cmd/create_config.go | 5 ++++- config/configuration.go | 2 ++ config/configuration_test.go | 1 + identity/ethereum_identity.go | 2 +- resources/data.go | 8 ++++---- 8 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 6c370f8d3..91f166f72 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -21,6 +21,17 @@ pruneopts = "UT" revision = "5312a61534124124185d41f09206b9fef1d88403" +[[projects]] + digest = "1:1156cfea0ff969858f6027df95c15ca5e802556b466aebeedaf53dde3b301db3" + name = "github.com/allegro/bigcache" + packages = [ + ".", + "queue", + ] + pruneopts = "UT" + revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068" + version = "v1.1.0" + [[projects]] branch = "master" digest = "1:7d191fd0c54ff370eaf6116a14dafe2a328df487baea280699f597aae858d00d" @@ -101,7 +112,7 @@ version = "v1.7" [[projects]] - digest = "1:0f390470311a75caba6b4223dcd881d4a9c5141afaf7fef3c5908c145a5073dd" + digest = "1:6aada383585d097e8ef3d06b74956eb1f22f49acb94ca0cb0672c1e767171a23" name = "github.com/ethereum/go-ethereum" packages = [ ".", @@ -130,7 +141,7 @@ "trie", ] pruneopts = "T" - revision = "e024c16f34c6028060b645efae1d6258e442442a" + revision = "27e633ca943ee9f49614b9ea074667227402b571" source = "github.com/centrifuge/go-ethereum" [[projects]] diff --git a/Gopkg.toml b/Gopkg.toml index b4e3c9eaa..4172e6141 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -50,10 +50,10 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/xsleonard/go-merkle" revision = "fbb7cafc5ae411e13e718172f5af7917ad6c3ed7" -[[constraint]] +[[override]] name = "github.com/ethereum/go-ethereum" source = "github.com/centrifuge/go-ethereum" - revision = "e024c16f34c6028060b645efae1d6258e442442a" + revision = "27e633ca943ee9f49614b9ea074667227402b571" [[override]] name = "github.com/satori/go.uuid" diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 85518be7d..e2a3e7329 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -30,7 +30,23 @@ networks: identityFactory: "0x90d294571e73842697a66b7a99a09dd6c73d356d" identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" anchorRepository: "0x7f854dfa98012d7fa55c803bba2260bcdee4b5ed" - paymentObligation: "" + paymentObligation: "0x691280677b52e3ca71e023eed2d83fa9fac3b64b" + + bernalheights: + # Numeric ID of the Centrifuge network + id: 52 + # Bootstrap list of nodes that Centrifuge provides to the russianhill testnet + bootstrapPeers: + - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" + - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" + # Ethereum network ID - Kovan + ethereumNetworkId: 42 + # Latest deployed Smart Contracts for the given testnet + contractAddresses: + identityFactory: "0x85b32f7a3f40481f12334041670c8cbe07f7d79c" + identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" + anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" + paymentObligation: "0xa3d3b45f422016201d7cd4c2bc217665483d90e6" # Peer-to-peer configurations p2p: diff --git a/cmd/create_config.go b/cmd/create_config.go index 3bfbae2cc..905f52ee1 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -18,6 +18,7 @@ var network string var apiPort int64 var p2pPort int64 var bootstraps []string +var txPoolAccess bool func createIdentity() (identity.CentID, error) { centrifugeId := identity.RandomCentID() @@ -76,6 +77,7 @@ func init() { "bootstraps": bootstraps, "apiPort": apiPort, "p2pPort": p2pPort, + "txpoolaccess": txPoolAccess, } v, err := config.CreateConfigFile(data) @@ -110,12 +112,13 @@ func init() { } createConfigCmd.Flags().StringVarP(&targetDataDir, "targetdir", "t", home+"/datadir", "Target Data Dir") - createConfigCmd.Flags().StringVarP(ðNodeUrl, "ethnodeurl", "e", "ws://127.0.0.1:9546", "URL of Ethereum Client Node (WS only)") + createConfigCmd.Flags().StringVarP(ðNodeUrl, "ethnodeurl", "e", "ws://127.0.0.1:9546", "URL of Ethereum Client Node") createConfigCmd.Flags().StringVarP(&accountKeyPath, "accountkeypath", "z", home+"/datadir/main.key", "Path of Ethereum Account Key JSON file") createConfigCmd.Flags().StringVarP(&accountPassword, "accountpwd", "k", "", "Ethereum Account Password") createConfigCmd.Flags().Int64VarP(&apiPort, "apiPort", "a", 8082, "Api Port") createConfigCmd.Flags().Int64VarP(&p2pPort, "p2pPort", "p", 38202, "Peer-to-Peer Port") createConfigCmd.Flags().StringVarP(&network, "network", "n", "russianhill", "Default Network") createConfigCmd.Flags().StringSliceVarP(&bootstraps, "bootstraps", "b", nil, "Bootstrap P2P Nodes") + createConfigCmd.Flags().BoolVarP(&txPoolAccess, "txpoolaccess", "x", true, "Transaction Pool access") rootCmd.AddCommand(createConfigCmd) } diff --git a/config/configuration.go b/config/configuration.go index 68112758c..86fd3c1f1 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -336,6 +336,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { bootstraps := args["bootstraps"].([]string) apiPort := args["apiPort"].(int64) p2pPort := args["p2pPort"].(int64) + txPoolAccess := args["txpoolaccess"].(bool) if targetDataDir == "" { return nil, errors.New("targetDataDir not provided") @@ -366,6 +367,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("nodePort", apiPort) v.Set("p2p.port", p2pPort) v.Set("ethereum.nodeURL", ethNodeUrl) + v.Set("ethereum.txPoolAccessEnabled", txPoolAccess) v.Set("ethereum.accounts.main.key", string(bfile)) v.Set("ethereum.accounts.main.password", accountPassword) v.Set("keys.p2p.privateKey", targetDataDir+"/p2p.key.pem") diff --git a/config/configuration_test.go b/config/configuration_test.go index 3590391bc..30aa320cd 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -30,6 +30,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { "bootstraps": []string{"/ip4/127.0.0.1/bootstrap1", "/ip4/127.0.0.1/bootstrap2"}, "apiPort": int64(8082), "p2pPort": int64(38202), + "txpoolaccess": false, } v, err := CreateConfigFile(data) diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index 6992d14f9..aa1f03449 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -542,7 +542,7 @@ func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { return err } - log.Infof("Key [%v] with type [$s] Added to Identity [%s]", lastKey, purpose, watchAddedToIdentity.Identity) + log.Infof("Key [%v] with type [%d] Added to Identity [%s]", lastKey, purpose, watchAddedToIdentity.Identity) return nil } diff --git a/resources/data.go b/resources/data.go index 80111fde7..fc45e9474 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\xc9\x76\xdb\x3a\x0f\xde\xeb\x29\x70\x9c\xcd\xff\x2f\x62\x6b\xb0\x64\x5b\xbb\x8c\x9d\x9c\x5c\xc7\x71\x9b\x26\x3b\x8a\x84\x2c\xd6\x12\xa9\x90\x94\x87\x3e\xfd\x3d\xa4\xa4\x34\x43\xd3\x5e\xaf\x78\x0c\xe0\xc3\xf4\x01\xd0\x11\x9c\x63\x4e\x9a\xd2\x00\xc3\x2d\x96\xb2\xae\x50\x18\x30\xa8\x8d\x40\x03\x64\x4d\xb8\xd0\x06\x14\x17\x1b\xcc\x0e\x1e\x45\x61\x14\xcf\x9b\x35\x5e\xa3\xd9\x49\xb5\x49\x41\x35\x5a\x73\x22\x0a\x5e\x96\x9e\x03\xe3\x02\xc1\x14\x08\xac\xc3\x15\xad\xa6\x06\x53\x10\x03\x67\x4f\x08\x50\x11\x2e\x8c\xc5\xf7\x7a\x95\xd4\x03\x38\x82\xb9\xa4\xa4\x74\x21\x70\xb1\x06\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x86\xa0\xd1\xc0\x8e\x9b\x02\x50\x6c\x61\x4b\x14\x27\x59\x89\x7a\xe8\x41\x6f\x6f\x21\x01\x38\x4b\x21\x8a\x22\xf7\x46\x53\xa0\xc2\xa6\xea\x32\xf8\xc4\x52\x98\x46\xd3\x56\x96\x49\x69\xb4\x51\xa4\x5e\x20\x2a\xdd\xda\x02\x1c\xc3\x60\xc4\xeb\xf1\x28\x08\x27\x43\x7f\xe8\x0f\x83\x91\xa1\xf5\x28\x9a\x86\x7e\x38\xe2\x75\xae\x47\x37\xd5\xea\x66\x9f\xed\x36\xcd\xc3\xfd\xfd\x79\xde\xfc\x5c\x65\xfb\x8b\x93\x25\xae\xae\xcf\xe6\xf2\xe7\xe1\x10\xc7\xd3\xed\x8d\x58\x7f\xdb\x2e\xae\x7e\xcc\xef\x37\x83\xbf\xc2\x46\x3d\xec\xb7\x3c\xb9\xb8\x4e\xaa\xcd\xe3\x1d\xfe\xb8\xfb\x72\x17\x3e\x2e\x9a\x20\xf9\x5e\xb3\x0f\xd1\xe6\xb3\x0c\x56\x51\x55\x90\x62\x71\x1a\xdf\x62\x2c\x82\x16\xb6\x2f\xd7\x49\x5f\xad\x3e\x09\xce\x50\x18\x6e\x0e\x97\x84\x1a\xa9\x0e\x29\x0c\x06\xaf\x24\x4b\x5c\x73\x6d\x5e\x88\x88\xa0\x85\x54\x4b\xac\xa5\xe6\xaf\xac\x6a\x72\xb0\x54\xf9\x27\x2b\xf9\x9a\x18\x2e\x85\x93\xb9\x06\x5e\x11\x2e\x7e\x4b\xa7\xae\xcf\x1e\x3c\x67\x4d\x1b\xe0\x11\x5c\x37\x15\x2a\x4e\xe1\xd3\x39\xc8\xdc\x31\xe8\x19\x57\x7e\x59\xb6\xcd\x8c\x83\xce\xea\xb4\xef\x18\x94\x5c\x1b\x6b\x29\x24\xc3\xb7\x64\xab\x95\xdc\x72\x27\x90\x0e\xfb\x59\x00\x7d\x78\xff\x81\x01\x51\x3c\x0c\xc3\x78\x18\xfa\xfe\x70\x1c\xbe\x66\x41\x10\x9e\x47\x5f\xa4\xbc\x9b\x73\x4e\x6f\xbe\xed\x56\xc5\xea\xf4\x3e\xd9\x7f\xa1\x0b\x39\xcf\x93\xe5\xcd\xfd\xe7\xcb\x7a\x97\x07\x6a\x12\xef\xe6\xfb\xf0\x61\x19\xd5\x67\x2c\x78\xcd\x85\xce\xc1\x34\x19\x86\x81\xff\x9e\x83\x9b\x87\xab\x93\xe9\x87\xc5\x47\xb5\xbd\x78\x38\x9d\xed\xd8\x46\x7e\xa5\x27\x27\xd5\xd9\xc3\xc7\x7a\x86\x87\xc3\xc3\xf8\xf6\x62\xba\xbe\x54\x51\xb1\xba\xfe\x3e\xe8\xea\x74\xd1\xb1\xbe\xaf\xa4\x2d\xf3\x31\x2c\xbb\xb9\x7e\x67\x2e\xc6\x9d\xf1\x9c\xd8\x12\x01\xc3\xba\x94\x07\x64\x70\x5b\x11\x65\xe0\xac\xa3\x9a\x86\x5c\x2a\x57\xd4\x35\xdf\xa2\x78\x51\xce\xb7\x74\x84\x77\xf9\xe8\xef\x67\x3e\x0b\x67\xe3\x78\x12\xe0\x24\x9a\x8e\xc3\x64\x36\x21\x49\x92\x4d\xc8\x6c\x46\xfc\x19\x63\x09\x9d\x44\x2c\x8a\x13\xf6\x07\xe6\xfa\xfb\x59\x92\xf8\xd4\x8f\x66\x2c\x0a\x82\x71\x1c\x91\xdc\x67\xf1\x94\xc6\x49\x92\x4c\xc2\x88\xcd\x68\x98\x93\x09\x4b\x90\xfe\x81\xe3\xfe\x7e\x92\x4f\xe3\x31\xcb\xc9\x6c\xea\x07\x21\x9b\xe4\x24\x8e\xe9\xd4\x8f\xb2\x8c\x84\x61\xe2\x67\x94\x21\x8e\xb3\x18\xd9\x5f\xa6\xe1\x08\x2c\x8d\x8e\x8d\x3c\xae\x11\x95\xad\x46\xce\xd7\x8d\x72\x1a\xda\xab\xc3\xba\xdd\x78\x2b\x5e\xa1\x6c\x0c\xec\x0a\x14\x20\x6b\x14\xdd\xe2\x13\x48\x9d\xa6\x25\xad\x05\xd0\x1e\xf4\x7f\x77\x26\x29\x0c\x22\x5f\x3b\x4f\x37\x0d\x36\xf8\xca\x85\xeb\x0c\xd1\x07\x41\x0b\x25\x85\x6c\xb4\x9d\x03\x8a\x5a\x73\xb1\xf6\x1e\xad\x41\x1b\x40\xbb\xb6\xb5\x6b\xa2\x68\xaa\x0c\x95\x9d\x24\x4b\x03\x54\x7a\x44\xa5\xd0\x76\x38\xbb\xa9\xda\xd9\x99\xc9\x10\x48\x59\x4a\x4a\x0c\x32\x20\x06\xb4\x21\xca\x34\xb5\x07\xd6\xfe\xae\x35\x4c\x21\x74\xe8\x97\x0a\x51\x43\x53\xc3\xd9\xe2\x2b\xd0\x03\x2d\x51\xb7\xa9\xb6\x0e\x80\x6b\xd8\x11\xee\xb6\xbd\x8d\x17\xb7\x28\x8c\x4d\xb5\x15\xdf\x11\xee\xb2\xbd\xba\x4d\x21\xb0\x89\x3e\x51\x59\xd7\x48\x79\xce\xe9\xcb\xa4\xbd\x9e\xc8\x6d\x6a\xb7\x58\xa2\xe5\xe8\xae\xe0\xb4\x78\x22\x39\x10\x4a\x65\x63\x57\x93\x84\x46\x63\xbf\x71\xa4\x2d\x42\xb7\x2a\x18\x70\xe1\xfe\xa4\x8d\x36\xb2\xea\x9c\x40\xce\x4b\xf4\xa0\xbf\x6e\x27\x2d\xcc\x35\xa9\x30\x85\x81\xbd\x68\x83\xa7\x1b\x66\x83\xe9\x81\x9f\xfc\xd2\x92\xdb\x8d\x68\x97\x14\xfc\x6f\x87\xa0\xf0\xb1\xe1\x0a\x61\xa7\x41\x2a\xe0\x35\xed\x0e\x9b\xbd\x63\xf6\x49\x89\xb1\x61\xbb\x92\xfc\xdf\x56\x57\x32\xfc\xba\x9c\xa7\xb0\xd3\xe9\x68\x64\x1b\x50\x16\x52\x9b\x74\x16\x8f\x93\xbe\x95\xee\xec\xae\x89\xcd\x84\x53\x1b\xec\x9a\xe8\x85\x7d\xa6\x10\xf8\xfd\xef\x8d\x72\xc9\x2b\x6e\x5a\xe5\xb9\x7d\xa6\x30\x9e\x04\x61\x34\x9d\xbe\xa0\xa8\x91\xae\x57\x2d\xb1\xc4\xaf\xbc\x8c\x22\x42\x13\x47\xd7\x3e\x03\xc6\xda\x33\x4d\x20\x2b\x25\xdd\x00\x11\xac\x4b\x04\x8c\xe2\xeb\x35\x2a\x64\x2d\xa1\x0d\xee\x4d\xdf\xe6\x96\xd4\x89\x6f\x59\xfd\x9e\x63\x85\x84\x81\x14\xe5\xc1\x0e\x4b\x4f\xf5\xfe\x5b\xa5\x0f\xe9\x17\xf4\x12\x09\x7b\x09\x1f\xc4\x1d\xfa\xb5\xed\xc3\xf3\xd8\x6b\x29\x4b\xa8\xc8\x1e\x14\x1a\xc5\xdb\x7b\xa1\x51\x30\x20\x2f\xd4\xe4\x16\x95\x07\x56\x71\xd9\xea\xa5\x10\x76\x35\xfd\x3d\x24\x17\x06\xd5\x96\x94\x0e\xf7\xd0\xd2\x9f\xd8\x00\x69\xa3\x94\xbb\x91\xcf\x2c\x0a\xa2\x21\x43\xb4\x47\xd4\x20\x35\xae\x4c\x3d\x80\xf5\x67\x77\x54\xd8\x65\x70\xce\xb5\xe3\x8a\x43\xd4\xb2\x7a\xc3\x35\x0d\x4c\x82\x90\x06\x74\x53\xd7\x52\x19\x30\x7b\x17\x11\xa9\xb9\xfd\x4c\xda\x2f\xa4\x2c\x4f\xa8\x5d\x0a\x17\xc2\x22\xb1\x14\x8c\x6a\xd0\xf3\xfe\x0d\x00\x00\xff\xff\x0a\x16\x18\x68\x1b\x0a\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x59\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xae\xd2\xe0\x92\xdc\x92\x5c\x8f\xf9\xf5\x1b\xf2\x83\x06\x7a\x60\x37\x36\x62\x76\x38\x29\x4a\x99\x5f\xbe\xbe\x4f\x4e\xde\xc1\x29\xd6\xa2\x6b\x02\x28\xdc\x60\x63\xdb\x35\x9a\x00\x01\x7d\x30\x18\x40\x2c\x85\x36\x3e\x80\xd3\xe6\x01\xab\xfd\x4c\xa2\x09\x4e\xd7\xdd\x12\x2f\x30\x6c\xad\x7b\x98\x83\xeb\xbc\xd7\xc2\xac\x74\xd3\xcc\x7a\x30\x6d\x10\xc2\x0a\x41\x8d\xb8\x66\xb0\xf4\x10\x56\x22\xc0\xc9\x23\x02\xac\x85\x36\x21\xe2\xcf\x26\x93\xf9\x0c\xe0\x1d\x9c\x5b\x29\x9a\x3e\x05\x6d\x96\x20\xad\x09\x4e\xc8\x00\x42\x29\x87\xde\xa3\x07\x83\xa8\x20\x58\xa8\x10\x3c\x06\xd8\xea\xb0\x02\x34\x1b\xd8\x08\xa7\x45\xd5\xa0\x3f\x9c\xc1\xe4\x1f\x21\x01\xb4\x9a\x03\x63\xac\x3f\x63\x58\xa1\xc3\x6e\x3d\x56\xf0\x8b\x9a\x43\xc1\x8a\xe1\xae\xb2\x36\xf8\xe0\x44\x7b\x89\xe8\xfc\xe0\x0b\xf0\x1e\x0e\x8e\x74\x9b\x1e\x25\x34\x3f\x24\x87\xe4\x30\x39\x0a\xb2\x3d\x62\x05\x25\xf4\x48\xb7\xb5\x3f\xba\x5a\xdf\x5c\xed\xaa\xed\x43\x77\x7f\x77\x77\x5a\x77\x7f\xdc\x54\xbb\xb3\xe3\x05\xde\x5c\x9c\x9c\xdb\x3f\xf6\xfb\x2c\x2b\x36\x57\x66\xf9\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\xcb\x26\xd8\xaf\x35\x3f\xbb\xe0\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xfa\xed\xb2\x4b\xf8\x6f\xad\xfa\x89\x3d\xfc\x6a\x93\x1b\xb6\x5e\x89\xd5\xe5\x87\xec\x1a\x33\x93\x0c\xb0\x53\xbb\x8e\xa7\x6e\x4d\x45\x68\x85\x26\xe8\xb0\xff\x28\x64\xb0\x6e\x3f\x87\x83\x83\x17\x37\x0b\x5c\x6a\x1f\x9e\x5d\x09\x23\x57\xd6\x2d\xb0\xb5\x5e\xbf\xf0\x6a\xc5\x3e\x52\xe5\x5f\x55\xa3\x97\x22\x68\x6b\xfa\xbb\x7e\x80\x9f\x85\x36\x7f\x4a\xa7\x71\xce\x33\x78\xca\x9a\x21\xc1\x77\x70\xd1\xad\xd1\x69\x09\xbf\x9c\x82\xad\x7b\x06\x3d\xe1\xca\x77\xcf\x61\x98\x59\x32\x7a\x7d\x98\x26\x06\x8d\xf6\x21\x7a\x1a\xab\xf0\x47\xb2\xb5\xce\x6e\x74\x7f\x61\x7b\xec\x27\x09\x4c\xe9\xfd\x17\x0c\x60\xd9\x21\xa5\xd9\x21\x25\xe4\x30\xa5\x2f\x59\x90\xd0\x53\xf6\xc9\xda\xdb\x73\xad\xe5\xd5\xd7\xed\xcd\xea\xe6\xc3\x1d\xdf\x7d\x92\x97\xf6\xbc\xe6\x8b\xab\xbb\x5f\x3f\xb6\xdb\x3a\x71\x79\xb6\x3d\xdf\xd1\xfb\x05\x6b\x4f\x54\xf2\x92\x0b\x63\x80\x82\x1f\xd2\x84\xbc\x16\xe0\xea\xfe\xf3\x71\xf1\xd3\xe5\xcf\x6e\x73\x76\xff\xa1\xdc\xaa\x07\xfb\x45\x1e\x1f\xaf\x4f\xee\x7f\x6e\x4b\xdc\xef\xef\xd3\xeb\xb3\x62\xf9\xd1\xb1\xd5\xcd\xc5\x6f\x07\x63\x9f\xce\x46\xd6\x4f\x9d\x8c\x6d\x7e\x0f\x8b\x51\xd7\xaf\xe8\x22\x1d\x9d\xcf\x45\x6c\x11\x28\x6c\x1b\xbb\x47\x05\xd7\x6b\xe1\x02\x9c\x8c\x54\xf3\x50\x5b\xd7\x37\x75\xa9\x37\x68\x9e\xb5\xf3\x47\x3a\xc2\xab\x7c\x24\xbb\x92\x28\x5a\xa6\x59\x9e\x60\xce\x8a\x94\xf2\x32\x17\x9c\x57\xb9\x28\x4b\x41\x4a\xa5\xb8\xcc\x99\x62\x19\x57\x6f\x30\x97\xec\x4a\xce\x89\x24\xac\x54\x2c\x49\xd2\x8c\x89\x9a\xa8\xac\x90\x19\xe7\x3c\xa7\x4c\x95\x92\xd6\x22\x57\x1c\xe5\x1b\x1c\x27\xbb\xbc\x2e\xb2\x54\xd5\xa2\x2c\x48\x42\x55\x5e\x8b\x2c\x93\x05\x61\x55\x25\x28\xe5\xa4\x92\x0a\x31\xad\x32\x54\x6f\xa9\x81\xec\x78\x99\xd0\x82\xf0\x3c\xaf\x32\x8a\x4c\x8a\x3c\x41\x42\x19\xa2\xa2\xaa\x60\xb5\x28\x6b\x21\x59\xc5\xd3\xaa\xd7\x4d\x85\xce\x88\x66\x85\x7a\xb9\x0a\xfe\x7f\x13\x05\xfd\x3f\x8a\xe2\x2f\x96\xc4\xdf\x24\x88\x4f\x76\x23\xcc\xab\x72\xa0\x7f\x81\x1e\xde\x90\x43\x91\x55\x8c\xd6\xb9\x60\x75\x4a\xd2\x22\xa9\x13\xca\x58\x4a\xd2\x84\xe7\x44\x16\xb2\x42\x92\xd7\xb9\xca\x4b\xf9\xa6\x1c\xb2\x54\x20\xcb\x59\x4d\x4a\x5e\x8b\x9a\xaa\x8a\x57\x85\x48\x79\x9e\xe4\x92\x54\x65\x81\xb2\x16\x24\xcf\x94\x7a\x53\x0e\x69\x9a\xd6\x3c\x2d\x91\x91\x3c\x4d\x29\xe6\x5c\xca\x3a\x67\x79\xca\x39\x66\xb4\x4e\x38\x29\xab\xb2\xa0\x9c\xbc\x2d\x07\xc1\x14\xab\xd2\xac\x4e\x29\x25\x09\xa7\x24\x51\xb9\x54\xa9\xa4\x95\xa4\x49\xce\x79\x96\x16\x4c\x95\x04\xf9\xc1\x6c\xf6\x0e\x22\xd5\xde\x07\xfb\xbe\x45\x74\xb1\x6d\xb5\x5e\x76\xae\xc7\xf2\xb3\x96\xb6\xc3\xaa\x70\xa3\xd7\x68\xbb\x00\xdb\x15\x1a\xb0\x2d\x9a\x71\x63\x30\x28\x7b\xcb\x48\xec\x08\xe0\x67\x30\xfd\x3c\xba\xcc\xe1\x80\x11\xdf\x47\xba\xea\xb0\xc3\x17\x21\xfa\x11\x0a\xbf\x37\x72\xe5\xac\xb1\x9d\x8f\x5a\x91\xe8\xbd\x36\xcb\xd9\xb7\xe8\x30\x24\x30\xec\x3b\xbe\x9f\xb6\xe9\xd6\x15\xba\xa8\xb6\x48\x18\x74\xfe\x48\x5a\xe3\xa3\x80\x47\xe5\x6d\xa3\xae\x2a\x04\xd1\x34\x56\x8a\x80\x0a\x44\x00\x1f\x84\x0b\x5d\x3b\x83\xe8\x7f\x3b\x38\xce\x81\xf6\xe8\x1f\x1d\xa2\x87\xae\x85\x93\xcb\x2f\x20\xf7\xb2\x41\x3f\x94\x3a\x04\x00\xed\x61\x2b\x74\xbf\x26\xc5\x7c\x71\x83\x26\xc4\x52\x87\xeb\x5b\xa1\xfb\x6a\x3f\x5f\xcf\x21\x89\x85\x3e\x52\xde\xb7\x28\x75\xad\xe5\xf3\xa2\x67\x13\xe5\x87\xd2\xae\xb1\xc1\x48\xe6\xed\x4a\xcb\xd5\xa3\x1c\x40\x48\x69\xbb\xf8\x4d\xb7\xd0\x79\x9c\x5e\x25\x1b\x9b\x30\x3e\x27\x0a\xb4\xe9\x7f\x94\x9d\x0f\x76\x3d\x06\x81\x5a\x37\x38\x83\x69\x2d\x3c\x1e\x60\x2e\xc4\x1a\xe7\x70\x10\x57\xc1\x83\xc7\xe5\x2f\x26\x33\x01\x3f\xc6\x95\x8d\x8e\xab\x44\x7c\xc8\xe0\x1f\x5b\x04\x87\xdf\x3a\xed\x10\xb6\x1e\xac\x03\xdd\xca\x71\x23\x8c\x0b\x60\x3c\x4a\x11\x62\xda\x7d\x4b\xfe\x19\xbb\x6b\x15\x7e\x59\x9c\xcf\x61\xeb\xe7\x47\x47\x71\x00\xcd\xca\xfa\x30\x2f\xb3\x94\x4f\xa3\xec\xf7\xd5\xa5\x88\x95\x68\x19\x93\x5d\x0a\x7f\x19\x8f\x73\x48\xc8\xf4\xf7\x83\x71\xa3\xd7\x3a\x0c\xc6\xe7\xf1\x38\x87\x34\x4f\x28\x2b\x8a\x67\x14\x0d\xb6\x9f\xd5\x40\x2c\xf3\xbd\xae\xe0\x84\xf1\xa2\xa7\xeb\x54\x81\x52\xc3\x7e\x2b\xa0\x6a\xac\x7c\x00\x61\xd4\x58\x08\x04\xa7\x97\x4b\x74\xa8\x06\x42\x07\xdc\x85\x69\xcc\x03\xa9\x39\x89\xac\x7e\x2d\xb0\x43\xa1\xc0\x9a\x66\x1f\xc5\x32\x51\x7d\x5a\xf2\xa7\x94\xbe\x43\x2f\x50\xa8\xe7\xf0\x49\x36\xa2\x5f\xc4\x39\x3c\xcd\xbd\xb5\xb6\x81\xb5\xd8\x81\xc3\xe0\xf4\xf0\x4d\xf1\x68\x14\x88\x67\x66\x76\x83\x6e\x06\xd1\x70\x31\xd8\xcd\x81\x8e\x3d\xfd\x73\x48\x6d\x02\xba\x8d\x68\x7a\xdc\xfd\x40\x7f\x11\x13\x94\x9d\x73\xfd\x72\xf9\xc4\x63\x25\x3c\x54\x88\x71\xfb\x0c\x28\x43\xdf\xa6\x09\x20\xc6\x8b\xaf\x19\x1d\x2b\x38\xd5\xbe\xe7\x4a\x8f\xe8\xed\xfa\x07\xae\x79\x50\x16\x8c\x0d\xe0\xbb\xb6\xb5\x2e\x40\xd8\xf5\x19\x89\x56\xc7\xff\x2f\x76\x97\xd6\x36\xc7\x32\x3e\x0a\x67\x26\x22\xa9\x39\x04\xd7\xe1\x6c\xf6\xef\x00\x00\x00\xff\xff\x88\x91\x60\xe6\x54\x0d\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 2587, mode: os.FileMode(420), modTime: time.Unix(1540892585, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3412, mode: os.FileMode(420), modTime: time.Unix(1542796688, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + From 13ca6c3b2a4fc8773bb20d8282c7e8ce431ebf7f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 21 Nov 2018 20:00:19 +0100 Subject: [PATCH 039/220] Remove usage of identity.IDService (#473) * Remove usage of identity.IDService * Fix test * Fix test --- anchors/anchor_repository_integration_test.go | 2 +- api/server_test.go | 2 + cmd/create_config.go | 17 ++--- cmd/manage_identities.go | 10 ++- documents/invoice/bootstrapper.go | 7 +- documents/invoice/model_test.go | 1 + documents/invoice/service_test.go | 68 ++++++++----------- documents/purchaseorder/bootstrapper.go | 7 +- documents/purchaseorder/model_test.go | 1 + documents/purchaseorder/service_test.go | 43 ++++-------- identity/bootstrapper.go | 20 +++--- .../ethereum_identity_integration_test.go | 6 +- identity/identity.go | 3 - nft/bootstrapper.go | 7 +- nft/payment_obligation_integration_test.go | 5 +- p2p/handler_integration_test.go | 6 +- testingutils/identity/identity.go | 8 +-- 17 files changed, 107 insertions(+), 106 deletions(-) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 8acf2e871..db9b29c23 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -25,7 +25,7 @@ var ( func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - identityService = identity.IDService + identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/api/server_test.go b/api/server_test.go index 256ff734f..b1eeb4c01 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -22,6 +22,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" + "github.com/centrifuge/go-centrifuge/identity" ) var ctx = map[string]interface{}{} @@ -38,6 +39,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &storage.Bootstrapper{}, anchors.Bootstrapper{}, + &identity.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, diff --git a/cmd/create_config.go b/cmd/create_config.go index 905f52ee1..1426501ec 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -20,9 +20,9 @@ var p2pPort int64 var bootstraps []string var txPoolAccess bool -func createIdentity() (identity.CentID, error) { +func createIdentity(idService identity.Service) (identity.CentID, error) { centrifugeId := identity.RandomCentID() - _, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) + _, confirmations, err := idService.CreateIdentity(centrifugeId) if err != nil { return [identity.CentIDLength]byte{}, err } @@ -39,16 +39,16 @@ func generateKeys(config config.Config) { keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } -func addKeys() error { - err := identity.IDService.AddKeyFromConfig(identity.KeyPurposeP2P) +func addKeys(idService identity.Service) error { + err := idService.AddKeyFromConfig(identity.KeyPurposeP2P) if err != nil { panic(err) } - err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeSigning) + err = idService.AddKeyFromConfig(identity.KeyPurposeSigning) if err != nil { panic(err) } - err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = idService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) if err != nil { panic(err) } @@ -90,7 +90,8 @@ func init() { cfg := ctx[config.BootstrappedConfig].(*config.Configuration) generateKeys(cfg) - id, err := createIdentity() + idService := ctx[identity.BootstrappedIDService].(identity.Service) + id, err := createIdentity(idService) if err != nil { panic(err) } @@ -104,7 +105,7 @@ func init() { log.Infof("Identity created [%s] [%x]", id.String(), id) - err = addKeys() + err = addKeys(idService) if err != nil { log.Fatalf("error: %v", err) } diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 0f7f26741..fd9436874 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -17,7 +17,7 @@ var createIdentityCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file cfgFile = ensureConfigFile() - baseBootstrap(cfgFile) + ctx := baseBootstrap(cfgFile) var centrifugeId identity.CentID var err error if centrifugeIdString == "" { @@ -28,7 +28,9 @@ var createIdentityCmd = &cobra.Command{ panic(err) } } - _, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) + + idService := ctx[identity.BootstrappedIDService].(identity.Service) + _, confirmations, err := idService.CreateIdentity(centrifugeId) if err != nil { panic(err) } @@ -53,6 +55,7 @@ var addKeyCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file cfgFile = ensureConfigFile() + ctx := baseBootstrap(cfgFile) var purposeInt int switch purpose { @@ -66,7 +69,8 @@ var addKeyCmd = &cobra.Command{ panic("Option not supported") } - err := identity.IDService.AddKeyFromConfig(purposeInt) + idService := ctx[identity.BootstrappedIDService].(identity.Service) + err := idService.AddKeyFromConfig(purposeInt) if err != nil { panic(err) } diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index de83bc8c0..c40e0c38f 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -43,8 +43,13 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("anchor repository not initialised") } + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return fmt.Errorf("identity service not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchorRepo, cfg), anchorRepo, identity.IDService) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 802eff603..5e35501f4 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -44,6 +44,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index ee17abd81..ad8d44947 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -49,10 +49,10 @@ func TestDefaultService(t *testing.T) { assert.NotNil(t, srv, "must be non-nil") } -func getServiceWithMockedLayers() Service { - idService := &testingcommons.MockIDService{} +func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { + idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return idService, DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) } func createMockDocument() (*Invoice, error) { @@ -92,7 +92,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_DeriveFromPayload(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() payload := testingdocuments.CreateInvoicePayload() var model documents.Model var err error @@ -116,7 +116,7 @@ func TestService_DeriveFromPayload(t *testing.T) { } func TestService_GetLastVersion(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) @@ -148,7 +148,7 @@ func TestService_GetLastVersion(t *testing.T) { } func TestService_GetVersion_invalid_version(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() currentVersion := utils.RandomSlice(32) inv := &Invoice{ GrossAmount: 60, @@ -166,7 +166,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { } func TestService_GetVersion(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) inv := &Invoice{ @@ -190,7 +190,7 @@ func TestService_GetVersion(t *testing.T) { } func TestService_Exists(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) inv := &Invoice{ GrossAmount: 60, @@ -254,7 +254,7 @@ func TestService_Create(t *testing.T) { } func TestService_DeriveInvoiceData(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() // some random model _, err := invSrv.DeriveInvoiceData(&mockModel{}) @@ -291,7 +291,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { } // Functions returns service mocks -func mockSignatureCheck(i *Invoice, invSrv Service) identity.Service { +func mockSignatureCheck(i *Invoice, idService testingcommons.MockIDService, invSrv Service) testingcommons.MockIDService { idkey := &identity.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, @@ -301,25 +301,18 @@ func mockSignatureCheck(i *Invoice, invSrv Service) identity.Service { docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) mockRepo := invSrv.(service).anchorRepository.(*mockAnchorRepo) mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - srv := &testingcommons.MockIDService{} id := &testingcommons.MockID{} centID, _ := identity.ToCentID(centIDBytes) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() + idService.On("LookupIdentityForID", centID).Return(id, nil).Once() id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() - return srv -} - -func setIdentityService(idService identity.Service) { - identity.IDService = idService + return idService } func TestService_CreateProofs(t *testing.T) { - defer setIdentityService(identity.IDService) - invSrv := getServiceWithMockedLayers() + idService, invSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, invSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, invSrv) proof, err := invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) @@ -329,46 +322,40 @@ func TestService_CreateProofs(t *testing.T) { } func TestService_CreateProofsValidationFails(t *testing.T) { - defer setIdentityService(identity.IDService) - invSrv := getServiceWithMockedLayers() + idService, invSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil err = getRepository().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) - idService := mockSignatureCheck(i, invSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } func TestService_CreateProofsInvalidField(t *testing.T) { - defer setIdentityService(identity.IDService) - invSrv := getServiceWithMockedLayers() + idService, invSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, invSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.Equal(t, "createProofs error No such field: invalid_field in obj", err.Error()) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { - invService := getServiceWithMockedLayers() + _, invService := getServiceWithMockedLayers() _, err := invService.CreateProofs(utils.RandomSlice(32), []string{"invoice_number"}) assert.Error(t, err) assert.Equal(t, "document not found: leveldb: not found", err.Error()) } func TestService_CreateProofsForVersion(t *testing.T) { - defer setIdentityService(identity.IDService) - invSrv := getServiceWithMockedLayers() + idService, invSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, invSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, invSrv) olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) @@ -382,7 +369,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() assert.Nil(t, err) _, err = invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice_number"}) assert.Error(t, err) @@ -390,12 +377,10 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { - defer setIdentityService(identity.IDService) - invSrv := getServiceWithMockedLayers() + idService, invSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, true) assert.Nil(t, err) - idService := mockSignatureCheck(i, invSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, invSrv) i.CoreDocument.SigningRoot = nil ctxh, err := header.NewContextHeader(context.Background(), cfg) signature, err := invSrv.RequestDocumentSignature(ctxh, i) @@ -499,7 +484,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { } func TestService_DeriveFromUpdatePayload(t *testing.T) { - invSrv := getServiceWithMockedLayers() + _, invSrv := getServiceWithMockedLayers() // nil payload doc, err := invSrv.DeriveFromUpdatePayload(nil, nil) assert.Error(t, err) @@ -659,7 +644,8 @@ func TestService_Update(t *testing.T) { } func TestService_calculateDataRoot(t *testing.T) { - invSrv := getServiceWithMockedLayers().(service) + _, srv := getServiceWithMockedLayers() + invSrv := srv.(service) ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index b89e84247..bbc8ae30e 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -42,8 +42,13 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("anchor repository not initialised") } + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return fmt.Errorf("identity service not initialised") + } + // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(identity.IDService, p2pClient, anchorRepo, cfg), anchorRepo, identity.IDService) + srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 136599e5e..27e24bdc0 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -44,6 +44,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index d6d9828fc..aefc00bb5 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -41,10 +41,10 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D return docRoot, args.Error(1) } -func getServiceWithMockedLayers() Service { +func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return idService, DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func TestService_Update(t *testing.T) { @@ -305,10 +305,6 @@ func TestService_Create(t *testing.T) { assert.True(t, getRepository().Exists(newCD.CurrentVersion)) } -func setIdentityService(idService identity.Service) { - identity.IDService = idService -} - func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, error) { i := &PurchaseOrder{ PoNumber: "test_po", @@ -367,7 +363,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er } // Functions returns service mocks -func mockSignatureCheck(i *PurchaseOrder, poSrv Service) identity.Service { +func mockSignatureCheck(i *PurchaseOrder, srv *testingcommons.MockIDService, poSrv Service) *testingcommons.MockIDService { idkey := &identity.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, @@ -377,7 +373,6 @@ func mockSignatureCheck(i *PurchaseOrder, poSrv Service) identity.Service { docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) mockRepo := poSrv.(service).anchorRepository.(*mockAnchorRepo) mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - srv := &testingcommons.MockIDService{} id := &testingcommons.MockID{} centID, _ := identity.ToCentID(centIDBytes) srv.On("LookupIdentityForID", centID).Return(id, nil).Once() @@ -386,12 +381,10 @@ func mockSignatureCheck(i *PurchaseOrder, poSrv Service) identity.Service { } func TestService_CreateProofs(t *testing.T) { - poSrv := getServiceWithMockedLayers() - defer setIdentityService(identity.IDService) + idService, poSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, poSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, poSrv) proof, err := poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) @@ -401,34 +394,30 @@ func TestService_CreateProofs(t *testing.T) { } func TestService_CreateProofsValidationFails(t *testing.T) { - defer setIdentityService(identity.IDService) - poSrv := getServiceWithMockedLayers() + idService, poSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil err = getRepository().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) - idService := mockSignatureCheck(i, poSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } func TestService_CreateProofsInvalidField(t *testing.T) { - defer setIdentityService(identity.IDService) - poSrv := getServiceWithMockedLayers() + idService, poSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, poSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.Equal(t, "createProofs error No such field: invalid_field in obj", err.Error()) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { - poSrv := getServiceWithMockedLayers() + _, poSrv := getServiceWithMockedLayers() _, err := poSrv.CreateProofs(utils.RandomSlice(32), []string{"po_number"}) assert.Error(t, err) assert.Equal(t, "document not found: leveldb: not found", err.Error()) @@ -471,12 +460,10 @@ func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseO } func TestService_CreateProofsForVersion(t *testing.T) { - defer setIdentityService(identity.IDService) - poSrv := getServiceWithMockedLayers() + idService, poSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - idService := mockSignatureCheck(i, poSrv) - setIdentityService(idService) + idService = mockSignatureCheck(i, idService, poSrv) olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) @@ -490,7 +477,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) - poSrv := getServiceWithMockedLayers() + _, poSrv := getServiceWithMockedLayers() assert.Nil(t, err) _, err = poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po_number"}) assert.Error(t, err) @@ -499,7 +486,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model - poSrv := getServiceWithMockedLayers() + _, poSrv := getServiceWithMockedLayers() ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -658,7 +645,7 @@ func TestService_GetVersion(t *testing.T) { } func TestService_Exists(t *testing.T) { - poSrv := getServiceWithMockedLayers() + _, poSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) po := &PurchaseOrder{ OrderAmount: 42, diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 70e7234fd..1d006032d 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -10,6 +10,9 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// BootstrappedIDService is used as a key to map the configured ID Service through context. +const BootstrappedIDService string = "BootstrappedIDService" + type Bootstrapper struct { } @@ -24,18 +27,19 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } + gethClient := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) - idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress("identityFactory")) + idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress("identityFactory"), gethClient) if err != nil { return err } - registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress("identityRegistry")) + registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress("identityRegistry"), gethClient) if err != nil { return err } - IDService = NewEthereumIdentityService(cfg, idFactory, registryContract, ethereum.GetClient, + context[BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, ethereum.GetClient, func(address common.Address, backend bind.ContractBackend) (contract, error) { return NewEthereumIdentityContract(address, backend) }) @@ -57,12 +61,10 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return nil } -func getIdentityFactoryContract(factoryAddress common.Address) (identityFactoryContract *EthereumIdentityFactoryContract, err error) { - client := ethereum.GetClient() - return NewEthereumIdentityFactoryContract(factoryAddress, client.GetEthClient()) +func getIdentityFactoryContract(factoryAddress common.Address, ethClient ethereum.Client) (identityFactoryContract *EthereumIdentityFactoryContract, err error) { + return NewEthereumIdentityFactoryContract(factoryAddress, ethClient.GetEthClient()) } -func getIdentityRegistryContract(registryAddress common.Address) (identityRegistryContract *EthereumIdentityRegistryContract, err error) { - client := ethereum.GetClient() - return NewEthereumIdentityRegistryContract(registryAddress, client.GetEthClient()) +func getIdentityRegistryContract(registryAddress common.Address, ethClient ethereum.Client) (identityRegistryContract *EthereumIdentityRegistryContract, err error) { + return NewEthereumIdentityRegistryContract(registryAddress, ethClient.GetEthClient()) } diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 3918845de..7f1240688 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -28,7 +28,7 @@ func TestMain(m *testing.M) { cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - identityService = identity.IDService + identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -92,7 +92,7 @@ func TestAddKeyFromConfig(t *testing.T) { assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - err = identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = identityService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") cfg.Set("identityId", defaultCentrifugeId) @@ -105,7 +105,7 @@ func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - err := identity.IDService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err := identityService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) assert.NotNil(t, err, "should error out") cfg.Set("identityId", defaultCentrifugeId) diff --git a/identity/identity.go b/identity/identity.go index 9095633fb..2f46b02a5 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -32,9 +32,6 @@ const ( KeyPurposeEthMsgAuth = 3 ) -// IDService is a default implementation of the Service -var IDService Service - // CentID represents a CentIDLength identity of an entity type CentID [CentIDLength]byte diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index f4ac5c9c9..a7c0d94e7 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -30,6 +30,11 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("service registry not initialised") } - setPaymentObligation(NewEthereumPaymentObligation(registry, identity.IDService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return fmt.Errorf("identity service not initialised") + } + + setPaymentObligation(NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext)) } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index f9f0b43b8..de2f9e8a3 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -20,15 +20,18 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" + "github.com/centrifuge/go-centrifuge/identity" ) var registry *documents.ServiceRegistry var cfg *config.Configuration +var idService identity.Service func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[config.BootstrappedConfig].(*config.Configuration) prevSignPubkey := cfg.Get("keys.signing.publicKey") prevSignPrivkey := cfg.Get("keys.signing.privateKey") @@ -50,7 +53,7 @@ func TestMain(m *testing.M) { func TestPaymentObligationService_mint(t *testing.T) { // create identity log.Debug("Create Identity for Testing") - testingidentity.CreateIdentityWithKeys(cfg) + testingidentity.CreateIdentityWithKeys(cfg, idService) // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index b400a241e..84e6222bd 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -33,6 +33,7 @@ var ( handler p2ppb.P2PServiceServer anchorRepo anchors.AnchorRepository cfg *config.Configuration + idService identity.Service ) func TestMain(m *testing.M) { @@ -40,13 +41,14 @@ func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[config.BootstrappedConfig].(*config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") handler = p2p.GRPCHandler(cfg, registry) - testingidentity.CreateIdentityWithKeys(cfg) + testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -180,7 +182,7 @@ func createIdentity(t *testing.T) identity.CentID { // Create Identity centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := identity.IDService.CreateIdentity(centrifugeId) + id, confirmations, err := idService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 33a3e49da..42b5a9d26 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -8,15 +8,15 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -func CreateIdentityWithKeys(cfg config.Config) identity.CentID { +func CreateIdentityWithKeys(cfg config.Config, idService identity.Service) identity.CentID { idConfig, _ := identity.GetIdentityConfig(cfg) // only create identity if it doesn't exist - id, err := identity.IDService.LookupIdentityForID(idConfig.ID) + id, err := idService.LookupIdentityForID(idConfig.ID) if err != nil { - _, confirmations, _ := identity.IDService.CreateIdentity(idConfig.ID) + _, confirmations, _ := idService.CreateIdentity(idConfig.ID) <-confirmations // LookupIdentityForId - id, _ = identity.IDService.LookupIdentityForID(idConfig.ID) + id, _ = idService.LookupIdentityForID(idConfig.ID) } // only add key if it doesn't exist From 71fbdada7e0c0bada68dcb2f5a87a965f203b37b Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 22 Nov 2018 15:00:09 +0100 Subject: [PATCH 040/220] Pprof/endpoint (#476) * add pprof port to config * add pprof end points * review changes --- api/server.go | 7 +++++++ build/configs/default_config.yaml | 4 ++++ config/configuration.go | 12 +++++++++++- config/configuration_test.go | 3 ++- resources/data.go | 4 ++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/api/server.go b/api/server.go index 69fb9bced..337af15cd 100644 --- a/api/server.go +++ b/api/server.go @@ -10,6 +10,7 @@ import ( "errors" "net" "net/http" + _ "net/http/pprof" "strings" "sync" "time" @@ -29,6 +30,7 @@ type Config interface { GetServerAddress() string GetServerPort() int GetNetworkString() string + IsPProfEnabled() bool } // apiServer is an implementation of node.Server interface for serving HTTP based Centrifuge API @@ -81,6 +83,11 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha return } + if c.config.IsPProfEnabled() { + log.Info("added pprof endpoints to the server") + mux.Handle("/debug/", http.DefaultServeMux) + } + mux.Handle("/", gwmux) srv := &http.Server{ Addr: addr, diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index e2a3e7329..c28a87c48 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -81,3 +81,7 @@ ethereum: # Disable when some ethereum clients do not support txpool api txPoolAccessEnabled: true +# any debugging config will go here +debug: + # pprof for debugging + pprof: false diff --git a/config/configuration.go b/config/configuration.go index 86fd3c1f1..e1dd0ef1f 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -107,6 +107,11 @@ func (c *Configuration) GetInt(key string) int { return cast.ToInt(c.get(key)) } +// GetBool returns value bool associated with key +func (c *Configuration) GetBool(key string) bool { + return cast.ToBool(c.get(key)) +} + // GetDuration returns value duration associated with key func (c *Configuration) GetDuration(key string) time.Duration { return cast.ToDuration(c.get(key)) @@ -223,7 +228,7 @@ func (c *Configuration) GetEthereumAccount(accountName string) (account *Account // Important flag for concurrency handling. Disable if Ethereum client doesn't support txpool API (INFURA) func (c *Configuration) GetTxPoolAccessEnabled() bool { - return cast.ToBool(c.get("ethereum.txPoolAccessEnabled")) + return c.GetBool("ethereum.txPoolAccessEnabled") } //////////////////////////////////////////////////////////////////////////////// @@ -274,6 +279,11 @@ func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { return c.GetString("keys.ethauth.publicKey"), c.GetString("keys.ethauth.privateKey") } +// IsPProfEnabled returns true if the pprof is enabled +func (c *Configuration) IsPProfEnabled() bool { + return c.GetBool("debug.pprof") +} + // Configuration Implementation func NewConfiguration(configFile string) *Configuration { cfg := &Configuration{configFile: configFile, mu: sync.RWMutex{}} diff --git a/config/configuration_test.go b/config/configuration_test.go index 30aa320cd..8f597b8c4 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -38,6 +38,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { assert.Equal(t, data["p2pPort"].(int64), v.GetInt64("p2p.port"), "p2p port match") _, err = os.Stat(targetDir + "/config.yaml") assert.Nil(t, err, "must be nil, config file should be created") - + c := NewConfiguration(v.ConfigFileUsed()) + assert.False(t, c.IsPProfEnabled(), "pprof is disabled by default") os.Remove(targetDir) } diff --git a/resources/data.go b/resources/data.go index fc45e9474..5a11a42ba 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x59\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xae\xd2\xe0\x92\xdc\x92\x5c\x8f\xf9\xf5\x1b\xf2\x83\x06\x7a\x60\x37\x36\x62\x76\x38\x29\x4a\x99\x5f\xbe\xbe\x4f\x4e\xde\xc1\x29\xd6\xa2\x6b\x02\x28\xdc\x60\x63\xdb\x35\x9a\x00\x01\x7d\x30\x18\x40\x2c\x85\x36\x3e\x80\xd3\xe6\x01\xab\xfd\x4c\xa2\x09\x4e\xd7\xdd\x12\x2f\x30\x6c\xad\x7b\x98\x83\xeb\xbc\xd7\xc2\xac\x74\xd3\xcc\x7a\x30\x6d\x10\xc2\x0a\x41\x8d\xb8\x66\xb0\xf4\x10\x56\x22\xc0\xc9\x23\x02\xac\x85\x36\x21\xe2\xcf\x26\x93\xf9\x0c\xe0\x1d\x9c\x5b\x29\x9a\x3e\x05\x6d\x96\x20\xad\x09\x4e\xc8\x00\x42\x29\x87\xde\xa3\x07\x83\xa8\x20\x58\xa8\x10\x3c\x06\xd8\xea\xb0\x02\x34\x1b\xd8\x08\xa7\x45\xd5\xa0\x3f\x9c\xc1\xe4\x1f\x21\x01\xb4\x9a\x03\x63\xac\x3f\x63\x58\xa1\xc3\x6e\x3d\x56\xf0\x8b\x9a\x43\xc1\x8a\xe1\xae\xb2\x36\xf8\xe0\x44\x7b\x89\xe8\xfc\xe0\x0b\xf0\x1e\x0e\x8e\x74\x9b\x1e\x25\x34\x3f\x24\x87\xe4\x30\x39\x0a\xb2\x3d\x62\x05\x25\xf4\x48\xb7\xb5\x3f\xba\x5a\xdf\x5c\xed\xaa\xed\x43\x77\x7f\x77\x77\x5a\x77\x7f\xdc\x54\xbb\xb3\xe3\x05\xde\x5c\x9c\x9c\xdb\x3f\xf6\xfb\x2c\x2b\x36\x57\x66\xf9\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\xcb\x26\xd8\xaf\x35\x3f\xbb\xe0\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xfa\xed\xb2\x4b\xf8\x6f\xad\xfa\x89\x3d\xfc\x6a\x93\x1b\xb6\x5e\x89\xd5\xe5\x87\xec\x1a\x33\x93\x0c\xb0\x53\xbb\x8e\xa7\x6e\x4d\x45\x68\x85\x26\xe8\xb0\xff\x28\x64\xb0\x6e\x3f\x87\x83\x83\x17\x37\x0b\x5c\x6a\x1f\x9e\x5d\x09\x23\x57\xd6\x2d\xb0\xb5\x5e\xbf\xf0\x6a\xc5\x3e\x52\xe5\x5f\x55\xa3\x97\x22\x68\x6b\xfa\xbb\x7e\x80\x9f\x85\x36\x7f\x4a\xa7\x71\xce\x33\x78\xca\x9a\x21\xc1\x77\x70\xd1\xad\xd1\x69\x09\xbf\x9c\x82\xad\x7b\x06\x3d\xe1\xca\x77\xcf\x61\x98\x59\x32\x7a\x7d\x98\x26\x06\x8d\xf6\x21\x7a\x1a\xab\xf0\x47\xb2\xb5\xce\x6e\x74\x7f\x61\x7b\xec\x27\x09\x4c\xe9\xfd\x17\x0c\x60\xd9\x21\xa5\xd9\x21\x25\xe4\x30\xa5\x2f\x59\x90\xd0\x53\xf6\xc9\xda\xdb\x73\xad\xe5\xd5\xd7\xed\xcd\xea\xe6\xc3\x1d\xdf\x7d\x92\x97\xf6\xbc\xe6\x8b\xab\xbb\x5f\x3f\xb6\xdb\x3a\x71\x79\xb6\x3d\xdf\xd1\xfb\x05\x6b\x4f\x54\xf2\x92\x0b\x63\x80\x82\x1f\xd2\x84\xbc\x16\xe0\xea\xfe\xf3\x71\xf1\xd3\xe5\xcf\x6e\x73\x76\xff\xa1\xdc\xaa\x07\xfb\x45\x1e\x1f\xaf\x4f\xee\x7f\x6e\x4b\xdc\xef\xef\xd3\xeb\xb3\x62\xf9\xd1\xb1\xd5\xcd\xc5\x6f\x07\x63\x9f\xce\x46\xd6\x4f\x9d\x8c\x6d\x7e\x0f\x8b\x51\xd7\xaf\xe8\x22\x1d\x9d\xcf\x45\x6c\x11\x28\x6c\x1b\xbb\x47\x05\xd7\x6b\xe1\x02\x9c\x8c\x54\xf3\x50\x5b\xd7\x37\x75\xa9\x37\x68\x9e\xb5\xf3\x47\x3a\xc2\xab\x7c\x24\xbb\x92\x28\x5a\xa6\x59\x9e\x60\xce\x8a\x94\xf2\x32\x17\x9c\x57\xb9\x28\x4b\x41\x4a\xa5\xb8\xcc\x99\x62\x19\x57\x6f\x30\x97\xec\x4a\xce\x89\x24\xac\x54\x2c\x49\xd2\x8c\x89\x9a\xa8\xac\x90\x19\xe7\x3c\xa7\x4c\x95\x92\xd6\x22\x57\x1c\xe5\x1b\x1c\x27\xbb\xbc\x2e\xb2\x54\xd5\xa2\x2c\x48\x42\x55\x5e\x8b\x2c\x93\x05\x61\x55\x25\x28\xe5\xa4\x92\x0a\x31\xad\x32\x54\x6f\xa9\x81\xec\x78\x99\xd0\x82\xf0\x3c\xaf\x32\x8a\x4c\x8a\x3c\x41\x42\x19\xa2\xa2\xaa\x60\xb5\x28\x6b\x21\x59\xc5\xd3\xaa\xd7\x4d\x85\xce\x88\x66\x85\x7a\xb9\x0a\xfe\x7f\x13\x05\xfd\x3f\x8a\xe2\x2f\x96\xc4\xdf\x24\x88\x4f\x76\x23\xcc\xab\x72\xa0\x7f\x81\x1e\xde\x90\x43\x91\x55\x8c\xd6\xb9\x60\x75\x4a\xd2\x22\xa9\x13\xca\x58\x4a\xd2\x84\xe7\x44\x16\xb2\x42\x92\xd7\xb9\xca\x4b\xf9\xa6\x1c\xb2\x54\x20\xcb\x59\x4d\x4a\x5e\x8b\x9a\xaa\x8a\x57\x85\x48\x79\x9e\xe4\x92\x54\x65\x81\xb2\x16\x24\xcf\x94\x7a\x53\x0e\x69\x9a\xd6\x3c\x2d\x91\x91\x3c\x4d\x29\xe6\x5c\xca\x3a\x67\x79\xca\x39\x66\xb4\x4e\x38\x29\xab\xb2\xa0\x9c\xbc\x2d\x07\xc1\x14\xab\xd2\xac\x4e\x29\x25\x09\xa7\x24\x51\xb9\x54\xa9\xa4\x95\xa4\x49\xce\x79\x96\x16\x4c\x95\x04\xf9\xc1\x6c\xf6\x0e\x22\xd5\xde\x07\xfb\xbe\x45\x74\xb1\x6d\xb5\x5e\x76\xae\xc7\xf2\xb3\x96\xb6\xc3\xaa\x70\xa3\xd7\x68\xbb\x00\xdb\x15\x1a\xb0\x2d\x9a\x71\x63\x30\x28\x7b\xcb\x48\xec\x08\xe0\x67\x30\xfd\x3c\xba\xcc\xe1\x80\x11\xdf\x47\xba\xea\xb0\xc3\x17\x21\xfa\x11\x0a\xbf\x37\x72\xe5\xac\xb1\x9d\x8f\x5a\x91\xe8\xbd\x36\xcb\xd9\xb7\xe8\x30\x24\x30\xec\x3b\xbe\x9f\xb6\xe9\xd6\x15\xba\xa8\xb6\x48\x18\x74\xfe\x48\x5a\xe3\xa3\x80\x47\xe5\x6d\xa3\xae\x2a\x04\xd1\x34\x56\x8a\x80\x0a\x44\x00\x1f\x84\x0b\x5d\x3b\x83\xe8\x7f\x3b\x38\xce\x81\xf6\xe8\x1f\x1d\xa2\x87\xae\x85\x93\xcb\x2f\x20\xf7\xb2\x41\x3f\x94\x3a\x04\x00\xed\x61\x2b\x74\xbf\x26\xc5\x7c\x71\x83\x26\xc4\x52\x87\xeb\x5b\xa1\xfb\x6a\x3f\x5f\xcf\x21\x89\x85\x3e\x52\xde\xb7\x28\x75\xad\xe5\xf3\xa2\x67\x13\xe5\x87\xd2\xae\xb1\xc1\x48\xe6\xed\x4a\xcb\xd5\xa3\x1c\x40\x48\x69\xbb\xf8\x4d\xb7\xd0\x79\x9c\x5e\x25\x1b\x9b\x30\x3e\x27\x0a\xb4\xe9\x7f\x94\x9d\x0f\x76\x3d\x06\x81\x5a\x37\x38\x83\x69\x2d\x3c\x1e\x60\x2e\xc4\x1a\xe7\x70\x10\x57\xc1\x83\xc7\xe5\x2f\x26\x33\x01\x3f\xc6\x95\x8d\x8e\xab\x44\x7c\xc8\xe0\x1f\x5b\x04\x87\xdf\x3a\xed\x10\xb6\x1e\xac\x03\xdd\xca\x71\x23\x8c\x0b\x60\x3c\x4a\x11\x62\xda\x7d\x4b\xfe\x19\xbb\x6b\x15\x7e\x59\x9c\xcf\x61\xeb\xe7\x47\x47\x71\x00\xcd\xca\xfa\x30\x2f\xb3\x94\x4f\xa3\xec\xf7\xd5\xa5\x88\x95\x68\x19\x93\x5d\x0a\x7f\x19\x8f\x73\x48\xc8\xf4\xf7\x83\x71\xa3\xd7\x3a\x0c\xc6\xe7\xf1\x38\x87\x34\x4f\x28\x2b\x8a\x67\x14\x0d\xb6\x9f\xd5\x40\x2c\xf3\xbd\xae\xe0\x84\xf1\xa2\xa7\xeb\x54\x81\x52\xc3\x7e\x2b\xa0\x6a\xac\x7c\x00\x61\xd4\x58\x08\x04\xa7\x97\x4b\x74\xa8\x06\x42\x07\xdc\x85\x69\xcc\x03\xa9\x39\x89\xac\x7e\x2d\xb0\x43\xa1\xc0\x9a\x66\x1f\xc5\x32\x51\x7d\x5a\xf2\xa7\x94\xbe\x43\x2f\x50\xa8\xe7\xf0\x49\x36\xa2\x5f\xc4\x39\x3c\xcd\xbd\xb5\xb6\x81\xb5\xd8\x81\xc3\xe0\xf4\xf0\x4d\xf1\x68\x14\x88\x67\x66\x76\x83\x6e\x06\xd1\x70\x31\xd8\xcd\x81\x8e\x3d\xfd\x73\x48\x6d\x02\xba\x8d\x68\x7a\xdc\xfd\x40\x7f\x11\x13\x94\x9d\x73\xfd\x72\xf9\xc4\x63\x25\x3c\x54\x88\x71\xfb\x0c\x28\x43\xdf\xa6\x09\x20\xc6\x8b\xaf\x19\x1d\x2b\x38\xd5\xbe\xe7\x4a\x8f\xe8\xed\xfa\x07\xae\x79\x50\x16\x8c\x0d\xe0\xbb\xb6\xb5\x2e\x40\xd8\xf5\x19\x89\x56\xc7\xff\x2f\x76\x97\xd6\x36\xc7\x32\x3e\x0a\x67\x26\x22\xa9\x39\x04\xd7\xe1\x6c\xf6\xef\x00\x00\x00\xff\xff\x88\x91\x60\xe6\x54\x0d\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x59\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xae\xd2\xe0\x92\xdc\x92\x5c\x8f\xf9\xf5\x1b\xf2\x83\x06\x7a\x60\x37\x36\x62\x76\x38\x29\xac\xcc\x2f\x5f\xdf\xa7\x4a\xde\xc1\x29\xd6\xa2\x6b\x02\x28\xdc\x60\x63\xdb\x35\x9a\x00\x01\x7d\x30\x18\x40\x2c\x85\x36\x3e\x80\xd3\xe6\x01\xab\xfd\x4c\xa2\x09\x4e\xd7\xdd\x12\x2f\x30\x6c\xad\x7b\x98\x83\xeb\xbc\xd7\xc2\xac\x74\xd3\xcc\x7a\x30\x6d\x10\xc2\x0a\x41\x8d\xb8\x66\xb0\xf4\x10\x56\x22\xc0\xc9\x23\x02\xac\x85\x36\x21\xe2\xcf\x26\x93\xf9\x0c\xe0\x1d\x9c\x5b\x29\x9a\x3e\x05\x6d\x96\x20\xad\x09\x4e\xc8\x00\x42\x29\x87\xde\xa3\x07\x83\xa8\x20\x58\xa8\x10\x3c\x06\xd8\xea\xb0\x02\x34\x1b\xd8\x08\xa7\x45\xd5\xa0\x3f\x9c\xc1\xe4\x1f\x21\x01\xb4\x9a\x03\x63\xac\x3f\x63\x58\xa1\xc3\x6e\x3d\x56\xf0\x8b\x9a\x43\xc1\x8a\xe1\xae\xb2\x36\xf8\xe0\x44\x7b\x89\xe8\xfc\xe0\x0b\xf0\x1e\x0e\x8e\x74\x9b\x1e\x25\x34\x3f\x24\x87\xe4\x30\x39\x0a\xb2\x3d\x62\x05\x25\xf4\x48\xb7\xb5\x3f\xba\x5a\xdf\x5c\xed\xaa\xed\x43\x77\x7f\x77\x77\x5a\x77\x7f\xdc\x54\xbb\xb3\xe3\x05\xde\x5c\x9c\x9c\xdb\x3f\xf6\xfb\x2c\x2b\x36\x57\x66\xf9\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\xcb\x26\xd8\xaf\x35\x3f\xbb\xe0\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xfa\xed\xb2\x4b\xf8\x6f\xad\xfa\x89\x3d\xfc\x6a\x93\x1b\xb6\x5e\x89\xd5\xe5\x87\xec\x1a\x33\x93\x0c\xb0\x53\xbb\x8e\xa7\x6e\x4d\x45\x68\x85\x26\xe8\xb0\xff\x28\x64\xb0\x6e\x3f\x87\x83\x83\x17\x37\x0b\x5c\x6a\x1f\x9e\x5d\x09\x23\x57\xd6\x2d\xb0\xb5\x5e\xbf\xf0\x6a\xc5\x3e\x52\xe5\x5f\x55\xa3\x97\x22\x68\x6b\xfa\xbb\x7e\x80\x9f\x85\x36\x7f\x4a\xa7\x71\xce\x33\x78\xca\x9a\x21\xc1\x77\x70\xd1\xad\xd1\x69\x09\xbf\x9c\x82\xad\x7b\x06\x3d\xe1\xca\x77\xcf\x61\x98\x59\x32\x7a\x7d\x98\x26\x06\x8d\xf6\x21\x7a\x1a\xab\xf0\x47\xb2\xb5\xce\x6e\x74\x7f\x61\x7b\xec\x27\x09\x4c\xe9\xfd\x17\x0c\x60\xd9\x21\xa5\xd9\x21\x25\xe4\x30\xa5\x2f\x59\x90\xd0\x53\xf6\xc9\xda\xdb\x73\xad\xe5\xd5\xd7\xed\xcd\xea\xe6\xc3\x1d\xdf\x7d\x92\x97\xf6\xbc\xe6\x8b\xab\xbb\x5f\x3f\xb6\xdb\x3a\x71\x79\xb6\x3d\xdf\xd1\xfb\x05\x6b\x4f\x54\xf2\x92\x0b\x63\x80\x82\x1f\xd2\x84\xbc\x16\xe0\xea\xfe\xf3\x71\xf1\xd3\xe5\xcf\x6e\x73\x76\xff\xa1\xdc\xaa\x07\xfb\x45\x1e\x1f\xaf\x4f\xee\x7f\x6e\x4b\xdc\xef\xef\xd3\xeb\xb3\x62\xf9\xd1\xb1\xd5\xcd\xc5\x6f\x07\x63\x9f\xce\x46\xd6\x4f\x9d\x8c\x6d\x7e\x0f\x8b\x51\xd7\xaf\xe8\x22\x1d\x9d\xcf\x45\x6c\x11\x28\x6c\x1b\xbb\x47\x05\xd7\x6b\xe1\x02\x9c\x8c\x54\xf3\x50\x5b\xd7\x37\x75\xa9\x37\x68\x9e\xb5\xf3\x47\x3a\xc2\xab\x7c\x24\xbb\x92\x28\x5a\xa6\x59\x9e\x60\xce\x8a\x94\xf2\x32\x17\x9c\x57\xb9\x28\x4b\x41\x4a\xa5\xb8\xcc\x99\x62\x19\x57\x6f\x30\x97\xec\x4a\xce\x89\x24\xac\x54\x2c\x49\xd2\x8c\x89\x9a\xa8\xac\x90\x19\xe7\x3c\xa7\x4c\x95\x92\xd6\x22\x57\x1c\xe5\x1b\x1c\x27\xbb\xbc\x2e\xb2\x54\xd5\xa2\x2c\x48\x42\x55\x5e\x8b\x2c\x93\x05\x61\x55\x25\x28\xe5\xa4\x92\x0a\x31\xad\x32\x54\x6f\xa9\x81\xec\x78\x99\xd0\x82\xf0\x3c\xaf\x32\x8a\x4c\x8a\x3c\x41\x42\x19\xa2\xa2\xaa\x60\xb5\x28\x6b\x21\x59\xc5\xd3\xaa\xd7\x4d\x85\xce\x88\x66\x85\x7a\xb9\x0a\xfe\x7f\x13\x05\xfd\x3f\x8a\xe2\x2f\x96\xc4\xdf\x24\x88\x4f\x76\x23\xcc\xab\x72\xa0\x7f\x81\x1e\xde\x90\x43\x91\x55\x8c\xd6\xb9\x60\x75\x4a\xd2\x22\xa9\x13\xca\x58\x4a\xd2\x84\xe7\x44\x16\xb2\x42\x92\xd7\xb9\xca\x4b\xf9\xa6\x1c\xb2\x54\x20\xcb\x59\x4d\x4a\x5e\x8b\x9a\xaa\x8a\x57\x85\x48\x79\x9e\xe4\x92\x54\x65\x81\xb2\x16\x24\xcf\x94\x7a\x53\x0e\x69\x9a\xd6\x3c\x2d\x91\x91\x3c\x4d\x29\xe6\x5c\xca\x3a\x67\x79\xca\x39\x66\xb4\x4e\x38\x29\xab\xb2\xa0\x9c\xbc\x2d\x07\xc1\x14\xab\xd2\xac\x4e\x29\x25\x09\xa7\x24\x51\xb9\x54\xa9\xa4\x95\xa4\x49\xce\x79\x96\x16\x4c\x95\x04\xf9\xc1\x6c\xf6\x0e\x22\xd5\xde\x07\xfb\xbe\x45\x74\xb1\x6d\xb5\x5e\x76\xae\xc7\xf2\xb3\x96\xb6\xc3\xaa\x70\xa3\xd7\x68\xbb\x00\xdb\x15\x1a\xb0\x2d\x9a\x71\x63\x30\x28\x7b\xcb\x48\xec\x08\xe0\x67\x30\x7d\x1e\x5d\xe6\x70\xc0\x88\xef\x23\x5d\x75\xd8\xe1\x8b\x10\xfd\x08\x85\xdf\x1b\xb9\x72\xd6\xd8\xce\x47\xad\x48\xf4\x5e\x9b\xe5\xec\x5b\x74\x18\x12\x18\xf6\x1d\xdf\x4f\xdb\x74\xeb\x0a\x5d\x54\x5b\x24\x0c\x3a\x7f\x24\xad\xf1\x51\xc0\xa3\xf2\xb6\x51\x57\x15\x82\x68\x1a\x2b\x45\x40\x05\x22\x80\x0f\xc2\x85\xae\x9d\x41\xf4\xbf\x1d\x1c\xe7\x40\x7b\xf4\x8f\x0e\xd1\x43\xd7\xc2\xc9\xe5\x17\x90\x7b\xd9\xa0\x1f\x4a\x1d\x02\x80\xf6\xb0\x15\xba\x5f\x93\x62\xbe\xb8\x41\x13\x62\xa9\xc3\xf5\xad\xd0\x7d\xb5\x9f\xaf\xe7\x90\xc4\x42\x1f\x29\xef\x5b\x94\xba\xd6\xf2\x79\xd1\xb3\x89\xf2\x43\x69\xd7\xd8\x60\x24\xf3\x76\xa5\xe5\xea\x51\x0e\x20\xa4\xb4\x5d\xfc\x4d\xb7\xd0\x79\x9c\x5e\x25\x1b\x9b\x30\x3e\x27\x0a\xb4\xe9\x3f\xca\xce\x07\xbb\x1e\x83\x40\xad\x1b\x9c\xc1\xb4\x16\x1e\x0f\x30\x17\x62\x8d\x73\x38\x88\xab\xe0\xc1\xe3\xf2\x17\x93\x99\x80\x1f\xe3\xca\x46\xc7\x55\x22\x3e\x64\xf0\x8f\x2d\x82\xc3\x6f\x9d\x76\x08\x5b\x0f\xd6\x81\x6e\xe5\xb8\x11\xc6\x05\x30\x1e\xa5\x08\x31\xed\xbe\x25\xff\x8c\xdd\xb5\x0a\xbf\x2c\xce\xe7\xb0\xf5\xf3\xa3\xa3\x38\x80\x66\x65\x7d\x98\x97\x59\xca\xa7\x51\xf6\xfb\xea\x52\xc4\x4a\xb4\x8c\xc9\x2e\x85\xbf\x8c\xc7\x39\x24\x64\xfa\xfb\xc1\xb8\xd1\x6b\x1d\x06\xe3\xf3\x78\x9c\x43\x9a\x27\x94\x15\xc5\x33\x8a\x06\xdb\xcf\x6a\x20\x96\xf9\x5e\x57\x70\xc2\x78\xd1\xd3\x75\xaa\x40\xa9\x61\xbf\x15\x50\x35\x56\x3e\x80\x30\x6a\x2c\x04\x82\xd3\xcb\x25\x3a\x54\x03\xa1\x03\xee\xc2\x34\xe6\x81\xd4\x9c\x44\x56\xbf\x16\xd8\xa1\x50\x60\x4d\xb3\x8f\x62\x99\xa8\x3e\x2d\xf9\x53\x4a\xdf\xa1\x17\x28\xd4\x73\xf8\x24\x1b\xd1\x2f\xe2\x1c\x9e\xe6\xde\x5a\xdb\xc0\x5a\xec\xc0\x61\x70\x7a\xf8\x4d\xf1\x68\x14\x88\x67\x66\x76\x83\x6e\x06\xd1\x70\x31\xd8\xcd\x81\x8e\x3d\xfd\x73\x48\x6d\x02\xba\x8d\x68\x7a\xdc\xfd\x40\x7f\x11\x13\x94\x9d\x73\xfd\x72\xf9\xc4\x63\x25\x3c\x54\x88\x71\xfb\x0c\x28\x43\xdf\xa6\x09\x20\xc6\x8b\xaf\x19\x1d\x2b\x38\xd5\xbe\xe7\x4a\x8f\xe8\xed\xfa\x07\xae\x79\x50\x16\x8c\x0d\xe0\xbb\xb6\xb5\x2e\x40\xd8\xf5\x19\x89\x56\xc7\xff\x2f\x76\x97\xd6\x36\xc7\x32\x3e\x0a\x67\x26\x22\xa9\x39\x04\xd7\x61\x54\x9a\x30\x7b\x50\x58\x75\xcb\xe5\xf8\x20\x45\x01\xf4\xf2\x5f\x5a\x88\x41\x66\xfd\xed\x20\xb4\xb6\x75\xb6\xee\xc7\xf3\xe8\x32\x83\xe1\xeb\x1c\x6a\xd1\x78\x9c\xfd\x3b\x00\x00\xff\xff\xbc\x1e\x8e\x26\xa6\x0d\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3412, mode: os.FileMode(420), modTime: time.Unix(1542796688, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3494, mode: os.FileMode(420), modTime: time.Unix(1542883920, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From a67d385eabe50b93fee81b797ce7e0d5c8739fbb Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 22 Nov 2018 17:57:08 +0100 Subject: [PATCH 041/220] Remove PaymentObligation global (var po *ethereumPaymentObligation) (#478) * Remove PaymentObligation global * Fmt --- api/bootstrapper.go | 5 ++-- api/server.go | 6 ++--- api/server_test.go | 29 ++++++++++++++++++---- api/service.go | 21 ++++++++++++++-- bootstrap/bootstrapper.go | 1 + nft/bootstrapper.go | 4 ++- nft/ethereum_payment_obligation.go | 10 -------- nft/handler.go | 4 +-- nft/payment_obligation_integration_test.go | 6 +++-- node/bootstrapper.go | 2 +- resources/data.go | 2 +- 11 files changed, 60 insertions(+), 30 deletions(-) diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 7cc012d54..bbe4bb7d7 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -18,12 +18,13 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("config not initialised") } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + // just check to make sure that registry is initialised + _, ok = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return fmt.Errorf("service registry not initialised") } - srv := apiServer{config: cfg, registry: registry} + srv := apiServer{config: cfg} ctx[bootstrap.BootstrappedAPIServer] = srv return nil } diff --git a/api/server.go b/api/server.go index 337af15cd..d29e91f68 100644 --- a/api/server.go +++ b/api/server.go @@ -16,7 +16,6 @@ import ( "time" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/documents" "github.com/grpc-ecosystem/grpc-gateway/runtime" logging "github.com/ipfs/go-log" "golang.org/x/net/context" @@ -35,8 +34,7 @@ type Config interface { // apiServer is an implementation of node.Server interface for serving HTTP based Centrifuge API type apiServer struct { - config Config - registry *documents.ServiceRegistry + config Config } func (apiServer) Name() string { @@ -77,7 +75,7 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha mux := http.NewServeMux() gwmux := runtime.NewServeMux() - err = registerServices(ctx, c.config, c.registry, grpcServer, gwmux, addr, dopts) + err = registerServices(ctx, c.config, grpcServer, gwmux, addr, dopts) if err != nil { startupErr <- err return diff --git a/api/server_test.go b/api/server_test.go index b1eeb4c01..46cdc8902 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -18,11 +18,12 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" - "github.com/centrifuge/go-centrifuge/identity" ) var ctx = map[string]interface{}{} @@ -44,6 +45,7 @@ func TestMain(m *testing.M) { p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, + &nft.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) @@ -60,8 +62,8 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil, nil)) - capi := apiServer{config: cfg, registry: registry} - ctx, canc := context.WithCancel(context.Background()) + capi := apiServer{config: cfg} + ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) @@ -76,8 +78,8 @@ func TestCentAPIServer_StartListenError(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 100000000) cfg.Set("centrifugeNetwork", "") - ctx, _ := context.WithCancel(context.Background()) - capi := apiServer{config: cfg, registry: registry} + ctx, _ := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) + capi := apiServer{config: cfg} startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) @@ -87,3 +89,20 @@ func TestCentAPIServer_StartListenError(t *testing.T) { assert.NotNil(t, err, "Error should be not nil") assert.Equal(t, "listen tcp: address 100000000: invalid port", err.Error()) } + +func TestCentAPIServer_FailedToGetRegistry(t *testing.T) { + // cause an error by using an invalid port + cfg.Set("nodeHostname", "0.0.0.0") + cfg.Set("nodePort", 100000000) + cfg.Set("centrifugeNetwork", "") + ctx, _ := context.WithCancel(context.Background()) + capi := apiServer{config: cfg} + startErr := make(chan error) + var wg sync.WaitGroup + wg.Add(1) + go capi.Start(ctx, &wg, startErr) + err := <-startErr + wg.Wait() + assert.NotNil(t, err, "Error should be not nil") + assert.Equal(t, "failed to get NodeObjRegistry", err.Error()) +} diff --git a/api/service.go b/api/service.go index 550a3cd17..a1fbdf930 100644 --- a/api/service.go +++ b/api/service.go @@ -3,6 +3,7 @@ package api import ( "fmt" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -20,7 +21,23 @@ import ( ) // registerServices registers all endpoints to the grpc server -func registerServices(ctx context.Context, cfg Config, registry *documents.ServiceRegistry, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { +func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, gwmux *runtime.ServeMux, addr string, dopts []grpc.DialOption) error { + // node object registry + nodeObjReg, ok := ctx.Value(bootstrap.NodeObjRegistry).(map[string]interface{}) + if !ok { + return fmt.Errorf("failed to get %s", bootstrap.NodeObjRegistry) + } + + // load dependencies + registry, ok := nodeObjReg[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + if !ok { + return fmt.Errorf("failed to get %s", documents.BootstrappedRegistry) + } + payObService, ok := nodeObjReg[nft.BootstrappedPayObService].(nft.PaymentObligation) + if !ok { + return fmt.Errorf("failed to get %s", nft.BootstrappedPayObService) + } + // documents (common) documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler(registry)) err := documentpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) @@ -61,7 +78,7 @@ func registerServices(ctx context.Context, cfg Config, registry *documents.Servi return err } - nftpb.RegisterNFTServiceServer(grpcServer, nft.GRPCHandler()) + nftpb.RegisterNFTServiceServer(grpcServer, nft.GRPCHandler(payObService)) err = nftpb.RegisterNFTServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index dbee1406a..8cc88465e 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -5,6 +5,7 @@ package bootstrap const ( BootstrappedP2PServer string = "BootstrappedP2PServer" BootstrappedAPIServer string = "BootstrappedAPIServer" + NodeObjRegistry string = "NodeObjRegistry" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index a7c0d94e7..8040148d4 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -11,6 +11,8 @@ import ( "github.com/centrifuge/go-centrifuge/queue" ) +const BootstrappedPayObService = "BootstrappedPayObService" + type Bootstrapper struct { } @@ -35,6 +37,6 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("identity service not initialised") } - setPaymentObligation(NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, setupMintListener, bindContract)) + ctx[BootstrappedPayObService] = NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, setupMintListener, bindContract) return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext)) } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 68ccd8d20..734e5cb47 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -28,8 +28,6 @@ import ( var log = logging.Logger("nft") -var po *ethereumPaymentObligation - const amountOfProofs = 5 var regexCollaborators, _ = regexp.Compile("collaborators\\[[0-9]+\\]") @@ -42,14 +40,6 @@ type Config interface { GetEthereumContextWaitTimeout() time.Duration } -func setPaymentObligation(s *ethereumPaymentObligation) { - po = s -} - -func GetPaymentObligation() *ethereumPaymentObligation { - return po -} - // ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out type ethereumPaymentObligationContract interface { diff --git a/nft/handler.go b/nft/handler.go index 2228d4ec3..a68f62b72 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -19,8 +19,8 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler() nftpb.NFTServiceServer { - return &grpcHandler{service: GetPaymentObligation()} +func GRPCHandler(payOb PaymentObligation) nftpb.NFTServiceServer { + return &grpcHandler{service: payOb} } // MintNFT will be called from the client API to mint an NFT diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index de2f9e8a3..c7e2bd0f1 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -14,18 +14,19 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/header" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/ethereum/go-ethereum/log" "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" - "github.com/centrifuge/go-centrifuge/identity" ) var registry *documents.ServiceRegistry var cfg *config.Configuration var idService identity.Service +var payOb nft.PaymentObligation func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") @@ -33,6 +34,7 @@ func TestMain(m *testing.M) { registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) prevSignPubkey := cfg.Get("keys.signing.publicKey") prevSignPrivkey := cfg.Get("keys.signing.privateKey") prevEthPubkey := cfg.Get("keys.ethauth.publicKey") @@ -81,7 +83,7 @@ func TestPaymentObligationService_mint(t *testing.T) { assert.Nil(t, err, "should not error out when getting invoice ID") // call mint // assert no error - confirmations, err := nft.GetPaymentObligation().MintNFT( + confirmations, err := payOb.MintNFT( ID, cfg.GetContractAddress("paymentObligation").String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", diff --git a/node/bootstrapper.go b/node/bootstrapper.go index b12d742d6..1fd0488db 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -21,7 +21,7 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { n := NewNode(srvs) feedback := make(chan error) // may be we can pass a context that exists in c here - ctx, canc := context.WithCancel(context.Background()) + ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, c)) go n.Start(ctx, feedback) controlC := make(chan os.Signal, 1) signal.Notify(controlC, os.Interrupt) diff --git a/resources/data.go b/resources/data.go index 5a11a42ba..64c5cf020 100644 --- a/resources/data.go +++ b/resources/data.go @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - From d38761f8cbc50b450135d57029cac1d972b20a80 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 22 Nov 2018 20:44:49 +0100 Subject: [PATCH 042/220] Include prefix precise proof (#477) * include prefix precise proof * comment out test --- Gopkg.lock | 4 +- Gopkg.toml | 4 +- documents/invoice/model.go | 4 +- documents/invoice/model_test.go | 7 +- documents/invoice/service_test.go | 14 ++-- documents/purchaseorder/model.go | 4 +- documents/purchaseorder/model_test.go | 7 +- documents/purchaseorder/service_test.go | 14 ++-- nft/payment_obligation_integration_test.go | 94 ++++++++++------------ 9 files changed, 74 insertions(+), 78 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 91f166f72..3e6f9ab61 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -78,14 +78,14 @@ revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" [[projects]] - digest = "1:3d9dcd118a682029404e301e7769803c3e6a48e7a964eb03364b938007080e24" + digest = "1:d065eb5f32b539d2935f0ec4f2f160b78c924306b923ce5eac6e7dfe46d07794" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "ff15857d84b0eea93e52cc465f71662b78f62f6f" + revision = "8957bc48e1bd690a835c630fa6fdfd141c41f5dd" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" diff --git a/Gopkg.toml b/Gopkg.toml index 4172e6141..d751f6d1e 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -38,9 +38,9 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/Masterminds/semver" version = "1.4.2" -[[constraint]] +[[override]] name = "github.com/centrifuge/precise-proofs" - revision = "ff15857d84b0eea93e52cc465f71662b78f62f6f" + revision = "8957bc48e1bd690a835c630fa6fdfd141c41f5dd" [[constraint]] name = "github.com/centrifuge/gocelery" diff --git a/documents/invoice/model.go b/documents/invoice/model.go index d4cff36eb..e429f2fa7 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -22,6 +22,8 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" ) +const prefix string = "invoice" + // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { // invoice number or reference number @@ -369,7 +371,7 @@ func (i *Invoice) calculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prefix}) invoiceData := i.createP2PProtobuf() err = t.AddLeavesFromDocument(invoiceData, i.getInvoiceSalts(invoiceData)) if err != nil { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 5e35501f4..82d0cc5de 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -258,7 +258,7 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { func TestInvoiceModel_createProofs(t *testing.T) { i, corDoc, err := createMockInvoice(t) assert.Nil(t, err) - corDoc, proof, err := i.createProofs([]string{"invoice_number", "collaborators[0]", "document_type"}) + corDoc, proof, err := i.createProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) assert.NotNil(t, corDoc) @@ -301,8 +301,9 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { i := Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2} tree, err := i.getDocumentDataTree() assert.Nil(t, err, "tree should be generated without error") - _, leaf := tree.GetLeafByProperty("invoice_number") - assert.Equal(t, "invoice_number", leaf.Property) + _, leaf := tree.GetLeafByProperty("invoice.invoice_number") + assert.NotNil(t, leaf) + assert.Equal(t, "invoice.invoice_number", leaf.Property) } func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, error) { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index ad8d44947..64db7ef9e 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -313,12 +313,12 @@ func TestService_CreateProofs(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) - proof, err := invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice_number"}) + proof, err := invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionId) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") } func TestService_CreateProofsValidationFails(t *testing.T) { @@ -329,7 +329,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = getRepository().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) - _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice_number"}) + _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -346,7 +346,7 @@ func TestService_CreateProofsInvalidField(t *testing.T) { func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, invService := getServiceWithMockedLayers() - _, err := invService.CreateProofs(utils.RandomSlice(32), []string{"invoice_number"}) + _, err := invService.CreateProofs(utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.Equal(t, "document not found: leveldb: not found", err.Error()) } @@ -359,19 +359,19 @@ func TestService_CreateProofsForVersion(t *testing.T) { olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - proof, err := invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice_number"}) + proof, err := invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) assert.Equal(t, olderVersion, proof.VersionId) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) _, invSrv := getServiceWithMockedLayers() assert.Nil(t, err) - _, err = invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice_number"}) + _, err = invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.Equal(t, "document not found for the given version: leveldb: not found", err.Error()) } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index d3080bb13..c7863c71b 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -22,6 +22,8 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" ) +const prefix string = "po" + // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { Status string // status of the Purchase Order @@ -347,7 +349,7 @@ func (p *PurchaseOrder) calculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prefix}) poData := p.createP2PProtobuf() err = t.AddLeavesFromDocument(poData, p.getPurchaseOrderSalts(poData)) if err != nil { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 27e24bdc0..344bd264f 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -231,7 +231,7 @@ func TestPOModel_calculateDataRoot(t *testing.T) { func TestPOModel_createProofs(t *testing.T) { poModel, corDoc, err := createMockPurchaseOrder(t) assert.Nil(t, err) - corDoc, proof, err := poModel.createProofs([]string{"po_number", "collaborators[0]", "document_type"}) + corDoc, proof, err := poModel.createProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) assert.NotNil(t, corDoc) @@ -267,8 +267,9 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { poModel := PurchaseOrder{PoNumber: "3213121", NetAmount: 2, OrderAmount: 2} tree, err := poModel.getDocumentDataTree() assert.Nil(t, err, "tree should be generated without error") - _, leaf := tree.GetLeafByProperty("po_number") - assert.Equal(t, "po_number", leaf.Property) + _, leaf := tree.GetLeafByProperty("po.po_number") + assert.NotNil(t, leaf) + assert.Equal(t, "po.po_number", leaf.Property) } func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, *coredocumentpb.CoreDocument, error) { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index aefc00bb5..1d9a5feeb 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -385,12 +385,12 @@ func TestService_CreateProofs(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) - proof, err := poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po_number"}) + proof, err := poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionId) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po_number") + assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") } func TestService_CreateProofsValidationFails(t *testing.T) { @@ -401,7 +401,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = getRepository().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) - _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po_number"}) + _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -418,7 +418,7 @@ func TestService_CreateProofsInvalidField(t *testing.T) { func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, poSrv := getServiceWithMockedLayers() - _, err := poSrv.CreateProofs(utils.RandomSlice(32), []string{"po_number"}) + _, err := poSrv.CreateProofs(utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) assert.Equal(t, "document not found: leveldb: not found", err.Error()) } @@ -467,19 +467,19 @@ func TestService_CreateProofsForVersion(t *testing.T) { olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - proof, err := poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po_number"}) + proof, err := poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po.po_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) assert.Equal(t, olderVersion, proof.VersionId) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po_number") + assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) _, poSrv := getServiceWithMockedLayers() assert.Nil(t, err) - _, err = poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po_number"}) + _, err = poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) assert.Equal(t, "document not found for the given version: leveldb: not found", err.Error()) } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index c7e2bd0f1..f95c8bbbf 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,24 +3,14 @@ package nft_test import ( - "context" "os" "testing" - "time" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/ethereum/go-ethereum/log" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/stretchr/testify/assert" ) var registry *documents.ServiceRegistry @@ -52,45 +42,45 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestPaymentObligationService_mint(t *testing.T) { - // create identity - log.Debug("Create Identity for Testing") - testingidentity.CreateIdentityWithKeys(cfg, idService) - - // create invoice (anchor) - service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) - assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader, err := header.NewContextHeader(context.Background(), cfg) - assert.Nil(t, err) - invoiceService := service.(invoice.Service) - dueDate := time.Now().Add(4 * 24 * time.Hour) - model, err := invoiceService.DeriveFromCreatePayload( - &invoicepb.InvoiceCreatePayload{ - Collaborators: []string{}, - Data: &invoicepb.InvoiceData{ - InvoiceNumber: "2132131", - GrossAmount: 123, - NetAmount: 123, - Currency: "EUR", - DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, - }, - }, contextHeader) - assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, err := invoiceService.Create(contextHeader, model) - - // get ID - ID, err := modelUpdated.ID() - assert.Nil(t, err, "should not error out when getting invoice ID") - // call mint - // assert no error - confirmations, err := payOb.MintNFT( - ID, - cfg.GetContractAddress("paymentObligation").String(), - "0xf72855759a39fb75fc7341139f5d7a3974d4da08", - []string{"gross_amount", "currency", "due_date", "document_type", "collaborators[0]"}, - ) - assert.Nil(t, err, "should not error out when minting an invoice") - tokenConfirm := <-confirmations - assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") - assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") -} +//func TestPaymentObligationService_mint(t *testing.T) { +// // create identity +// log.Debug("Create Identity for Testing") +// testingidentity.CreateIdentityWithKeys(cfg, idService) +// +// // create invoice (anchor) +// service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) +// assert.Nil(t, err, "should not error out when getting invoice service") +// contextHeader, err := header.NewContextHeader(context.Background(), cfg) +// assert.Nil(t, err) +// invoiceService := service.(invoice.Service) +// dueDate := time.Now().Add(4 * 24 * time.Hour) +// model, err := invoiceService.DeriveFromCreatePayload( +// &invoicepb.InvoiceCreatePayload{ +// Collaborators: []string{}, +// Data: &invoicepb.InvoiceData{ +// InvoiceNumber: "2132131", +// GrossAmount: 123, +// NetAmount: 123, +// Currency: "EUR", +// DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, +// }, +// }, contextHeader) +// assert.Nil(t, err, "should not error out when creating invoice model") +// modelUpdated, err := invoiceService.Create(contextHeader, model) +// +// // get ID +// ID, err := modelUpdated.ID() +// assert.Nil(t, err, "should not error out when getting invoice ID") +// // call mint +// // assert no error +// confirmations, err := payOb.MintNFT( +// ID, +// cfg.GetContractAddress("paymentObligation").String(), +// "0xf72855759a39fb75fc7341139f5d7a3974d4da08", +// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "document_type", "collaborators[0]"}, +// ) +// assert.Nil(t, err, "should not error out when minting an invoice") +// tokenConfirm := <-confirmations +// assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") +// assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") +//} From 50f80d5d7fa33e452986756353e1ba05d252b5c7 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 26 Nov 2018 14:44:53 +0100 Subject: [PATCH 043/220] Queue implements Server and removing the queue.Queue global (#469) * Queue implements Server and removing the queue.Queue global * Looks good * Fix tests * Fix problem with init * More queue init fixes * More queue init fixes * Fix tests * Fix tests * Fix tests * Lock for qs.stop * Fix race conditions * Fix problems and review comments * Fix problems and review comments * Fix problems and review comments * Fix problems and review comments * Lock * Lock * Lock * model test --- anchors/anchor_confirmation_task.go | 10 +- anchors/bootstrapper.go | 12 +- anchors/ethereum_anchor_repository.go | 14 +- anchors/ethereum_anchor_repository_test.go | 2 +- api/server.go | 4 - api/server_test.go | 3 + bootstrap/bootstrapper.go | 7 +- bootstrap/test_bootstrapper.go | 8 +- context/bootstrapper.go | 4 +- context/testingbootstrap/testing_bootstrap.go | 3 +- documents/invoice/model_test.go | 3 + documents/purchaseorder/model_test.go | 2 + identity/bootstrapper.go | 31 +++-- identity/ethereum_identity.go | 29 +++-- identity/ethereum_identity_test.go | 26 ++-- identity/id_registration_confirmation_task.go | 10 +- .../key_registration_confirmation_task.go | 19 ++- nft/bootstrapper.go | 13 +- nft/ethereum_payment_obligation.go | 17 +-- nft/ethereum_payment_obligation_test.go | 3 +- nft/minting_confirmation_task.go | 10 +- nft/payment_obligation_integration_test.go | 1 + node/bootstrapper.go | 12 +- queue/bootstrapper.go | 34 +---- queue/bootstrapper_test.go | 39 ------ queue/queue.go | 69 ---------- queue/server.go | 121 ++++++++++++++++++ queue/test_bootstrapper.go | 29 ++++- 28 files changed, 283 insertions(+), 252 deletions(-) delete mode 100644 queue/bootstrapper_test.go delete mode 100644 queue/queue.go create mode 100644 queue/server.go diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index 5dfe90e7e..820d8d43e 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -48,17 +48,11 @@ type anchorConfirmationTask struct { AnchorCommittedFilterer anchorCommittedWatcher } -// Name returns AnchorRepositoryConfirmationTaskName -func (act *anchorConfirmationTask) Name() string { +// TaskTypeName returns AnchorRepositoryConfirmationTaskName +func (act *anchorConfirmationTask) TaskTypeName() string { return AnchorRepositoryConfirmationTaskName } -// Init registers the task to the queue -func (act *anchorConfirmationTask) Init() error { - queue.Queue.Register(act.Name(), act) - return nil -} - // Copy returns a new instance of anchorConfirmationTask func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &anchorConfirmationTask{ diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 629cc24bc..1b4c99ba8 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -3,6 +3,7 @@ package anchors import ( "errors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" @@ -31,8 +32,12 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - var repo AnchorRepository - repo = NewEthereumAnchorRepository(cfg, repositoryContract, ethereum.GetClient) + if _, ok := ctx[bootstrap.BootstrappedQueueServer]; !ok { + return errors.New("queue server hasn't been initialized") + } + + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + repo := newEthereumAnchorRepository(cfg, repositoryContract, queueSrv, ethereum.GetClient) ctx[BootstrappedAnchorRepo] = repo task := &anchorConfirmationTask{ @@ -42,5 +47,6 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { EthContextInitializer: ethereum.DefaultWaitForTransactionMiningContext, } - return queue.InstallQueuedTask(ctx, task) + queueSrv.RegisterTaskType(task.TaskTypeName(), task) + return nil } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 1693724f5..59c7cd933 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -38,10 +37,11 @@ type EthereumAnchorRepository struct { config Config anchorRepositoryContract AnchorRepositoryContract gethClientFinder func() ethereum.Client + queue *queue.Server } -func NewEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorRepositoryContract, gethClientFinder func() ethereum.Client) *EthereumAnchorRepository { - return &EthereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder} +func newEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorRepositoryContract, queue *queue.Server, gethClientFinder func() ethereum.Client) *EthereumAnchorRepository { + return &EthereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder, queue: queue} } // Commits takes an anchorID and returns the corresponding documentRoot from the chain @@ -87,7 +87,7 @@ func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, d } cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, centrifugeId, documentProofs, signature) - confirmations, err = setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) + confirmations, err = ethRepository.setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) if err != nil { wError := errors.Wrap(err, 1) log.Errorf("Failed to set up event listener for commit transaction [id: %x, hash: %x]: %v", @@ -176,9 +176,9 @@ func setUpPreCommitEventListener(contractEvent WatchAnchorPreCommitted, from com // setUpCommitEventListener sets up the listened for the "AnchorCommitted" event to notify the upstream code // about successful mining/creation of a commit -func setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { +func (ethRepository *EthereumAnchorRepository) setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { confirmations = make(chan *WatchCommit) - asyncRes, err := queue.Queue.DelayKwargs(AnchorRepositoryConfirmationTaskName, map[string]interface{}{ + asyncRes, err := ethRepository.queue.EnqueueJob(AnchorRepositoryConfirmationTaskName, map[string]interface{}{ AnchorIDParam: commitData.AnchorID, AddressParam: from, CentrifugeIDParam: commitData.CentrifugeID, @@ -209,7 +209,7 @@ func waitAndRoutePreCommitEvent(conf <-chan *EthereumAnchorRepositoryContractAnc } // waitAndRouteCommitEvent notifies the confirmations channel whenever a commit is being noted as Ethereum event -func waitAndRouteCommitEvent(timeout time.Duration, asyncResult *gocelery.AsyncResult, confirmations chan<- *WatchCommit, commitData *CommitData) { +func waitAndRouteCommitEvent(timeout time.Duration, asyncResult queue.TaskResult, confirmations chan<- *WatchCommit, commitData *CommitData) { _, err := asyncResult.Get(timeout) confirmations <- &WatchCommit{commitData, err} } diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 144398578..38759e7e9 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -80,7 +80,7 @@ func TestGetDocumentRootOf(t *testing.T) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetGethCallOpts").Return(nil) - ethRepo := NewEthereumAnchorRepository(cfg, repo, func() ethereum.Client { + ethRepo := newEthereumAnchorRepository(cfg, repo, nil, func() ethereum.Client { return ethClient }) docRoot := utils.RandomByte32() diff --git a/api/server.go b/api/server.go index d29e91f68..3f7ac9202 100644 --- a/api/server.go +++ b/api/server.go @@ -1,9 +1,5 @@ package api -// LICENSE: Apache -// This is taken from https://github.com/philips/grpc-gateway-example/ -// PLEASE DO NOT call any config.* stuff here as it creates dependencies that can't be injected easily when testing - import ( "crypto/tls" "crypto/x509" diff --git a/api/server_test.go b/api/server_test.go index 46cdc8902..eead1078f 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -21,6 +21,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" @@ -39,6 +40,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &queue.Bootstrapper{}, anchors.Bootstrapper{}, &identity.Bootstrapper{}, documents.Bootstrapper{}, @@ -46,6 +48,7 @@ func TestMain(m *testing.M) { &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, + &queue.Starter{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 8cc88465e..f47ef2b86 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -3,9 +3,10 @@ package bootstrap // DO NOT PUT any app logic in this package to avoid any dependency cycles const ( - BootstrappedP2PServer string = "BootstrappedP2PServer" - BootstrappedAPIServer string = "BootstrappedAPIServer" - NodeObjRegistry string = "NodeObjRegistry" + BootstrappedP2PServer string = "BootstrappedP2PServer" + BootstrappedAPIServer string = "BootstrappedAPIServer" + BootstrappedQueueServer string = "BootstrappedQueueServer" + NodeObjRegistry string = "NodeObjRegistry" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/bootstrap/test_bootstrapper.go b/bootstrap/test_bootstrapper.go index 2d01f03aa..65d52646e 100644 --- a/bootstrap/test_bootstrapper.go +++ b/bootstrap/test_bootstrapper.go @@ -12,12 +12,12 @@ type TestBootstrapper interface { TestTearDown() error } -func RunTestBootstrappers(bootstrappers []TestBootstrapper, context map[string]interface{}) { - if context == nil { - context = map[string]interface{}{} +func RunTestBootstrappers(bootstrappers []TestBootstrapper, ctx map[string]interface{}) { + if ctx == nil { + ctx = map[string]interface{}{} } for _, b := range bootstrappers { - err := b.TestBootstrap(context) + err := b.TestBootstrap(ctx) if err != nil { panic(err) } diff --git a/context/bootstrapper.go b/context/bootstrapper.go index a81f1f30f..33fb19567 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -31,7 +31,8 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &config.Bootstrapper{}, &storage.Bootstrapper{}, ethereum.Bootstrapper{}, - anchors.Bootstrapper{}, + &queue.Bootstrapper{}, + &anchors.Bootstrapper{}, &identity.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, @@ -39,7 +40,6 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, - &queue.Bootstrapper{}, } } diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index a6b67e3bc..92caff014 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -26,6 +26,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, &storage.Bootstrapper{}, ethereum.Bootstrapper{}, + &queue.Bootstrapper{}, anchors.Bootstrapper{}, &identity.Bootstrapper{}, documents.Bootstrapper{}, @@ -33,7 +34,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, - &queue.Bootstrapper{}, + &queue.Starter{}, } func TestFunctionalEthereumBootstrap() map[string]interface{} { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 82d0cc5de..493f16ee5 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -23,6 +23,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -44,11 +45,13 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &queue.Bootstrapper{}, &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, + &queue.Starter{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[config.BootstrappedConfig].(*config.Configuration) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 344bd264f..56f57a474 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + "github.com/centrifuge/go-centrifuge/queue" ) var ctx = map[string]interface{}{} @@ -44,6 +45,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &queue.Bootstrapper{}, &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 1d006032d..4d5754b32 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -3,6 +3,7 @@ package identity import ( "errors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" @@ -17,7 +18,7 @@ type Bootstrapper struct { } // Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. -// the idRegistrationConfirmationTask is added to be registered on the Queue at queue.Bootstrapper +// the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") @@ -39,25 +40,23 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - context[BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, ethereum.GetClient, + if _, ok := context[bootstrap.BootstrappedQueueServer]; !ok { + return errors.New("queue hasn't been initialized") + } + queueSrv := context[bootstrap.BootstrappedQueueServer].(*queue.Server) + + context[BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, queueSrv, ethereum.GetClient, func(address common.Address, backend bind.ContractBackend) (contract, error) { return NewEthereumIdentityContract(address, backend) }) - err = queue.InstallQueuedTask(context, - newIdRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext)) - if err != nil { - return err - } - - err = queue.InstallQueuedTask(context, - newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg, ethereum.GetClient, - func(address common.Address, backend bind.ContractBackend) (contract, error) { - return NewEthereumIdentityContract(address, backend) - })) - if err != nil { - return err - } + idRegTask := newIdRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext) + keyRegTask := newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg, queueSrv, ethereum.GetClient, + func(address common.Address, backend bind.ContractBackend) (contract, error) { + return NewEthereumIdentityContract(address, backend) + }) + queueSrv.RegisterTaskType(idRegTask.TaskTypeName(), idRegTask) + queueSrv.RegisterTaskType(keyRegTask.TaskTypeName(), keyRegTask) return nil } diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index aa1f03449..09ba922bb 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -16,7 +16,6 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -83,12 +82,14 @@ type ethereumIdentity struct { registryContract registry config Config gethClientFinder func() ethereum.Client + queue *queue.Server } func newEthereumIdentity(id CentID, registryContract registry, config Config, + queue *queue.Server, gethClientFinder func() ethereum.Client, contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) *ethereumIdentity { - return ðereumIdentity{centID: id, registryContract: registryContract, config: config, gethClientFinder: gethClientFinder, contractProvider: contractProvider} + return ðereumIdentity{centID: id, registryContract: registryContract, config: config, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} } // CentrifugeID sets the CentID to the Identity @@ -222,7 +223,7 @@ func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int var keyFixed [32]byte copy(keyFixed[:], key) - confirmations, err = setUpKeyRegisteredEventListener(id.config, id, keyPurpose, keyFixed, h.Number.Uint64()) + confirmations, err = id.setUpKeyRegisteredEventListener(id.config, id, keyPurpose, keyFixed, h.Number.Uint64()) if err != nil { wError := errors.Wrap(err, 1) log.Errorf("Failed to set up event listener for identity [id: %s]: %v", id, wError) @@ -298,13 +299,13 @@ func sendIdentityCreationTransaction(identityFactory factory, opts *bind.Transac } // setUpKeyRegisteredEventListener listens for Identity creation -func setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { +func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) centId := identity.CentID() if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(keyRegistrationConfirmationTaskName, + asyncRes, err := id.queue.EnqueueJob(keyRegistrationConfirmationTaskName, map[string]interface{}{ centIDParam: centId, keyParam: key, @@ -320,13 +321,13 @@ func setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpos // setUpRegistrationEventListener sets up the listened for the "IdentityCreated" event to notify the upstream code about successful mining/creation // of the identity. -func setUpRegistrationEventListener(config Config, identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { +func (ids *EthereumIdentityService) setUpRegistrationEventListener(config Config, identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) bCentId := identityToBeCreated.CentID() if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, queue.BlockHeightParam: blockHeight}) + asyncRes, err := ids.queue.EnqueueJob(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, queue.BlockHeightParam: blockHeight}) if err != nil { return nil, err } @@ -335,13 +336,13 @@ func setUpRegistrationEventListener(config Config, identityToBeCreated Identity, } // waitAndRouteKeyRegistrationEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { +func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { _, err := asyncRes.Get(timeout) confirmations <- &WatchIdentity{Identity: pushThisIdentity, Error: err} } // waitAndRouteIdentityRegistrationEvent notifies the confirmations channel whenever the identity creation is being noted as Ethereum event -func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { +func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { _, err := asyncRes.Get(timeout) confirmations <- &WatchIdentity{pushThisIdentity, err} } @@ -353,13 +354,15 @@ type EthereumIdentityService struct { registryContract registry gethClientFinder func() ethereum.Client contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) + queue *queue.Server } // NewEthereumIdentityService creates a new NewEthereumIdentityService given the config and the smart contracts func NewEthereumIdentityService(config Config, factoryContract factory, registryContract registry, + queue *queue.Server, gethClientFinder func() ethereum.Client, contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) Service { - return &EthereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider} + return &EthereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} } // CheckIdentityExists checks if the identity represented by id actually exists on ethereum @@ -389,7 +392,7 @@ func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (ex // CreateIdentity creates an identity representing the id on ethereum func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) - id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.gethClientFinder, ids.contractProvider) + id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider) conn := ids.gethClientFinder() opts, err := conn.GetTxOpts(ids.config.GetEthereumDefaultAccountName()) if err != nil { @@ -401,7 +404,7 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden return nil, confirmations, err } - confirmations, err = setUpRegistrationEventListener(ids.config, id, h.Number.Uint64()) + confirmations, err = ids.setUpRegistrationEventListener(ids.config, id, h.Number.Uint64()) if err != nil { wError := errors.Wrap(err, 1) log.Infof("Failed to set up event listener for identity [mockID: %s]: %v", id, wError) @@ -442,7 +445,7 @@ func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Id if err != nil { return nil, err } - return newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.gethClientFinder, ids.contractProvider), nil + return newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider), nil } // GetClientP2PURL returns the p2p url associated with the centID diff --git a/identity/ethereum_identity_test.go b/identity/ethereum_identity_test.go index 48e818c69..93f1be764 100644 --- a/identity/ethereum_identity_test.go +++ b/identity/ethereum_identity_test.go @@ -108,7 +108,7 @@ func TestGetClientP2PURL_happy(t *testing.T) { g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -127,7 +127,7 @@ func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -148,7 +148,7 @@ func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, errors.New("p2p key error")) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -168,7 +168,7 @@ func TestGetIdentityKey_fail_lookup(t *testing.T) { c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -198,7 +198,7 @@ func TestGetIdentityKey_fail_FetchKey(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeP2P)}, big.NewInt(1), }, errors.New("p2p key error")) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -228,7 +228,7 @@ func TestGetIdentityKey_fail_empty(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeP2P)}, big.NewInt(1), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -258,7 +258,7 @@ func TestGetIdentityKey_Success(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeP2P)}, big.NewInt(1), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -289,7 +289,7 @@ func TestValidateKey_success(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeSigning)}, big.NewInt(0), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -319,7 +319,7 @@ func TestValidateKey_fail_getId(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeSigning)}, big.NewInt(0), }, errors.New("Key error")) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -347,7 +347,7 @@ func TestValidateKey_fail_mismatch_key(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeSigning)}, big.NewInt(0), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -377,7 +377,7 @@ func TestValidateKey_fail_missing_purpose(t *testing.T) { nil, big.NewInt(0), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -407,7 +407,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeP2P)}, big.NewInt(0), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil @@ -437,7 +437,7 @@ func TestValidateKey_fail_revocation(t *testing.T) { []*big.Int{big.NewInt(KeyPurposeSigning)}, big.NewInt(1), }, nil) - srv := NewEthereumIdentityService(c, f, r, func() ethereum.Client { + srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { return g }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil diff --git a/identity/id_registration_confirmation_task.go b/identity/id_registration_confirmation_task.go index 370d5fab3..7e0a17e0c 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/id_registration_confirmation_task.go @@ -44,17 +44,11 @@ func newIdRegistrationConfirmationTask( } } -// Name returns the name of the task -func (rct *idRegistrationConfirmationTask) Name() string { +// TaskTypeName returns the name of the task +func (rct *idRegistrationConfirmationTask) TaskTypeName() string { return idRegistrationConfirmationTaskName } -// Init registers the task to queue -func (rct *idRegistrationConfirmationTask) Init() error { - queue.Queue.Register(idRegistrationConfirmationTaskName, rct) - return nil -} - // Copy returns a new copy of the the task func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &idRegistrationConfirmationTask{ diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index 5003f773f..0675dbda6 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -40,12 +40,14 @@ type keyRegistrationConfirmationTask struct { config Config gethClientFinder func() ethereum.Client contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) + queue *queue.Server } func newKeyRegistrationConfirmationTask( ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), registryContract *EthereumIdentityRegistryContract, config Config, + queue *queue.Server, gethClientFinder func() ethereum.Client, contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error), ) *keyRegistrationConfirmationTask { @@ -53,23 +55,18 @@ func newKeyRegistrationConfirmationTask( contextInitializer: ethContextInitializer, contract: registryContract, config: config, + queue: queue, timeout: config.GetEthereumContextWaitTimeout(), gethClientFinder: gethClientFinder, contractProvider: contractProvider, } } -// Name returns keyRegistrationConfirmationTaskName -func (krct *keyRegistrationConfirmationTask) Name() string { +// TaskTypeName returns keyRegistrationConfirmationTaskName +func (krct *keyRegistrationConfirmationTask) TaskTypeName() string { return keyRegistrationConfirmationTaskName } -// Init registers task with the queue -func (krct *keyRegistrationConfirmationTask) Init() error { - queue.Queue.Register(keyRegistrationConfirmationTaskName, krct) - return nil -} - // Copy returns a new copy of the task func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &keyRegistrationConfirmationTask{ @@ -84,7 +81,9 @@ func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) krct.contract, krct.config, krct.gethClientFinder, - krct.contractProvider}, nil + krct.contractProvider, + krct.queue, + }, nil } // ParseKwargs parses the args into the task @@ -147,7 +146,7 @@ func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { krct.ctx, _ = krct.contextInitializer(krct.timeout) } - id := newEthereumIdentity(krct.centID, krct.contract, krct.config, krct.gethClientFinder, krct.contractProvider) + id := newEthereumIdentity(krct.centID, krct.contract, krct.config, krct.queue, krct.gethClientFinder, krct.contractProvider) contract, err := id.getContract() if err != nil { return nil, err diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 8040148d4..ab8c215a1 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -37,6 +38,14 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("identity service not initialised") } - ctx[BootstrappedPayObService] = NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, setupMintListener, bindContract) - return queue.InstallQueuedTask(ctx, newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext)) + if _, ok := ctx[bootstrap.BootstrappedQueueServer]; !ok { + return errors.New("queue hasn't been initialized") + } + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + + ctx[BootstrappedPayObService] = NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, queueSrv, setupMintListener, bindContract) + // queue task + task := newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext) + queueSrv.RegisterTaskType(task.TaskTypeName(), task) + return nil } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 734e5cb47..32ed55795 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -8,8 +8,6 @@ import ( "regexp" - "github.com/centrifuge/gocelery" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -53,13 +51,15 @@ type ethereumPaymentObligation struct { identityService identity.Service ethClient ethereum.Client config Config - setupMintListener func(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) + queue *queue.Server + setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) } // NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters func NewEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, - setupMintListener func(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { + queue *queue.Server, + setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ registry: registry, identityService: identityService, @@ -67,6 +67,7 @@ func NewEthereumPaymentObligation(registry *documents.ServiceRegistry, identityS config: config, setupMintListener: setupMintListener, bindContract: bindContract, + queue: queue, } } @@ -139,7 +140,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, return nil, err } - watch, err := s.setupMintListener(s.config, requestData.TokenID, registryAddress) + watch, err := s.setupMintListener(s.config, s.queue, requestData.TokenID, registryAddress) if err != nil { return nil, err } @@ -154,7 +155,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, // setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code // about successful minting of an NFt -func setupMintListener(config Config, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { +func setupMintListener(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { confirmations = make(chan *WatchTokenMinted) conn := ethereum.GetClient() @@ -162,7 +163,7 @@ func setupMintListener(config Config, tokenID *big.Int, registryAddress string) if err != nil { return nil, err } - asyncRes, err := queue.Queue.DelayKwargs(mintingConfirmationTaskName, map[string]interface{}{ + asyncRes, err := qs.EnqueueJob(mintingConfirmationTaskName, map[string]interface{}{ tokenIDParam: hex.EncodeToString(tokenID.Bytes()), queue.BlockHeightParam: h.Number.Uint64(), registryAddressParam: registryAddress, @@ -176,7 +177,7 @@ func setupMintListener(config Config, tokenID *big.Int, registryAddress string) } // waitAndRouteNFTApprovedEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes *gocelery.AsyncResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { +func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes queue.TaskResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { _, err := asyncRes.Get(timeout) confirmations <- &WatchTokenMinted{tokenID, err} } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 21b581ec8..2b6e3a605 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -14,6 +14,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -178,7 +179,7 @@ func TestPaymentObligationService(t *testing.T) { // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) confirmations := make(chan *WatchTokenMinted) - service := NewEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, func(config Config, tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { + service := NewEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, nil, func(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { return confirmations, nil }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 25d4ca2cf..44624156c 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -52,17 +52,11 @@ func newMintingConfirmationTask( } } -// Name returns mintingConfirmationTaskName -func (nftc *mintingConfirmationTask) Name() string { +// TaskTypeName returns mintingConfirmationTaskName +func (nftc *mintingConfirmationTask) TaskTypeName() string { return mintingConfirmationTaskName } -// Init registers the task to the queue -func (nftc *mintingConfirmationTask) Init() error { - queue.Queue.Register(mintingConfirmationTaskName, nftc) - return nil -} - // Copy returns a new instance of mintingConfirmationTask func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &mintingConfirmationTask{ diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index f95c8bbbf..1ff28459f 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -5,6 +5,7 @@ package nft_test import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/documents" diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 1fd0488db..8b9348a84 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -43,16 +43,20 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { func getServers(ctx map[string]interface{}) ([]Server, error) { p2pSrv, ok := ctx[bootstrap.BootstrappedP2PServer] if !ok { - return nil, fmt.Errorf("p2p server not initialised") + return nil, fmt.Errorf("p2p server not initialized") } apiSrv, ok := ctx[bootstrap.BootstrappedAPIServer] if !ok { - return nil, fmt.Errorf("API server not initiliase") + return nil, fmt.Errorf("API server not initialized") + } + + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer] + if !ok { + return nil, fmt.Errorf("queue server not initialized") } var servers []Server - servers = append(servers, p2pSrv.(Server)) - servers = append(servers, apiSrv.(Server)) + servers = append(servers, p2pSrv.(Server), apiSrv.(Server), queueSrv.(Server)) return servers, nil } diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index dbe3d4106..10b67f834 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -3,41 +3,21 @@ package queue import ( "errors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" ) -const BootstrappedQueuedTasks string = "BootstrappedQueuedTasks" - type Bootstrapper struct { + context map[string]interface{} } -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { +func (b *Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } cfg := context[config.BootstrappedConfig].(*config.Configuration) - // to see how BootstrappedQueuedTasks get populated check usages of InstallQueuedTask - if queuedTasks, ok := context[BootstrappedQueuedTasks]; ok { - if queuedTasksTyped, ok := queuedTasks.([]QueuedTask); ok { - InitQueue(queuedTasksTyped, cfg.GetNumWorkers(), cfg.GetWorkerWaitTimeMS()) - return nil - } - } - return errors.New("could not find the list of " + BootstrappedQueuedTasks) -} - -// InstallQueuedTask adds a queued task to the context so that when the queue initializes it can update it self -// with different tasks types queued in the node -func InstallQueuedTask(context map[string]interface{}, queuedTask QueuedTask) error { - if queuedTasks, ok := context[BootstrappedQueuedTasks]; ok { - if queuedTasksTyped, ok := queuedTasks.([]QueuedTask); ok { - context[BootstrappedQueuedTasks] = append(queuedTasksTyped, queuedTask) - return nil - } else { - return errors.New(BootstrappedQueuedTasks + " is of an unexpected type") - } - } else { - context[BootstrappedQueuedTasks] = []QueuedTask{queuedTask} - return nil - } + srv := &Server{config: cfg, taskTypes: []TaskType{}} + context[bootstrap.BootstrappedQueueServer] = srv + b.context = context + return nil } diff --git a/queue/bootstrapper_test.go b/queue/bootstrapper_test.go deleted file mode 100644 index b7c1dbc06..000000000 --- a/queue/bootstrapper_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// +build unit - -package queue - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -type MockQueuedTask struct{} - -func (MockQueuedTask) Name() string { - return "MockTask" -} - -func (MockQueuedTask) Init() error { - return nil -} - -func TestInstallQueuedTaskCreatingNewListOfTasks(t *testing.T) { - context := map[string]interface{}{} - err := InstallQueuedTask(context, MockQueuedTask{}) - assert.Nil(t, err, "Installation of tasks should be successful") - assert.Equal(t, 1, len(context[BootstrappedQueuedTasks].([]QueuedTask))) -} - -func TestInstallQueuedTaskappendingToListOfTasks(t *testing.T) { - queuedTasks := []QueuedTask{MockQueuedTask{}} - context := map[string]interface{}{BootstrappedQueuedTasks: queuedTasks} - err := InstallQueuedTask(context, MockQueuedTask{}) - assert.Nil(t, err, "Installation of tasks should be successful") - assert.Equal(t, 2, len(context[BootstrappedQueuedTasks].([]QueuedTask))) -} - -func TestInstallQueuedTaskQueuedTasksListHasInvalidType(t *testing.T) { - err := InstallQueuedTask(map[string]interface{}{BootstrappedQueuedTasks: 1}, MockQueuedTask{}) - assert.NotNil(t, err, "Installation of tasks should NOT be successful") -} diff --git a/queue/queue.go b/queue/queue.go deleted file mode 100644 index a80cf887e..000000000 --- a/queue/queue.go +++ /dev/null @@ -1,69 +0,0 @@ -package queue - -import ( - "sync" - - "errors" - "time" - - "github.com/centrifuge/gocelery" -) - -const ( - BlockHeightParam string = "BlockHeight" - TimeoutParam string = "Timeout" -) - -var Queue *gocelery.CeleryClient -var queueInit sync.Once - -// QueuedTask is a task to be queued in the centrifuge node to be completed asynchronously -type QueuedTask interface { - Name() string - Init() error -} - -func InitQueue(tasks []QueuedTask, numWorkers, workerWaitTime int) { - queueInit.Do(func() { - var err error - Queue, err = gocelery.NewCeleryClient( - gocelery.NewInMemoryBroker(), - gocelery.NewInMemoryBackend(), - numWorkers, - workerWaitTime, - ) - if err != nil { - panic("Could not initialize the queue") - } - for _, task := range tasks { - task.Init() - } - Queue.StartWorker() - }) -} - -func StopQueue() { - Queue.StopWorker() -} - -// GetDuration parses key parameter to time.Duration type -func GetDuration(key interface{}) (time.Duration, error) { - f64, ok := key.(float64) - if !ok { - return time.Duration(0), errors.New("Could not parse interface to float64") - } - return time.Duration(f64), nil -} - -// ParseBlockHeight parses blockHeight interface param to uint64 -func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[BlockHeightParam]; ok { - bhf, ok := bhi.(float64) - if ok { - return uint64(bhf), nil - } else { - return 0, errors.New("value can not be parsed") - } - } - return 0, errors.New("value can not be parsed") -} diff --git a/queue/server.go b/queue/server.go new file mode 100644 index 000000000..c79e445b1 --- /dev/null +++ b/queue/server.go @@ -0,0 +1,121 @@ +package queue + +import ( + "sync" + + "context" + "errors" + "time" + + "github.com/centrifuge/gocelery" + logging "github.com/ipfs/go-log" +) + +const ( + BlockHeightParam string = "BlockHeight" + TimeoutParam string = "Timeout" +) + +var log = logging.Logger("queue-server") + +// Config is an interface for queue specific configurations +type Config interface { + + // GetNumWorkers gets the number of background workers to initiate + GetNumWorkers() int + + // GetWorkerWaitTime gets the worker wait time for a task to be available while polling + // increasing this may slow down task execution while reducing it may consume a lot of CPU cycles + GetWorkerWaitTimeMS() int +} + +// TaskType is a task to be queued in the centrifuge node to be completed asynchronously +type TaskType interface { + + // TaskTypeName of the task + TaskTypeName() string +} + +// TaskResult represents a result from a queued task execution +type TaskResult interface { + + // Get the result within a timeout from the queue task execution + Get(timeout time.Duration) (interface{}, error) +} + +// Server represents the queue server currently implemented based on gocelery +type Server struct { + config Config + lock sync.RWMutex + queue *gocelery.CeleryClient + taskTypes []TaskType +} + +// TaskTypeName of the queue server +func (qs *Server) Name() string { + return "QueueServer" +} + +// Start the queue server +func (qs *Server) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { + defer wg.Done() + qs.lock.Lock() + var err error + qs.queue, err = gocelery.NewCeleryClient( + gocelery.NewInMemoryBroker(), + gocelery.NewInMemoryBackend(), + qs.config.GetNumWorkers(), + qs.config.GetWorkerWaitTimeMS(), + ) + if err != nil { + startupErr <- err + } + for _, task := range qs.taskTypes { + qs.queue.Register(task.TaskTypeName(), task) + } + // start the workers + qs.queue.StartWorker() + qs.lock.Unlock() + + <-ctx.Done() + log.Info("Shutting down Queue server with context done") + qs.lock.Lock() + qs.queue.StopWorker() + qs.lock.Unlock() + log.Info("Queue server stopped") +} + +// RegisterTaskType registers a task type on the queue server +func (qs *Server) RegisterTaskType(name string, task interface{}) { + qs.taskTypes = append(qs.taskTypes, task.(TaskType)) +} + +// EnqueueJob enqueues a job on the queue server for the given taskTypeName +func (qs *Server) EnqueueJob(taskTypeName string, params map[string]interface{}) (TaskResult, error) { + qs.lock.RLock() + defer qs.lock.RUnlock() + if qs.queue == nil { + return nil, errors.New("queue hasn't been initialised") + } + return qs.queue.DelayKwargs(taskTypeName, params) +} + +// GetDuration parses key parameter to time.Duration type +func GetDuration(key interface{}) (time.Duration, error) { + f64, ok := key.(float64) + if !ok { + return time.Duration(0), errors.New("Could not parse interface to float64") + } + return time.Duration(f64), nil +} + +// ParseBlockHeight parses blockHeight interface param to uint64 +func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { + if bhi, ok := valMap[BlockHeightParam]; ok { + bhf, ok := bhi.(float64) + if ok { + return uint64(bhf), nil + } + } + return 0, errors.New("value can not be parsed") +} diff --git a/queue/test_bootstrapper.go b/queue/test_bootstrapper.go index fab8ade08..b36bad946 100644 --- a/queue/test_bootstrapper.go +++ b/queue/test_bootstrapper.go @@ -2,11 +2,38 @@ package queue +import ( + "context" + "sync" + + "github.com/centrifuge/go-centrifuge/bootstrap" +) + func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { return b.Bootstrap(context) } func (b *Bootstrapper) TestTearDown() error { - StopQueue() + return nil +} + +type Starter struct { + canF context.CancelFunc +} + +func (s *Starter) TestBootstrap(ctx map[string]interface{}) error { + // handle the special case for running the queue server after task types have been registered (done by node bootstrapper at runtime) + qs := ctx[bootstrap.BootstrappedQueueServer].(*Server) + childErr := make(chan error) + var wg sync.WaitGroup + wg.Add(1) + c, canF := context.WithCancel(context.Background()) + s.canF = canF + go qs.Start(c, &wg, childErr) + return nil +} + +func (s *Starter) TestTearDown() error { + s.canF() return nil } From 4a1e3613b97cf5f385e0a52189e0f6ff968a2a09 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 26 Nov 2018 17:27:04 +0100 Subject: [PATCH 044/220] Add linting checks (#479) Changes: - Added gometalinter - following checks are enabled: goimport, vet, staticcheck, nakedret Following changes are suggested by these linters. We still need to add few more linters which we can do on a regular basis. Fixes #475 --- .travis.yml | 2 +- Makefile | 7 +- anchors/anchor.go | 3 +- anchors/anchor_confirmation_task.go | 45 +++++----- anchors/anchor_confirmation_task_test.go | 44 ++++----- anchors/anchor_repository.go | 6 +- anchors/bootstrapper.go | 3 +- anchors/ethereum_anchor_repository.go | 89 +++++++++---------- anchors/ethereum_anchor_repository_test.go | 2 +- api/insecure.go | 4 +- api/server.go | 7 +- bootstrap/bootstrapper.go | 1 + cmd/create_config.go | 12 +-- cmd/manage_identities.go | 18 ++-- config/bootstrapper.go | 5 +- config/configuration.go | 79 ++++++++-------- config/configuration_test.go | 4 +- config/test_bootstrapper.go | 2 +- context/bootstrapper.go | 6 +- coredocument/coredocument.go | 5 +- coredocument/processor.go | 1 + documents/bootstrapper.go | 1 + documents/error.go | 6 +- documents/handler.go | 4 +- documents/handler_test.go | 6 +- documents/invoice/bootstrapper.go | 3 +- documents/invoice/model.go | 4 +- documents/invoice/service.go | 10 +-- documents/invoice/service_test.go | 14 +-- documents/model_test.go | 4 +- documents/purchaseorder/bootstrapper.go | 7 +- documents/purchaseorder/model.go | 2 +- documents/purchaseorder/model_test.go | 7 +- documents/purchaseorder/service.go | 10 +-- documents/purchaseorder/service_test.go | 14 +-- documents/service.go | 4 +- documents/test_bootstrapper.go | 4 +- ethereum/bootstrapper.go | 3 + ethereum/geth_client.go | 2 +- ethereum/geth_client_test.go | 4 +- header/context.go | 12 +-- healthcheck/handler.go | 1 + identity/bootstrapper.go | 6 +- identity/ethereum_identity.go | 39 ++++---- identity/id_registration_confirmation_task.go | 21 ++--- .../id_registration_confirmation_task_test.go | 2 +- identity/identity.go | 29 +++--- identity/identity_test.go | 2 +- .../key_registration_confirmation_task.go | 18 ++-- ...key_registration_confirmation_task_test.go | 4 +- keytools/ed25519/ed25519.go | 12 +-- keytools/generate.go | 1 + keytools/keytools.go | 4 +- keytools/secp256k1/secp256k1.go | 51 +++++------ keytools/sign.go | 12 ++- keytools/verify.go | 8 +- nft/bootstrapper.go | 7 +- nft/ethereum_payment_obligation.go | 27 +++--- nft/ethereum_payment_obligation_test.go | 8 +- nft/handler_test.go | 10 +-- nft/minting_confirmation_task.go | 17 ++-- nft/minting_confirmation_task_test.go | 4 +- nft/payment_obligation.go | 4 +- node/bootstrapper.go | 8 +- node/node.go | 5 +- notification/notification.go | 31 +++++-- notification/notification_test.go | 2 +- p2p/bootstrapper.go | 5 +- p2p/bootstrapper_test.go | 3 +- p2p/client.go | 21 ++--- p2p/server.go | 11 ++- p2p/validator.go | 1 + queue/bootstrapper.go | 2 + queue/server.go | 8 +- storage/bootstrapper.go | 10 ++- storage/leveldb.go | 2 +- storage/test_bootstrapper.go | 2 +- utils/constants.go | 1 + utils/events.go | 8 +- utils/events_test.go | 2 +- utils/httputils.go | 15 +--- utils/time.go | 1 + utils/tools.go | 21 +++-- version/bootstrapper.go | 5 +- version/check.go | 2 +- version/version.go | 3 +- 86 files changed, 479 insertions(+), 443 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b69ec4bb..289afb818 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ jobs: include: - stage: test script: - - make proto-lint proto-all gen-swagger generate format-go + - make lint-check proto-lint proto-all gen-swagger generate format-go - echo "Checking that prototool and format-go don't result in a modified git tree" && git diff --exit-code protobufs/gen - ./build/scripts/test_wrapper.sh after_success: diff --git a/Makefile b/Makefile index 9bc0ace25..81ad72844 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,12 @@ install-deps: ## Install Dependencies @command -v dep >/dev/null 2>&1 || go get -u github.com/golang/dep/... @dep ensure @npm --prefix ./build install + @curl -L https://git.io/vp6lP | sh + @mv ./bin/* $(GOPATH)/bin/; rm -rf ./bin + +lint-check: ## formats go code + @gometalinter --disable-all --enable=golint --enable=goimports --enable=vet --enable=nakedret \ + --enable=staticcheck --vendor --skip=resources --skip=testingutils --skip=protobufs --deadline=1m ./...; format-go: ## formats go code @goimports -w . @@ -47,7 +53,6 @@ generate: ## autogenerate go files for config vendorinstall: ## Installs all protobuf dependencies with go-vendorinstall go install github.com/centrifuge/go-centrifuge/vendor/github.com/roboll/go-vendorinstall - go-vendorinstall golang.org/x/tools/cmd/goimports go-vendorinstall github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway go-vendorinstall github.com/golang/protobuf/protoc-gen-go go-vendorinstall github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger diff --git a/anchors/anchor.go b/anchors/anchor.go index 19f571f34..5bb046289 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -22,13 +22,14 @@ const ( // DocumentProofLength is the length in bytes of a single proof DocumentProofLength = 32 - //Supported anchor schema version as stored on public repository + // AnchorSchemaVersion as stored on public repository AnchorSchemaVersion uint = 1 ) // AnchorID type is byte array of length AnchorIDLength type AnchorID [AnchorIDLength]byte +// Config defines required functions for the package Anchors type Config interface { GetEthereumDefaultAccountName() string GetEthereumContextWaitTimeout() time.Duration diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index 820d8d43e..f977be8ee 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -17,19 +17,19 @@ import ( ) const ( - AnchorRepositoryConfirmationTaskName string = "AnchorRepositoryConfirmationTaskName" - AnchorIDParam string = "AnchorIDParam" - CentrifugeIDParam string = "CentrifugeIDParam" - BlockHeight string = "BlockHeight" - AddressParam string = "AddressParam" + anchorRepositoryConfirmationTaskName string = "anchorRepositoryConfirmationTaskName" + anchorIDParam string = "anchorIDParam" + centIDParam string = "centIDParam" + blockHeight string = "blockHeight" + addressParam string = "addressParam" ) type anchorCommittedWatcher interface { FilterAnchorCommitted( opts *bind.FilterOpts, from []common.Address, - anchorId []*big.Int, - centrifugeId []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) + anchorID []*big.Int, + centID []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) } // anchorConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumAnchoryRepositoryContract. @@ -48,9 +48,9 @@ type anchorConfirmationTask struct { AnchorCommittedFilterer anchorCommittedWatcher } -// TaskTypeName returns AnchorRepositoryConfirmationTaskName +// TaskTypeName returns anchorRepositoryConfirmationTaskName func (act *anchorConfirmationTask) TaskTypeName() string { - return AnchorRepositoryConfirmationTaskName + return anchorRepositoryConfirmationTaskName } // Copy returns a new instance of anchorConfirmationTask @@ -69,49 +69,49 @@ func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { // ParseKwargs parses args to anchorConfirmationTask func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - anchorID, ok := kwargs[AnchorIDParam] + anchorID, ok := kwargs[anchorIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + AnchorIDParam) + return fmt.Errorf("undefined kwarg " + anchorIDParam) } anchorIDBytes, err := getBytesAnchorID(anchorID) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", AnchorIDParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", anchorIDParam, err.Error()) } act.AnchorID = anchorIDBytes //parse the centrifuge id - centID, ok := kwargs[CentrifugeIDParam] + centID, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + CentrifugeIDParam) + return fmt.Errorf("undefined kwarg " + centIDParam) } centIDBytes, err := getBytesCentrifugeID(centID) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", CentrifugeIDParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } act.CentrifugeID = centIDBytes // parse the address - address, ok := kwargs[AddressParam] + address, ok := kwargs[addressParam] if !ok { - return fmt.Errorf("undefined kwarg " + AddressParam) + return fmt.Errorf("undefined kwarg " + addressParam) } addressStr, ok := address.(string) if !ok { - return fmt.Errorf("param is not hex string " + AddressParam) + return fmt.Errorf("param is not hex string " + addressParam) } addressTyped, err := getAddressFromHexString(addressStr) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", AddressParam, err.Error()) + return fmt.Errorf("malformed kwarg [%s] because [%s]", addressParam, err.Error()) } act.From = addressTyped - if bhi, ok := kwargs[BlockHeight]; ok { + if bhi, ok := kwargs[blockHeight]; ok { bhf, ok := bhi.(float64) if ok { act.BlockHeight = uint64(bhf) @@ -160,13 +160,12 @@ func (act *anchorConfirmationTask) RunTask() (interface{}, error) { return iter.Event, nil } - if err != utils.EventNotFound { + if err != utils.ErrEventNotFound { return nil, err } + time.Sleep(100 * time.Millisecond) } - - return nil, fmt.Errorf("failed to filter anchor events") } func getBytesAnchorID(key interface{}) (AnchorID, error) { diff --git a/anchors/anchor_confirmation_task_test.go b/anchors/anchor_confirmation_task_test.go index b925261d3..36427f161 100644 --- a/anchors/anchor_confirmation_task_test.go +++ b/anchors/anchor_confirmation_task_test.go @@ -39,17 +39,17 @@ func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) timeout := float64(5000) - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, - AddressParam: address, - CentrifugeIDParam: centId, - BlockHeight: float64(0), + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + anchorIDParam: anchorID, + addressParam: address, + centIDParam: centId, + blockHeight: float64(0), queue.TimeoutParam: timeout, }) err := act.ParseKwargs(kwargs) if err != nil { assert.Nil(t, err) - t.Fatalf("Could not parse %s or %s", AnchorIDParam, AddressParam) + t.Fatalf("Could not parse %s or %s", anchorIDParam, addressParam) } //convert byte 32 to big int @@ -64,9 +64,9 @@ func TestAnchoringConfirmationTask_ParseKwargsAnchorNotPassed(t *testing.T) { address := common.BytesToAddress([]byte{1, 2, 3, 4}) var centrifugeIdBytes [6]byte - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AddressParam: address, - CentrifugeIDParam: centrifugeIdBytes, + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + addressParam: address, + centIDParam: centrifugeIdBytes, }) err := act.ParseKwargs(kwargs) assert.NotNil(t, err, "Anchor id should not have been parsed") @@ -76,9 +76,9 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAnchor(t *testing.T) { act := anchorConfirmationTask{} anchorID := 123 address := common.BytesToAddress([]byte{1, 2, 3, 4}) - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, - AddressParam: address, + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + anchorIDParam: anchorID, + addressParam: address, }) err := act.ParseKwargs(kwargs) assert.NotNil(t, err, "Anchor id should not have been parsed because it was of incorrect type") @@ -87,8 +87,8 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAnchor(t *testing.T) { func TestAnchoringConfirmationTask_ParseKwargsAddressNotPassed(t *testing.T) { act := anchorConfirmationTask{} anchorID := [32]byte{1, 2, 3} - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + anchorIDParam: anchorID, }) err := act.ParseKwargs(kwargs) assert.NotNil(t, err, "address should not have been parsed") @@ -98,9 +98,9 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidAddress(t *testing.T) { act := anchorConfirmationTask{} anchorID := [32]byte{1, 2, 3} address := 123 - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, - AddressParam: address, + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + anchorIDParam: anchorID, + addressParam: address, }) err := act.ParseKwargs(kwargs) assert.NotNil(t, err, "address should not have been parsed because it was of incorrect type") @@ -113,11 +113,11 @@ func TestAnchoringConfirmationTask_ParseKwargsInvalidTimeout(t *testing.T) { centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) timeout := "int64" - kwargs, _ := utils.SimulateJsonDecodeForGocelery(map[string]interface{}{ - AnchorIDParam: anchorID, - AddressParam: address, - CentrifugeIDParam: centId, - BlockHeight: float64(0), + kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ + anchorIDParam: anchorID, + addressParam: address, + centIDParam: centId, + blockHeight: float64(0), queue.TimeoutParam: timeout, }) err := act.ParseKwargs(kwargs) diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index d127c81ef..ff1f9b176 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -10,9 +10,9 @@ import ( var log = logging.Logger("anchorRepository") // AnchorRepository defines a set of functions that can be -// implemented by any type that stores and retrieves the anchoring, and pre anchoring details +// implemented by any type that stores and retrieves the anchoring, and pre anchoring details. type AnchorRepository interface { - PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) - CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) + PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) + CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) } diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 1b4c99ba8..50c2dba17 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -12,9 +12,10 @@ import ( // BootstrappedAnchorRepo is used as a key to map the configured anchor repository through context. const BootstrappedAnchorRepo string = "BootstrappedAnchorRepo" +// Bootstrapper implements bootstrapper.Bootstrapper for package requirement initialisations. type Bootstrapper struct{} -// Bootstrap initializes the AnchorRepositoryContract as well as the anchorConfirmationTask that depends on it. +// Bootstrap initializes the anchorRepositoryContract as well as the anchorConfirmationTask that depends on it. // the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { if _, ok := ctx[config.BootstrappedConfig]; !ok { diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 59c7cd933..ddf7db2d1 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -16,51 +16,47 @@ import ( "github.com/go-errors/errors" ) -type AnchorRepositoryContract interface { - PreCommit(opts *bind.TransactOpts, anchorID *big.Int, signingRoot [32]byte, centrifugeId *big.Int, signature []byte, expirationBlock *big.Int) (*types.Transaction, error) - Commit(opts *bind.TransactOpts, _anchorID *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) +type anchorRepositoryContract interface { + PreCommit(opts *bind.TransactOpts, anchorID *big.Int, signingRoot [32]byte, centID *big.Int, signature []byte, expirationBlock *big.Int) (*types.Transaction, error) + Commit(opts *bind.TransactOpts, anchorID *big.Int, documentRoot [32]byte, centID *big.Int, documentProofs [][32]byte, signatures []byte) (*types.Transaction, error) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) } -type WatchAnchorPreCommitted interface { + +type watchAnchorPreCommitted interface { //event name: AnchorPreCommitted WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *EthereumAnchorRepositoryContractAnchorPreCommitted, from []common.Address, anchorID []*big.Int) (event.Subscription, error) } -type WatchAnchorCommitted interface { - //event name: AnchorCommitted - WatchAnchorCommitted(opts *bind.WatchOpts, sink chan<- *EthereumAnchorRepositoryContractAnchorCommitted, - from []common.Address, anchorID []*big.Int, centrifugeId []*big.Int) (event.Subscription, error) -} - -type EthereumAnchorRepository struct { +type ethereumAnchorRepository struct { config Config - anchorRepositoryContract AnchorRepositoryContract + anchorRepositoryContract anchorRepositoryContract gethClientFinder func() ethereum.Client queue *queue.Server } -func newEthereumAnchorRepository(config Config, anchorRepositoryContract AnchorRepositoryContract, queue *queue.Server, gethClientFinder func() ethereum.Client) *EthereumAnchorRepository { - return &EthereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder, queue: queue} +func newEthereumAnchorRepository(config Config, anchorRepositoryContract anchorRepositoryContract, queue *queue.Server, gethClientFinder func() ethereum.Client) AnchorRepository { + return ðereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder, queue: queue} } -// Commits takes an anchorID and returns the corresponding documentRoot from the chain -func (ethRepository *EthereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { +// GetDocumentRootOf takes an anchorID and returns the corresponding documentRoot from the chain. +func (ethRepository *ethereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := ethRepository.gethClientFinder().GetGethCallOpts() return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) } -//PreCommitAnchor will call the transaction PreCommit on the smart contract -func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centrifugeId identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { +// PreCommitAnchor will call the transaction PreCommit on the smart contract +func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { ethRepositoryContract := ethRepository.anchorRepositoryContract opts, err := ethereum.GetClient().GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { - return + return confirmations, err } - preCommitData := newPreCommitData(anchorID, signingRoot, centrifugeId, signature, expirationBlock) + + preCommitData := newPreCommitData(anchorID, signingRoot, centID, signature, expirationBlock) if err != nil { - return + return confirmations, err } err = sendPreCommitTransaction(ethRepositoryContract, opts, preCommitData) @@ -68,13 +64,14 @@ func (ethRepository *EthereumAnchorRepository) PreCommitAnchor(anchorID AnchorID wError := errors.Wrap(err, 1) log.Errorf("Failed to send Ethereum pre-commit transaction [id: %x, signingRoot: %x, SchemaVersion:%v]: %v", preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.SchemaVersion, wError) - return + return confirmations, err } + return confirmations, err } -// CommitAnchor will send a commit transaction to ethereum -func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centrifugeId identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { +// CommitAnchor will send a commit transaction to Ethereum. +func (ethRepository *ethereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { conn := ethereum.GetClient() opts, err := conn.GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) if err != nil { @@ -86,8 +83,9 @@ func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, d return nil, err } - cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, centrifugeId, documentProofs, signature) + cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, centID, documentProofs, signature) confirmations, err = ethRepository.setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) + if err != nil { wError := errors.Wrap(err, 1) log.Errorf("Failed to set up event listener for commit transaction [id: %x, hash: %x]: %v", @@ -105,8 +103,8 @@ func (ethRepository *EthereumAnchorRepository) CommitAnchor(anchorID AnchorID, d return confirmations, err } -// sendPreCommitTransaction sends the actual transaction to the ethereum node -func sendPreCommitTransaction(contract AnchorRepositoryContract, opts *bind.TransactOpts, preCommitData *PreCommitData) (err error) { +// sendPreCommitTransaction sends the actual transaction to the ethereum node. +func sendPreCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, preCommitData *PreCommitData) error { //preparation of data in specific types for the call to Ethereum schemaVersion := big.NewInt(int64(preCommitData.SchemaVersion)) @@ -115,30 +113,29 @@ func sendPreCommitTransaction(contract AnchorRepositoryContract, opts *bind.Tran preCommitData.CentrifugeID, preCommitData.Signature, preCommitData.ExpirationBlock, schemaVersion) if err != nil { - return - } else { - log.Infof("Sent off transaction pre-commit [id: %x, hash: %x, SchemaVersion:%v] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", preCommitData.AnchorID, - preCommitData.SigningRoot, schemaVersion, tx.Hash(), tx.Nonce(), tx.CheckNonce()) + return err } + log.Infof("Sent off transaction pre-commit [id: %x, hash: %x, SchemaVersion:%v] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", preCommitData.AnchorID, + preCommitData.SigningRoot, schemaVersion, tx.Hash(), tx.Nonce(), tx.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return + return nil } // sendCommitTransaction sends the actual transaction to register the Anchor on Ethereum registry contract -func sendCommitTransaction(contract AnchorRepositoryContract, opts *bind.TransactOpts, commitData *CommitData) (err error) { +func sendCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, commitData *CommitData) error { tx, err := ethereum.GetClient().SubmitTransactionWithRetries(contract.Commit, opts, commitData.AnchorID.BigInt(), commitData.DocumentRoot, commitData.CentrifugeID.BigInt(), commitData.DocumentProofs, commitData.Signature) if err != nil { return err - } else { - log.Infof("Sent off the anchor [id: %x, hash: %x] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", commitData.AnchorID, - commitData.DocumentRoot, tx.Hash(), tx.Nonce(), tx.CheckNonce()) } + log.Infof("Sent off the anchor [id: %x, hash: %x] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", commitData.AnchorID, + commitData.DocumentRoot, tx.Hash(), tx.Nonce(), tx.CheckNonce()) log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return + return nil } // TODO: This method is only used by setUpPreCommitEventListener below, it will be changed soon so we can remove the hardcoded `time.Second` and use the global one @@ -153,14 +150,14 @@ func generateEventContext() (*bind.WatchOpts, context.CancelFunc) { // setUpPreCommitEventListener sets up the listened for the "PreCommit" event to notify the upstream code // about successful mining/creation of a pre-commit. -func setUpPreCommitEventListener(contractEvent WatchAnchorPreCommitted, from common.Address, preCommitData *PreCommitData) (confirmations chan *WatchPreCommit, err error) { +func setUpPreCommitEventListener(contractEvent watchAnchorPreCommitted, from common.Address, preCommitData *PreCommitData) (confirmations chan *WatchPreCommit, err error) { watchOpts, cancelFunc := generateEventContext() //there should always be only one notification coming for this //single anchor being registered anchorPreCommittedEvents := make(chan *EthereumAnchorRepositoryContractAnchorPreCommitted) confirmations = make(chan *WatchPreCommit) - go waitAndRoutePreCommitEvent(anchorPreCommittedEvents, watchOpts.Context, confirmations, preCommitData) + go waitAndRoutePreCommitEvent(watchOpts.Context, anchorPreCommittedEvents, confirmations, preCommitData) // Somehow there are some possible resource leakage situations with this handling but I have to understand // Subscriptions a bit better before writing this code. @@ -176,13 +173,13 @@ func setUpPreCommitEventListener(contractEvent WatchAnchorPreCommitted, from com // setUpCommitEventListener sets up the listened for the "AnchorCommitted" event to notify the upstream code // about successful mining/creation of a commit -func (ethRepository *EthereumAnchorRepository) setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { +func (ethRepository *ethereumAnchorRepository) setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { confirmations = make(chan *WatchCommit) - asyncRes, err := ethRepository.queue.EnqueueJob(AnchorRepositoryConfirmationTaskName, map[string]interface{}{ - AnchorIDParam: commitData.AnchorID, - AddressParam: from, - CentrifugeIDParam: commitData.CentrifugeID, - BlockHeight: commitData.BlockHeight, + asyncRes, err := ethRepository.queue.EnqueueJob(anchorRepositoryConfirmationTaskName, map[string]interface{}{ + anchorIDParam: commitData.AnchorID, + addressParam: from, + centIDParam: commitData.CentrifugeID, + blockHeight: commitData.BlockHeight, }) if err != nil { return nil, err @@ -193,7 +190,7 @@ func (ethRepository *EthereumAnchorRepository) setUpCommitEventListener(timeout } // waitAndRoutePreCommitEvent notifies the confirmations channel whenever a pre-commit is being noted as Ethereum event -func waitAndRoutePreCommitEvent(conf <-chan *EthereumAnchorRepositoryContractAnchorPreCommitted, ctx context.Context, confirmations chan<- *WatchPreCommit, preCommitData *PreCommitData) { +func waitAndRoutePreCommitEvent(ctx context.Context, conf <-chan *EthereumAnchorRepositoryContractAnchorPreCommitted, confirmations chan<- *WatchPreCommit, preCommitData *PreCommitData) { for { select { case <-ctx.Done(): diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 38759e7e9..20d81a7e1 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -19,7 +19,7 @@ import ( type mockAnchorRepo struct { mock.Mock - AnchorRepositoryContract + anchorRepositoryContract } func (m *mockAnchorRepo) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) { diff --git a/api/insecure.go b/api/insecure.go index 342986937..e0f77cfc0 100644 --- a/api/insecure.go +++ b/api/insecure.go @@ -6,7 +6,7 @@ package api // Make sure you enter "localhost:8082" as the Common Name. const ( - InsecureKey = `-----BEGIN RSA PRIVATE KEY----- + insecureKey = `-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyEnDbL/RxZrgDN85W958GvCnWYfLIl/yf3OnzRpSlhz5oKg6 hnigQeUiFlU60p8vnTbjr4idoyobYCTvqRh6oZk8r1zJ4H2Kx3HIIAkSgu1jzPV/ QwwbA0O4cJ9RttS3vFf9bDoJ4T93t8JNuRgF0jrQX8zPn/22/g1BrrhIV5gp8pWD @@ -33,7 +33,7 @@ FsU0FQKBgDS5XqHLIuN8isp2uOYzOLUqafStV/qAzvx9Tv6PNgBWLFekz9xpfxux yaQJtUNTfTXQ6tMjUpAwJam/G1h7ZTNYj2iuDVNlAgpwP45SkxWQ2dJEwtAyooVe kkVOdXE61p7fxhigyBb77uoX3adz4ECr3ktbAL2a0Z1XG9oTa2LW -----END RSA PRIVATE KEY-----` - InsecureCert = `-----BEGIN CERTIFICATE----- + insecureCert = `-----BEGIN CERTIFICATE----- MIIDmDCCAoACCQDHr6ZuK9By7zANBgkqhkiG9w0BAQsFADCBjTELMAkGA1UEBhMC VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x GDAWBgNVBAoMD0NlbnRyaWZ1Z2UgSW5jLjESMBAGA1UEAwwJbG9jYWxob3N0MSMw diff --git a/api/server.go b/api/server.go index 3f7ac9202..9c351dc2b 100644 --- a/api/server.go +++ b/api/server.go @@ -6,7 +6,7 @@ import ( "errors" "net" "net/http" - _ "net/http/pprof" + _ "net/http/pprof" // we need this side effect that loads the pprof endpoints to defaultServerMux "strings" "sync" "time" @@ -21,6 +21,7 @@ import ( var log = logging.Logger("api-server") +// Config defines methods required for the package api type Config interface { GetServerAddress() string GetServerPort() int @@ -152,7 +153,7 @@ func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Ha func loadCertPool() (certPool *x509.CertPool, err error) { certPool = x509.NewCertPool() - ok := certPool.AppendCertsFromPEM([]byte(InsecureCert)) + ok := certPool.AppendCertsFromPEM([]byte(insecureCert)) if !ok { return nil, centerrors.Wrap(errors.New("could not load certpool"), "") } @@ -160,7 +161,7 @@ func loadCertPool() (certPool *x509.CertPool, err error) { } func loadKeyPair() (keyPair tls.Certificate, err error) { - pair, err := tls.X509KeyPair([]byte(InsecureCert), []byte(InsecureKey)) + pair, err := tls.X509KeyPair([]byte(insecureCert), []byte(insecureKey)) if err != nil { return pair, err } diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index f47ef2b86..8e4aaacb2 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -2,6 +2,7 @@ package bootstrap // DO NOT PUT any app logic in this package to avoid any dependency cycles +// Bootstrap constants are keys to mapped value in bootstrapped context const ( BootstrappedP2PServer string = "BootstrappedP2PServer" BootstrappedAPIServer string = "BootstrappedAPIServer" diff --git a/cmd/create_config.go b/cmd/create_config.go index 1426501ec..1fc73b559 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -11,7 +11,7 @@ import ( ) var targetDataDir string -var ethNodeUrl string +var ethNodeURL string var accountKeyPath string var accountPassword string var network string @@ -21,14 +21,14 @@ var bootstraps []string var txPoolAccess bool func createIdentity(idService identity.Service) (identity.CentID, error) { - centrifugeId := identity.RandomCentID() - _, confirmations, err := idService.CreateIdentity(centrifugeId) + centID := identity.RandomCentID() + _, confirmations, err := idService.CreateIdentity(centID) if err != nil { return [identity.CentIDLength]byte{}, err } _ = <-confirmations - return centrifugeId, nil + return centID, nil } func generateKeys(config config.Config) { @@ -73,7 +73,7 @@ func init() { "accountKeyPath": accountKeyPath, "accountPassword": accountPassword, "network": network, - "ethNodeUrl": ethNodeUrl, + "ethNodeURL": ethNodeURL, "bootstraps": bootstraps, "apiPort": apiPort, "p2pPort": p2pPort, @@ -113,7 +113,7 @@ func init() { } createConfigCmd.Flags().StringVarP(&targetDataDir, "targetdir", "t", home+"/datadir", "Target Data Dir") - createConfigCmd.Flags().StringVarP(ðNodeUrl, "ethnodeurl", "e", "ws://127.0.0.1:9546", "URL of Ethereum Client Node") + createConfigCmd.Flags().StringVarP(ðNodeURL, "ethnodeurl", "e", "ws://127.0.0.1:9546", "URL of Ethereum Client Node") createConfigCmd.Flags().StringVarP(&accountKeyPath, "accountkeypath", "z", home+"/datadir/main.key", "Path of Ethereum Account Key JSON file") createConfigCmd.Flags().StringVarP(&accountPassword, "accountpwd", "k", "", "Ethereum Account Password") createConfigCmd.Flags().Int64VarP(&apiPort, "apiPort", "a", 8082, "Api Port") diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index fd9436874..60f857e1d 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" ) -var centrifugeIdString string +var centIDString string var purpose string var createIdentityCmd = &cobra.Command{ @@ -18,19 +18,19 @@ var createIdentityCmd = &cobra.Command{ //cmd requires a config file cfgFile = ensureConfigFile() ctx := baseBootstrap(cfgFile) - var centrifugeId identity.CentID + var centID identity.CentID var err error - if centrifugeIdString == "" { - centrifugeId = identity.RandomCentID() + if centIDString == "" { + centID = identity.RandomCentID() } else { - centrifugeId, err = identity.CentIDFromString(centrifugeIdString) + centID, err = identity.CentIDFromString(centIDString) if err != nil { panic(err) } } idService := ctx[identity.BootstrappedIDService].(identity.Service) - _, confirmations, err := idService.CreateIdentity(centrifugeId) + _, confirmations, err := idService.CreateIdentity(centID) if err != nil { panic(err) } @@ -38,7 +38,7 @@ var createIdentityCmd = &cobra.Command{ log.Infof("Identity created [%s]", watchIdentity.Identity.CentID().String()) // We need a way to return the identity created so it can be read by an automated process as well // when id autogenerated - id := []byte("{\"id\": \"" + centrifugeId.String() + "\"}") + id := []byte("{\"id\": \"" + centID.String() + "\"}") err = ioutil.WriteFile("newidentity.json", id, 0644) if err != nil { panic(err) @@ -80,8 +80,8 @@ var addKeyCmd = &cobra.Command{ } func init() { - createIdentityCmd.Flags().StringVarP(¢rifugeIdString, "centrifugeid", "i", "", "Centrifuge ID") - addKeyCmd.Flags().StringVarP(¢rifugeIdString, "centrifugeid", "i", "", "Centrifuge ID") + createIdentityCmd.Flags().StringVarP(¢IDString, "centrifugeid", "i", "", "Centrifuge ID") + addKeyCmd.Flags().StringVarP(¢IDString, "centrifugeid", "i", "", "Centrifuge ID") addKeyCmd.Flags().StringVarP(&purpose, "purpose", "p", "", "Key Purpose [p2p|sign|ethauth]") rootCmd.AddCommand(createIdentityCmd) rootCmd.AddCommand(addKeyCmd) diff --git a/config/bootstrapper.go b/config/bootstrapper.go index ed30608a7..11e1a62db 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -4,18 +4,21 @@ import ( "errors" ) +// Bootstrap constants are keys to the value mappings in context bootstrap. const ( BootstrappedConfig string = "BootstrappedConfig" BootstrappedConfigFile string = "BootstrappedConfigFile" ) +// Bootstrapper implements bootstrap.Bootstrapper to initialise config package. type Bootstrapper struct{} +// Bootstrap takes the passed in config file, loads the config and puts the config back into context. func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[BootstrappedConfigFile]; !ok { return errors.New("config file hasn't been provided") } cfgFile := context[BootstrappedConfigFile].(string) - context[BootstrappedConfig] = NewConfiguration(cfgFile) + context[BootstrappedConfig] = LoadConfiguration(cfgFile) return nil } diff --git a/config/configuration.go b/config/configuration.go index e1dd0ef1f..87fd265fb 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -27,6 +27,7 @@ import ( var log = logging.Logger("config") +// Config defines the methods that a config type should implement. type Config interface { GetStoragePath() string GetP2PPort() int @@ -58,61 +59,62 @@ type Config interface { GetEthAuthKeyPair() (pub, priv string) } -// Configuration holds the configuration details for the node +// Configuration holds the configuration details for the node. type Configuration struct { mu sync.RWMutex configFile string v *viper.Viper } -// AccountConfig holds the account details +// AccountConfig holds the account details. type AccountConfig struct { Address string Key string Password string } -// IsSet check if the key is set in the config +// IsSet check if the key is set in the config. func (c *Configuration) IsSet(key string) bool { c.mu.RLock() defer c.mu.RUnlock() return c.v.IsSet(key) } -// Set update the key and the value it holds in the configuration +// Set update the key and the value it holds in the configuration. func (c *Configuration) Set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.v.Set(key, value) } +// SetDefault sets the default value for the given key. func (c *Configuration) SetDefault(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.v.SetDefault(key, value) } -// Get returns associated value for the key +// Get returns associated value for the key. func (c *Configuration) Get(key string) interface{} { return c.get(key) } -// GetString returns value string associated with key +// GetString returns value string associated with key. func (c *Configuration) GetString(key string) string { return cast.ToString(c.get(key)) } -// GetInt returns value int associated with key +// GetInt returns value int associated with key. func (c *Configuration) GetInt(key string) int { return cast.ToInt(c.get(key)) } -// GetBool returns value bool associated with key +// GetBool returns value bool associated with key. func (c *Configuration) GetBool(key string) bool { return cast.ToBool(c.get(key)) } -// GetDuration returns value duration associated with key +// GetDuration returns value duration associated with key. func (c *Configuration) GetDuration(key string) time.Duration { return cast.ToDuration(c.get(key)) } @@ -123,92 +125,92 @@ func (c *Configuration) get(key string) interface{} { return c.v.Get(key) } -// GetStoragePath returns the data storage backend +// GetStoragePath returns the data storage backend. func (c *Configuration) GetStoragePath() string { return c.GetString("storage.Path") } -// GetP2PPort returns P2P Port +// GetP2PPort returns P2P Port. func (c *Configuration) GetP2PPort() int { return c.GetInt("p2p.port") } -// GetP2PExternalIP returns P2P External IP +// GetP2PExternalIP returns P2P External IP. func (c *Configuration) GetP2PExternalIP() string { return c.GetString("p2p.externalIP") } -// GetP2PConnectionTimeout returns P2P Connect Timeout +// GetP2PConnectionTimeout returns P2P Connect Timeout. func (c *Configuration) GetP2PConnectionTimeout() time.Duration { return c.GetDuration("p2p.connectTimeout") } -//////////////////////////////////////////////////////////////////////////////// -// Notifications -//////////////////////////////////////////////////////////////////////////////// +// GetReceiveEventNotificationEndpoint returns the webhook endpoint defined in the config. func (c *Configuration) GetReceiveEventNotificationEndpoint() string { return c.GetString("notifications.endpoint") } -//////////////////////////////////////////////////////////////////////////////// -// Server -//////////////////////////////////////////////////////////////////////////////// - +// GetServerPort returns the defined server port in the config. func (c *Configuration) GetServerPort() int { return c.GetInt("nodePort") } +// GetServerAddress returns the defined server address of form host:port in the config. func (c *Configuration) GetServerAddress() string { return fmt.Sprintf("%s:%s", c.GetString("nodeHostname"), c.GetString("nodePort")) } -//////////////////////////////////////////////////////////////////////////////// -// Queuing -//////////////////////////////////////////////////////////////////////////////// - +// GetNumWorkers returns number of queue workers defined in the config. func (c *Configuration) GetNumWorkers() int { return c.GetInt("queue.numWorkers") } +// GetWorkerWaitTimeMS returns the queue worker sleep time between cycles. func (c *Configuration) GetWorkerWaitTimeMS() int { return c.GetInt("queue.workerWaitTimeMS") } -//////////////////////////////////////////////////////////////////////////////// -// Ethereum -//////////////////////////////////////////////////////////////////////////////// +// GetEthereumNodeURL returns the URL of the Ethereum Node. func (c *Configuration) GetEthereumNodeURL() string { return c.GetString("ethereum.nodeURL") } +// GetEthereumContextReadWaitTimeout returns the read duration to pass for context.Deadline. func (c *Configuration) GetEthereumContextReadWaitTimeout() time.Duration { return c.GetDuration("ethereum.contextReadWaitTimeout") } +// GetEthereumContextWaitTimeout returns the commit duration to pass for context.Deadline. func (c *Configuration) GetEthereumContextWaitTimeout() time.Duration { return c.GetDuration("ethereum.contextWaitTimeout") } +// GetEthereumIntervalRetry returns duration to wait between retries. func (c *Configuration) GetEthereumIntervalRetry() time.Duration { return c.GetDuration("ethereum.intervalRetry") } +// GetEthereumMaxRetries returns the max acceptable retries. func (c *Configuration) GetEthereumMaxRetries() int { return c.GetInt("ethereum.maxRetries") } +// GetEthereumGasPrice returns the gas price to use for a ethereum transaction. func (c *Configuration) GetEthereumGasPrice() *big.Int { return big.NewInt(cast.ToInt64(c.get("ethereum.gasPrice"))) } +// GetEthereumGasLimit returns the gas limit to use for a ethereum transaction. func (c *Configuration) GetEthereumGasLimit() uint64 { return cast.ToUint64(c.get("ethereum.gasLimit")) } +// GetEthereumDefaultAccountName returns the default account to use for the transaction. func (c *Configuration) GetEthereumDefaultAccountName() string { return c.GetString("ethereum.defaultAccountName") } +// GetEthereumAccount returns the account details associated with the account name. func (c *Configuration) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { k := fmt.Sprintf("ethereum.accounts.%s", accountName) @@ -226,18 +228,18 @@ func (c *Configuration) GetEthereumAccount(accountName string) (account *Account return account, nil } -// Important flag for concurrency handling. Disable if Ethereum client doesn't support txpool API (INFURA) +// GetTxPoolAccessEnabled returns if the node can check the txpool for nonce increment. +// Note:Important flag for concurrency handling. Disable if Ethereum client doesn't support txpool API (INFURA). func (c *Configuration) GetTxPoolAccessEnabled() bool { return c.GetBool("ethereum.txPoolAccessEnabled") } -//////////////////////////////////////////////////////////////////////////////// -// Network Configuration -//////////////////////////////////////////////////////////////////////////////// +// GetNetworkString returns defined network the node is connected to. func (c *Configuration) GetNetworkString() string { return c.GetString("centrifugeNetwork") } +// GetNetworkKey returns the specific key(k) value defined in the default network. func (c *Configuration) GetNetworkKey(k string) string { return fmt.Sprintf("networks.%s.%s", c.GetNetworkString(), k) } @@ -262,7 +264,7 @@ func (c *Configuration) GetNetworkID() uint32 { return uint32(c.GetInt(c.GetNetworkKey("id"))) } -// GetIdentityID returns the self centID +// GetIdentityID returns the self centID in bytes. func (c *Configuration) GetIdentityID() ([]byte, error) { id, err := hexutil.Decode(c.GetString("identityId")) if err != nil { @@ -271,10 +273,12 @@ func (c *Configuration) GetIdentityID() ([]byte, error) { return id, err } +// GetSigningKeyPair returns the signing key pair. func (c *Configuration) GetSigningKeyPair() (pub, priv string) { return c.GetString("keys.signing.publicKey"), c.GetString("keys.signing.privateKey") } +// GetEthAuthKeyPair returns ethereum key pair. func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { return c.GetString("keys.ethauth.publicKey"), c.GetString("keys.ethauth.privateKey") } @@ -284,8 +288,8 @@ func (c *Configuration) IsPProfEnabled() bool { return c.GetBool("debug.pprof") } -// Configuration Implementation -func NewConfiguration(configFile string) *Configuration { +// LoadConfiguration loads the configuration from the given file. +func LoadConfiguration(configFile string) *Configuration { cfg := &Configuration{configFile: configFile, mu: sync.RWMutex{}} cfg.InitializeViper() return cfg @@ -302,8 +306,9 @@ func (c *Configuration) readConfigFile(path string) error { return err } +// InitializeViper loads viper if not loaded already. +// This method should not have any effects if Viper is already initialized. func (c *Configuration) InitializeViper() { - // This method should not have any effects if Viper is already initialized. if c.v != nil { return } @@ -342,7 +347,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { accountKeyPath := args["accountKeyPath"].(string) accountPassword := args["accountPassword"].(string) network := args["network"].(string) - ethNodeUrl := args["ethNodeUrl"].(string) + ethNodeURL := args["ethNodeURL"].(string) bootstraps := args["bootstraps"].([]string) apiPort := args["apiPort"].(int64) p2pPort := args["p2pPort"].(int64) @@ -376,7 +381,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("nodeHostname", "0.0.0.0") v.Set("nodePort", apiPort) v.Set("p2p.port", p2pPort) - v.Set("ethereum.nodeURL", ethNodeUrl) + v.Set("ethereum.nodeURL", ethNodeURL) v.Set("ethereum.txPoolAccessEnabled", txPoolAccess) v.Set("ethereum.accounts.main.key", string(bfile)) v.Set("ethereum.accounts.main.password", accountPassword) diff --git a/config/configuration_test.go b/config/configuration_test.go index 8f597b8c4..62b786368 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -26,7 +26,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { "accountKeyPath": accountKeyPath, "accountPassword": "pwrd", "network": "russianhill", - "ethNodeUrl": "ws://127.0.0.1:9546", + "ethNodeURL": "ws://127.0.0.1:9546", "bootstraps": []string{"/ip4/127.0.0.1/bootstrap1", "/ip4/127.0.0.1/bootstrap2"}, "apiPort": int64(8082), "p2pPort": int64(38202), @@ -38,7 +38,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { assert.Equal(t, data["p2pPort"].(int64), v.GetInt64("p2p.port"), "p2p port match") _, err = os.Stat(targetDir + "/config.yaml") assert.Nil(t, err, "must be nil, config file should be created") - c := NewConfiguration(v.ConfigFileUsed()) + c := LoadConfiguration(v.ConfigFileUsed()) assert.False(t, c.IsPProfEnabled(), "pprof is disabled by default") os.Remove(targetDir) } diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 07019b9e9..2fa6e5ce6 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -21,7 +21,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { log.Fatal("Current working dir is not in `go-centrifuge`") } } - c := NewConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) + c := LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) context[BootstrappedConfig] = c return nil } diff --git a/context/bootstrapper.go b/context/bootstrapper.go index 33fb19567..a0274691c 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -21,10 +21,12 @@ import ( var log = logging.Logger("context") +// MainBootstrapper holds all the bootstrapper implementations type MainBootstrapper struct { Bootstrappers []bootstrap.Bootstrapper } +// PopulateBaseBootstrappers adds all the bootstrapper implementations to MainBootstrapper func (m *MainBootstrapper) PopulateBaseBootstrappers() { m.Bootstrappers = []bootstrap.Bootstrapper{ &version.Bootstrapper{}, @@ -43,12 +45,14 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { } } +// PopulateRunBootstrappers adds blocking Node bootstrapper at the end. +// Note: Node bootstrapper must be the last bootstrapper to be invoked as it won't return until node is shutdown func (m *MainBootstrapper) PopulateRunBootstrappers() { m.PopulateBaseBootstrappers() - // NODE BOOTSTRAPPER MUST BE THE LAST BOOTSTRAPPER TO BE INVOKED AS IT WON'T RETURN UNTIL NODE IS SHUTDOWN m.Bootstrappers = append(m.Bootstrappers, &node.Bootstrapper{}) } +// Bootstrap runs all the loaded bootstrapper implementations. func (m *MainBootstrapper) Bootstrap(context map[string]interface{}) error { for _, b := range m.Bootstrappers { err := b.Bootstrap(context) diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index c8d1e8893..0a5fedded 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -208,7 +208,7 @@ func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, return cd, nil } -// GetExternalCollaborators returns collaborators of a document without the own centID +// GetExternalCollaborators returns collaborators of a document without the own centID. func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.CoreDocument) ([][]byte, error) { var collabs [][]byte @@ -290,5 +290,6 @@ func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDoc proof.SortedHashes = append(proof.SortedHashes, rootHashes...) proofs = append(proofs, &proof) } - return + + return proofs, nil } diff --git a/coredocument/processor.go b/coredocument/processor.go index 43a759eab..1ba218133 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -18,6 +18,7 @@ import ( var log = logging.Logger("coredocument") +// Config defines required methods required for the coredocument package. type Config interface { GetNetworkID() uint32 GetIdentityID() ([]byte, error) diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 32b74aaf1..f810d8214 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -3,6 +3,7 @@ package documents // BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context const BootstrappedRegistry = "BootstrappedRegistry" +// Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} // Bootstrap sets the required storage and registers diff --git a/documents/error.go b/documents/error.go index 098220468..35a7e2822 100644 --- a/documents/error.go +++ b/documents/error.go @@ -18,13 +18,13 @@ func (e Error) Error() string { return e.err.Error() } -// New creates a new error from a key and a msg +// NewError creates a new error from a key and a msg. func NewError(key, msg string) error { err := fmt.Errorf(msg) return Error{key: key, err: err} } -// Append function is used to create a list of errors. +// AppendError function is used to create a list of errors. // First argument can be nil, a multierror.Error, or any other error func AppendError(dstErr, srcErr error) error { _, ok := dstErr.(*multierror.Error) @@ -69,7 +69,7 @@ func Errors(err error) []error { return []error{err} } -// Len returns the amount of embedded errors +// LenError returns the amount of embedded errors. func LenError(err error) int { if err == nil { diff --git a/documents/handler.go b/documents/handler.go index 3d4717581..1de7f848b 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -74,8 +74,8 @@ func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDo func ConvertDocProofToClientFormat(proof *DocumentProof) (*documentpb.DocumentProof, error) { return &documentpb.DocumentProof{ Header: &documentpb.ResponseHeader{ - DocumentId: hexutil.Encode(proof.DocumentId), - VersionId: hexutil.Encode(proof.VersionId), + DocumentId: hexutil.Encode(proof.DocumentID), + VersionId: hexutil.Encode(proof.VersionID), State: proof.State, }, FieldProofs: ConvertProofsToClientFormat(proof.FieldProofs)}, nil diff --git a/documents/handler_test.go b/documents/handler_test.go index 78808b7e3..0e0cb457d 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -80,7 +80,7 @@ func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { } id, _ := hexutil.Decode(req.Identifier) version, _ := hexutil.Decode(req.Version) - doc := &documents.DocumentProof{DocumentId: utils.RandomSlice(32)} + doc := &documents.DocumentProof{DocumentID: utils.RandomSlice(32)} service.On("CreateProofsForVersion", id, version, req.Fields).Return(doc, nil) grpcHandler := documents.GRPCHandler(registry) retDoc, _ := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) @@ -149,8 +149,8 @@ func TestConvertDocProofToClientFormat(t *testing.T) { { name: "happy", input: &documents.DocumentProof{ - DocumentId: []byte{1, 2, 1}, - VersionId: []byte{1, 2, 2}, + DocumentID: []byte{1, 2, 1}, + VersionID: []byte{1, 2, 2}, State: "state", FieldProofs: []*proofspb.Proof{ { diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index c40e0c38f..67c1405fe 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -14,6 +14,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage" ) +// Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} // Bootstrap sets the required storage and registers @@ -24,7 +25,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[storage.BootstrappedLevelDb]; !ok { + if _, ok := ctx[storage.BootstrappedLevelDB]; !ok { return errors.New("initializing LevelDB repository failed") } diff --git a/documents/invoice/model.go b/documents/invoice/model.go index e429f2fa7..46b61d912 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -268,6 +268,8 @@ func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) *invoicepb return i.InvoiceSalts } +// ID returns document identifier. +// Note: this is not a unique identifier for each version of the document. func (i *Invoice) ID() ([]byte, error) { coreDoc, err := i.PackCoreDocument() if err != nil { @@ -399,5 +401,5 @@ func (i *Invoice) createProofs(fields []string) (coreDoc *coredocumentpb.CoreDoc } proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) - return + return coreDoc, proofs, err } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 246198d99..f343c05d9 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -99,8 +99,8 @@ func (s service) invoiceProof(model documents.Model, fields []string) (*document return nil, err } return &documents.DocumentProof{ - DocumentId: coreDoc.DocumentIdentifier, - VersionId: coreDoc.CurrentVersion, + DocumentID: coreDoc.DocumentIdentifier, + VersionID: coreDoc.CurrentVersion, FieldProofs: proofs, }, nil } @@ -219,10 +219,10 @@ func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err temp, err := s.getInvoiceVersion(documentID, nextVersion) if err != nil { return inv, nil - } else { - inv = temp - nextVersion = inv.CoreDocument.NextVersion } + + inv = temp + nextVersion = inv.CoreDocument.NextVersion } return inv, nil } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 64db7ef9e..7703889db 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -315,8 +315,8 @@ func TestService_CreateProofs(t *testing.T) { idService = mockSignatureCheck(i, idService, invSrv) proof, err := invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionId) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") } @@ -361,8 +361,8 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Nil(t, err) proof, err := invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) - assert.Equal(t, olderVersion, proof.VersionId) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") } @@ -413,13 +413,13 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { centID, err := identity.ToCentID(centIDBytes) assert.Nil(t, err) - signKey := identity.IdentityKey{ + signKey := identity.IDKey{ PublicKey: key1Pub[:], PrivateKey: key1, } - idConfig := &identity.IdentityConfig{ + idConfig := &identity.IDConfig{ ID: centID, - Keys: map[int]identity.IdentityKey{ + Keys: map[int]identity.IDKey{ identity.KeyPurposeSigning: signKey, }, } diff --git a/documents/model_test.go b/documents/model_test.go index b3b149556..0a54b681a 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -1,3 +1,5 @@ +// +build unit + package documents import ( @@ -11,7 +13,6 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ @@ -21,7 +22,6 @@ func TestMain(m *testing.M) { &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index bbc8ae30e..3533bcca5 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -14,16 +14,17 @@ import ( "github.com/centrifuge/go-centrifuge/storage" ) -type Bootstrapper struct { -} +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} +// Bootstrap initialises required services for purchaseorder. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[storage.BootstrappedLevelDb]; !ok { + if _, ok := ctx[storage.BootstrappedLevelDB]; !ok { return errors.New("could not initialize purchase order repository") } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index c7863c71b..8e32d5092 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -377,5 +377,5 @@ func (p *PurchaseOrder) createProofs(fields []string) (coreDoc *coredocumentpb.C } proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) - return + return coreDoc, proofs, err } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 56f57a474..1204415fd 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -3,13 +3,12 @@ package purchaseorder import ( + "context" "encoding/json" + "os" "reflect" "testing" - "context" - "os" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/anchors" @@ -23,6 +22,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" - "github.com/centrifuge/go-centrifuge/queue" ) var ctx = map[string]interface{}{} diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index f3cf606a6..973987624 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -268,10 +268,10 @@ func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { temp, err := s.getPurchaseOrderVersion(documentID, nextVersion) if err != nil { return model, nil - } else { - model = temp - nextVersion = model.CoreDocument.NextVersion } + + model = temp + nextVersion = model.CoreDocument.NextVersion } return model, nil } @@ -300,8 +300,8 @@ func (s service) purchaseOrderProof(model documents.Model, fields []string) (*do return nil, err } return &documents.DocumentProof{ - DocumentId: coreDoc.DocumentIdentifier, - VersionId: coreDoc.CurrentVersion, + DocumentID: coreDoc.DocumentIdentifier, + VersionID: coreDoc.CurrentVersion, FieldProofs: proofs, }, nil } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 1d9a5feeb..80ae08eb7 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -328,13 +328,13 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er centID, err := identity.ToCentID(centIDBytes) assert.Nil(t, err) - signKey := identity.IdentityKey{ + signKey := identity.IDKey{ PublicKey: key1Pub[:], PrivateKey: key1, } - idConfig := &identity.IdentityConfig{ + idConfig := &identity.IDConfig{ ID: centID, - Keys: map[int]identity.IdentityKey{ + Keys: map[int]identity.IDKey{ identity.KeyPurposeSigning: signKey, }, } @@ -387,8 +387,8 @@ func TestService_CreateProofs(t *testing.T) { idService = mockSignatureCheck(i, idService, poSrv) proof, err := poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionId) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") } @@ -469,8 +469,8 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Nil(t, err) proof, err := poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po.po_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentId) - assert.Equal(t, olderVersion, proof.VersionId) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") } diff --git a/documents/service.go b/documents/service.go index 44ab0d809..d703b3408 100644 --- a/documents/service.go +++ b/documents/service.go @@ -9,8 +9,8 @@ import ( // DocumentProof is a value to represent a document and its field proofs type DocumentProof struct { - DocumentId []byte - VersionId []byte + DocumentID []byte + VersionID []byte State string FieldProofs []*proofspb.Proof } diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 131576650..9cff1de4b 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -13,10 +13,10 @@ import ( var testLevelDB Repository func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - if _, ok := context[storage.BootstrappedLevelDb]; !ok { + if _, ok := context[storage.BootstrappedLevelDB]; !ok { return errors.New("initializing LevelDB repository failed") } - testLevelDB = LevelDBRepository{LevelDB: context[storage.BootstrappedLevelDb].(*leveldb.DB)} + testLevelDB = LevelDBRepository{LevelDB: context[storage.BootstrappedLevelDB].(*leveldb.DB)} return b.Bootstrap(context) } diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 473b8679b..a12e2fa01 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -6,10 +6,13 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) +// BootstrappedEthereumClient is a key to mapped client in bootstrap context. const BootstrappedEthereumClient string = "BootstrappedEthereumClient" +// Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} +// Bootstrap initialises ethereum client. func (Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index b0a1e0a87..7bca4e372 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -300,7 +300,7 @@ func (gc *gethClient) incrementNonce(opts *bind.TransactOpts, txpoolAccessEnable } var keys []int - for k, _ := range res["pending"][opts.From.Hex()] { + for k := range res["pending"][opts.From.Hex()] { ki, err := strconv.Atoi(k) if err != nil { return fmt.Errorf("failed to convert nonce: %v", err) diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index a88309585..f6799dfb1 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -54,8 +54,8 @@ func (transactionRequest *MockTransactionRequest) RegisterTransaction(opts *bind err = errors.Wrap(transactionUnderpriced, 1) } } - tx = types.NewTransaction(1, common.Address{}, nil, 0, nil, nil) - return + + return types.NewTransaction(1, common.Address{}, nil, 0, nil, nil), err } func TestInitTransactionWithRetries(t *testing.T) { diff --git a/header/context.go b/header/context.go index ee83cc2da..b8967b80a 100644 --- a/header/context.go +++ b/header/context.go @@ -8,13 +8,13 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -// Placeholder to pass custom request objects down the pipeline +// ContextHeader holds custom request objects to pass down the pipeline. type ContextHeader struct { context context.Context - self *identity.IdentityConfig + self *identity.IDConfig } -// NewContextHeader creates new instance of the request headers needed +// NewContextHeader creates new instance of the request headers. func NewContextHeader(context context.Context, config config.Config) (*ContextHeader, error) { idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) if err != nil { @@ -24,12 +24,12 @@ func NewContextHeader(context context.Context, config config.Config) (*ContextHe return &ContextHeader{self: idConfig, context: context}, nil } -// Self returns Self CentID -func (h *ContextHeader) Self() *identity.IdentityConfig { +// Self returns Self CentID. +func (h *ContextHeader) Self() *identity.IDConfig { return h.self } -// Context returns context.Context of the request +// Context returns context.Context of the request. func (h *ContextHeader) Context() context.Context { return h.context } diff --git a/healthcheck/handler.go b/healthcheck/handler.go index f7364508e..b5f96b0a8 100644 --- a/healthcheck/handler.go +++ b/healthcheck/handler.go @@ -8,6 +8,7 @@ import ( "github.com/golang/protobuf/ptypes/empty" ) +// Config defines methods required for the package healthcheck type Config interface { GetNetworkString() string } diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 4d5754b32..069faab14 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -14,8 +14,8 @@ import ( // BootstrappedIDService is used as a key to map the configured ID Service through context. const BootstrappedIDService string = "BootstrappedIDService" -type Bootstrapper struct { -} +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} // Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. // the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper @@ -50,7 +50,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return NewEthereumIdentityContract(address, backend) }) - idRegTask := newIdRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext) + idRegTask := newIDRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext) keyRegTask := newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg, queueSrv, ethereum.GetClient, func(address common.Address, backend bind.ContractBackend) (contract, error) { return NewEthereumIdentityContract(address, backend) diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index 09ba922bb..daaf27323 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -26,7 +26,7 @@ import ( var log = logging.Logger("identity") type factory interface { - CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) + CreateIdentity(opts *bind.TransactOpts, centID *big.Int) (*types.Transaction, error) } type registry interface { @@ -147,15 +147,15 @@ func (id *ethereumIdentity) FetchKey(key []byte) (Key, error) { func (id *ethereumIdentity) CurrentP2PKey() (ret string, err error) { key, err := id.LastKeyForPurpose(KeyPurposeP2P) if err != nil { - return + return ret, err } key32, _ := utils.SliceToByte32(key) - p2pId, err := ed25519.PublicKeyToP2PKey(key32) + p2pID, err := ed25519.PublicKeyToP2PKey(key32) if err != nil { - return + return ret, err } - ret = p2pId.Pretty() - return + + return p2pID.Pretty(), nil } func (id *ethereumIdentity) findContract() (exists bool, err error) { @@ -263,7 +263,7 @@ func (id *ethereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdenti } // sendRegistrationTransaction sends the actual transaction to add a Key on Ethereum registry contract -func sendKeyRegistrationTransaction(identityContract contract, opts *bind.TransactOpts, identity *ethereumIdentity, keyPurpose int, key []byte) (err error) { +func sendKeyRegistrationTransaction(identityContract contract, opts *bind.TransactOpts, identity *ethereumIdentity, keyPurpose int, key []byte) error { //preparation of data in specific types for the call to Ethereum bigInt := big.NewInt(int64(keyPurpose)) @@ -279,35 +279,33 @@ func sendKeyRegistrationTransaction(identityContract contract, opts *bind.Transa } log.Infof("Sent off key [%v:%x] to add to CentrifugeID [%s]. Ethereum transaction hash [%x]", keyPurpose, bKey, identity, tx.Hash()) - return + return nil } // sendIdentityCreationTransaction sends the actual transaction to create identity on Ethereum registry contract -func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated Identity) (err error) { +func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated Identity) error { //preparation of data in specific types for the call to Ethereum tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) if err != nil { log.Infof("Failed to send identity for creation [CentrifugeID: %s] : %v", identityToBeCreated, err) return err - } else { - log.Infof("Sent off identity creation [%s]. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", identityToBeCreated, tx.Hash(), tx.Nonce(), tx.CheckNonce()) } + log.Infof("Sent off identity creation [%s]. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", identityToBeCreated, tx.Hash(), tx.Nonce(), tx.CheckNonce()) log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - - return + return err } // setUpKeyRegisteredEventListener listens for Identity creation func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) - centId := identity.CentID() + centID := identity.CentID() if err != nil { return nil, err } asyncRes, err := id.queue.EnqueueJob(keyRegistrationConfirmationTaskName, map[string]interface{}{ - centIDParam: centId, + centIDParam: centID, keyParam: key, keyPurposeParam: keyPurpose, queue.BlockHeightParam: bh, @@ -323,11 +321,12 @@ func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config Config, ident // of the identity. func (ids *EthereumIdentityService) setUpRegistrationEventListener(config Config, identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { confirmations = make(chan *WatchIdentity) - bCentId := identityToBeCreated.CentID() + centID := identityToBeCreated.CentID() if err != nil { return nil, err } - asyncRes, err := ids.queue.EnqueueJob(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: bCentId, queue.BlockHeightParam: blockHeight}) + + asyncRes, err := ids.queue.EnqueueJob(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: centID, queue.BlockHeightParam: blockHeight}) if err != nil { return nil, err } @@ -347,7 +346,7 @@ func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue confirmations <- &WatchIdentity{pushThisIdentity, err} } -// EthereumidentityService implements `Service` +// EthereumIdentityService implements `Service` type EthereumIdentityService struct { config Config factoryContract factory @@ -499,8 +498,8 @@ func (ids *EthereumIdentityService) GetIdentityKey(identity CentID, pubKey []byt } // ValidateKey checks if a given key is valid for the given centrifugeID. -func (ids *EthereumIdentityService) ValidateKey(centrifugeId CentID, key []byte, purpose int) error { - idKey, err := ids.GetIdentityKey(centrifugeId, key) +func (ids *EthereumIdentityService) ValidateKey(centID CentID, key []byte, purpose int) error { + idKey, err := ids.GetIdentityKey(centID, key) if err != nil { return err } diff --git a/identity/id_registration_confirmation_task.go b/identity/id_registration_confirmation_task.go index 7e0a17e0c..63d5e91b6 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/id_registration_confirmation_task.go @@ -18,7 +18,7 @@ const ( ) type identitiesCreatedFilterer interface { - FilterIdentityCreated(opts *bind.FilterOpts, centrifugeId []*big.Int) (*EthereumIdentityFactoryContractIdentityCreatedIterator, error) + FilterIdentityCreated(opts *bind.FilterOpts, centID []*big.Int) (*EthereumIdentityFactoryContractIdentityCreatedIterator, error) } // idRegistrationConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumIdentityFactoryContract. @@ -32,7 +32,7 @@ type idRegistrationConfirmationTask struct { filterer identitiesCreatedFilterer } -func newIdRegistrationConfirmationTask( +func newIDRegistrationConfirmationTask( timeout time.Duration, identityCreatedWatcher identitiesCreatedFilterer, ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), @@ -60,17 +60,17 @@ func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { rct.filterer}, nil } -// ParseKwargs parses the kwargs into the task +// ParseKwargs parses the kwargs into the task. func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - centId, ok := kwargs[centIDParam] + id, ok := kwargs[centIDParam] if !ok { return fmt.Errorf("undefined kwarg " + centIDParam) } - centIdTyped, err := getCentID(centId) + centID, err := getCentID(id) if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } - rct.centID = centIdTyped + rct.centID = centID rct.blockHeight, err = queue.ParseBlockHeight(kwargs) if err != nil { @@ -103,10 +103,7 @@ func (rct *idRegistrationConfirmationTask) RunTask() (interface{}, error) { } for { - iter, err := rct.filterer.FilterIdentityCreated( - fOpts, - []*big.Int{rct.centID.BigInt()}, - ) + iter, err := rct.filterer.FilterIdentityCreated(fOpts, []*big.Int{rct.centID.BigInt()}) if err != nil { return nil, centerrors.Wrap(err, "failed to start filtering identity event logs") } @@ -117,11 +114,9 @@ func (rct *idRegistrationConfirmationTask) RunTask() (interface{}, error) { return iter.Event, nil } - if err != utils.EventNotFound { + if err != utils.ErrEventNotFound { return nil, err } time.Sleep(100 * time.Millisecond) } - - return nil, fmt.Errorf("failed to filter identity events") } diff --git a/identity/id_registration_confirmation_task_test.go b/identity/id_registration_confirmation_task_test.go index d21f2b9b9..960d9a09c 100644 --- a/identity/id_registration_confirmation_task_test.go +++ b/identity/id_registration_confirmation_task_test.go @@ -21,7 +21,7 @@ func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { queue.BlockHeightParam: blockHeight, queue.TimeoutParam: timeout, } - decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) if err != nil { t.Errorf("Could not parse %s for [%x]", centIDParam, id) diff --git a/identity/identity.go b/identity/identity.go index 2f46b02a5..00c96ae63 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -35,14 +35,14 @@ const ( // CentID represents a CentIDLength identity of an entity type CentID [CentIDLength]byte -// IdentityConfig holds information about the identity -type IdentityConfig struct { +// IDConfig holds information about the identity +type IDConfig struct { ID CentID - Keys map[int]IdentityKey + Keys map[int]IDKey } -// IdentityKey represents a key pair -type IdentityKey struct { +// IDKey represents a key pair +type IDKey struct { PublicKey []byte PrivateKey []byte } @@ -68,6 +68,7 @@ func (c CentID) BigInt() *big.Int { return utils.ByteSliceToBigInt(c[:]) } +// Config defines methods required for the package identity. type Config interface { GetEthereumDefaultAccountName() string GetIdentityID() ([]byte, error) @@ -127,7 +128,7 @@ type Service interface { GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) // ValidateKey checks if a given key is valid for the given centrifugeID. - ValidateKey(centrifugeId CentID, key []byte, purpose int) error + ValidateKey(centID CentID, key []byte, purpose int) error // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file AddKeyFromConfig(purpose int) error @@ -136,8 +137,8 @@ type Service interface { ValidateSignature(signature *coredocumentpb.Signature, message []byte) error } -// GetIdentityConfig returns the identity and keys associated with the node -func GetIdentityConfig(config Config) (*IdentityConfig, error) { +// GetIdentityConfig returns the identity and keys associated with the node. +func GetIdentityConfig(config Config) (*IDConfig, error) { centIDBytes, err := config.GetIdentityID() if err != nil { return nil, err @@ -148,13 +149,13 @@ func GetIdentityConfig(config Config) (*IdentityConfig, error) { } //ed25519 keys - keys := map[int]IdentityKey{} + keys := map[int]IDKey{} pk, sk, err := ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) if err != nil { return nil, err } - keys[KeyPurposeP2P] = IdentityKey{PublicKey: pk, PrivateKey: sk} - keys[KeyPurposeSigning] = IdentityKey{PublicKey: pk, PrivateKey: sk} + keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} + keys[KeyPurposeSigning] = IDKey{PublicKey: pk, PrivateKey: sk} //secp256k1 keys pk, sk, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) @@ -165,9 +166,9 @@ func GetIdentityConfig(config Config) (*IdentityConfig, error) { if err != nil { return nil, err } - keys[KeyPurposeEthMsgAuth] = IdentityKey{PublicKey: pubKey, PrivateKey: sk} + keys[KeyPurposeEthMsgAuth] = IDKey{PublicKey: pubKey, PrivateKey: sk} - return &IdentityConfig{ID: centID, Keys: keys}, nil + return &IDConfig{ID: centID, Keys: keys}, nil } // ToCentID takes bytes and return CentID @@ -232,6 +233,6 @@ func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated -func Sign(idConfig *IdentityConfig, purpose int, payload []byte) *coredocumentpb.Signature { +func Sign(idConfig *IDConfig, purpose int, payload []byte) *coredocumentpb.Signature { return signatures.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) } diff --git a/identity/identity_test.go b/identity/identity_test.go index 7fddd29bd..4bdb652fa 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -279,7 +279,7 @@ func TestSign(t *testing.T) { key1 := []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} c := RandomCentID() msg := utils.RandomSlice(100) - sig := Sign(&IdentityConfig{c, map[int]IdentityKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) + sig := Sign(&IDConfig{c, map[int]IDKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) err := signatures.VerifySignature(key1Pub, msg, sig.Signature) assert.True(t, err == nil) diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index 0675dbda6..8fcf9e914 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -88,15 +88,15 @@ func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) // ParseKwargs parses the args into the task func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - centId, ok := kwargs[centIDParam] + id, ok := kwargs[centIDParam] if !ok { return fmt.Errorf("undefined kwarg " + centIDParam) } - centIdTyped, err := getCentID(centId) + centID, err := getCentID(id) if err != nil { return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } - krct.centID = centIdTyped + krct.centID = centID // key parsing key, ok := kwargs[keyParam] @@ -151,19 +151,15 @@ func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { if err != nil { return nil, err } - krct.filterer = contract + krct.filterer = contract fOpts := &bind.FilterOpts{ Context: krct.ctx, Start: krct.blockHeight, } for { - iter, err := krct.filterer.FilterKeyAdded( - fOpts, - [][32]byte{krct.key}, - []*big.Int{big.NewInt(int64(krct.keyPurpose))}, - ) + iter, err := krct.filterer.FilterKeyAdded(fOpts, [][32]byte{krct.key}, []*big.Int{big.NewInt(int64(krct.keyPurpose))}) if err != nil { return nil, centerrors.Wrap(err, "failed to start filtering key event logs") } @@ -174,11 +170,9 @@ func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { return iter.Event, nil } - if err != utils.EventNotFound { + if err != utils.ErrEventNotFound { return nil, err } time.Sleep(100 * time.Millisecond) } - - return nil, fmt.Errorf("failed to filter key events") } diff --git a/identity/key_registration_confirmation_task_test.go b/identity/key_registration_confirmation_task_test.go index f1e013259..4e6115948 100644 --- a/identity/key_registration_confirmation_task_test.go +++ b/identity/key_registration_confirmation_task_test.go @@ -27,7 +27,7 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { keyPurposeParam: keyPurpose, queue.BlockHeightParam: bh, } - decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) if err != nil { t.Errorf("parse error %s", err.Error()) @@ -55,7 +55,7 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPathOverrideTimeout(t * queue.BlockHeightParam: bh, queue.TimeoutParam: overrideTimeout, } - decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) err = rct.ParseKwargs(decoded) if err != nil { t.Errorf("parse error %s", err.Error()) diff --git a/keytools/ed25519/ed25519.go b/keytools/ed25519/ed25519.go index dea7dfe17..1d4d7039a 100644 --- a/keytools/ed25519/ed25519.go +++ b/keytools/ed25519/ed25519.go @@ -53,19 +53,15 @@ func GenerateSigningKeyPair() (publicKey ed25519.PublicKey, privateKey ed25519.P if err != nil { log.Fatal(err) } - return + return publicKey, privateKey } // PublicKeyToP2PKey returns p2pId from the public key -func PublicKeyToP2PKey(publicKey [32]byte) (p2pId peer.ID, err error) { +func PublicKeyToP2PKey(publicKey [32]byte) (p2pID peer.ID, err error) { pk, err := crypto.UnmarshalEd25519PublicKey(publicKey[:]) if err != nil { - return "", err + return p2pID, err } - p2pId, err = peer.IDFromPublicKey(pk) - if err != nil { - return "", err - } - return + return peer.IDFromPublicKey(pk) } diff --git a/keytools/generate.go b/keytools/generate.go index 9916871dc..5806d67f8 100644 --- a/keytools/generate.go +++ b/keytools/generate.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/utils" ) +// GenerateSigningKeyPair generates based on the curveType and writes keys to file paths given. func GenerateSigningKeyPair(publicFileName, privateFileName, curveType string) { var publicKey, privateKey []byte switch strings.ToLower(curveType) { diff --git a/keytools/keytools.go b/keytools/keytools.go index 7a44379c0..c17c79bde 100644 --- a/keytools/keytools.go +++ b/keytools/keytools.go @@ -6,9 +6,9 @@ import ( var log = logging.Logger("keytools") +// Constants shared within subfolders const ( CurveEd25519 string = "ed25519" CurveSecp256K1 string = "secp256k1" + MaxMsgLen = 32 ) - -const MaxMsgLen = 32 diff --git a/keytools/secp256k1/secp256k1.go b/keytools/secp256k1/secp256k1.go index e041a565f..72bd91a2a 100644 --- a/keytools/secp256k1/secp256k1.go +++ b/keytools/secp256k1/secp256k1.go @@ -16,13 +16,15 @@ import ( var log = logging.Logger("signing") -const SignatureRSFormatLen = 64 //64 byte [R || S] format -const SignatureRSVFormatLen = 65 //65 byte [R || S || V] format -const SignatureVPosition = 64 -const PrivateKeyLen = 32 +const ( + signatureRSFormatLen = 64 //64 byte [R || S] format + signatureRSVFormatLen = 65 //65 byte [R || S || V] format + signatureVPosition = 64 + privateKeyLen = 32 +) +// GenerateSigningKeyPair generates secp2562k1 based keys. func GenerateSigningKeyPair() (publicKey, privateKey []byte) { - log.Debug("generate secp256k1 keys") key, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) if err != nil { @@ -30,18 +32,19 @@ func GenerateSigningKeyPair() (publicKey, privateKey []byte) { } publicKey = elliptic.Marshal(secp256k1.S256(), key.X, key.Y) - privateKey = make([]byte, PrivateKeyLen) + privateKey = make([]byte, privateKeyLen) blob := key.D.Bytes() - copy(privateKey[PrivateKeyLen-len(blob):], blob) + copy(privateKey[privateKeyLen-len(blob):], blob) return publicKey, privateKey } +// Sign signs the message using private key func Sign(message []byte, privateKey []byte) (signature []byte, err error) { return secp256k1.Sign(message, privateKey) - } +// SignEthereum converts message to ethereum specific format and signs it. func SignEthereum(message []byte, privateKey []byte) (signature []byte, err error) { // The hash is calculated in Ethereum in the following way // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). @@ -49,65 +52,62 @@ func SignEthereum(message []byte, privateKey []byte) (signature []byte, err erro return Sign(hash, privateKey) } +// GetAddress returns the hex of first 20 bytes of the Keccak256 has of public keuy func GetAddress(publicKey []byte) string { - hash := crypto.Keccak256(publicKey[1:]) address := hash[12:] //address is the last 20 bytes of the hash len(hash) = 20 return hexutil.Encode(address) } +// VerifySignatureWithAddress verifies the signature using address provided func VerifySignatureWithAddress(address, sigHex string, msg []byte) bool { fromAddr := common.HexToAddress(address) - sig, err := hexutil.Decode(sigHex) - if err != nil { log.Error(err.Error()) return false } - if len(sig) != SignatureRSVFormatLen { + if len(sig) != signatureRSVFormatLen { log.Error("signature must be 65 bytes long") return false } // see implementation in go-ethereum for further details // https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L442 - if sig[SignatureVPosition] != 0 && sig[SignatureVPosition] != 1 { - if sig[SignatureVPosition] != 27 && sig[SignatureVPosition] != 28 { + if sig[signatureVPosition] != 0 && sig[signatureVPosition] != 1 { + if sig[signatureVPosition] != 27 && sig[signatureVPosition] != 28 { log.Error("V value in signature has to be 27 or 28") return false } - sig[SignatureVPosition] -= 27 // change V value to 0 or 1 + sig[signatureVPosition] -= 27 // change V value to 0 or 1 } pubKey, err := crypto.SigToPub(SignHash(msg), sig) if err != nil { - return false } recoveredAddr := crypto.PubkeyToAddress(*pubKey) - return fromAddr == recoveredAddr } +// SignHash returns the hash of the data. // The hash is calculated as // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // for further details see // https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L404 - func SignHash(data []byte) []byte { msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(data)) return crypto.Keccak256(append([]byte(msg), data...)) } +// VerifySignature verifies signature using the public key provided. func VerifySignature(publicKey, message, signature []byte) bool { - if len(signature) == SignatureRSFormatLen+1 { + if len(signature) == signatureRSFormatLen+1 { // signature in [R || S || V] format is 65 bytes //https://bitcoin.stackexchange.com/questions/38351/ecdsa-v-r-s-what-is-v - - signature = signature[0:SignatureRSFormatLen] + signature = signature[0:signatureRSFormatLen] } // the signature should have the 64 byte [R || S] format return secp256k1.VerifySignature(publicKey, message, signature) @@ -125,6 +125,7 @@ func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { if err != nil { return nil, nil, fmt.Errorf("failed to read public key: %v", err) } + return publicKey, privateKey, nil } @@ -132,16 +133,16 @@ func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { func GetPrivateEthAuthKey(fileName string) (key []byte, err error) { key, err = utils.ReadKeyFromPemFile(fileName, utils.PrivateKey) if err != nil { - log.Error(err) + return nil, err } - return + return key, nil } // GetPublicEthAuthKey returns the public key from the file func GetPublicEthAuthKey(fileName string) (key []byte, err error) { key, err = utils.ReadKeyFromPemFile(fileName, utils.PublicKey) if err != nil { - log.Error(err) + return nil, err } - return + return key, nil } diff --git a/keytools/sign.go b/keytools/sign.go index 874af8a28..4806ddd99 100644 --- a/keytools/sign.go +++ b/keytools/sign.go @@ -7,25 +7,23 @@ import ( "github.com/centrifuge/go-centrifuge/keytools/secp256k1" ) +// SignMessage signs the message using the private key as the curveType provided. +// if ethereumSign is true, then the signature format is specific to ethereum. func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool) ([]byte, error) { - curveType = strings.ToLower(curveType) - switch curveType { - case CurveSecp256K1: msg := make([]byte, MaxMsgLen) copy(msg, message) if ethereumSign { return secp256k1.SignEthereum(msg, privateKey) } - return secp256k1.Sign(msg, privateKey) + return secp256k1.Sign(msg, privateKey) case CurveEd25519: - return []byte(""), fmt.Errorf("curve ed25519 not supported yet") - + return nil, fmt.Errorf("curve ed25519 not supported yet") default: - return []byte(""), fmt.Errorf("curve %s not supported", curveType) + return nil, fmt.Errorf("curve %s not supported", curveType) } } diff --git a/keytools/verify.go b/keytools/verify.go index 14c9f346a..37f318d76 100644 --- a/keytools/verify.go +++ b/keytools/verify.go @@ -5,13 +5,13 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +// VerifyMessage verifies message using the public key as per the curve type. +// if ethereumVerify is true, ethereum specific verification is done func VerifyMessage(publicKey, message []byte, signature []byte, curveType string, ethereumVerify bool) bool { - signatureBytes := make([]byte, len(signature)) copy(signatureBytes, signature) switch curveType { - case CurveSecp256K1: msg := make([]byte, MaxMsgLen) copy(msg, message) @@ -19,13 +19,11 @@ func VerifyMessage(publicKey, message []byte, signature []byte, curveType string address := secp256k1.GetAddress(publicKey) return secp256k1.VerifySignatureWithAddress(address, hexutil.Encode(signatureBytes), msg) } - return secp256k1.VerifySignature(publicKey, msg, signatureBytes) + return secp256k1.VerifySignature(publicKey, msg, signatureBytes) case CurveEd25519: return false - default: return false } - } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index ab8c215a1..ad7338e7c 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -12,10 +12,11 @@ import ( "github.com/centrifuge/go-centrifuge/queue" ) +// BootstrappedPayObService is the key to PaymentObligationService in bootstrap context. const BootstrappedPayObService = "BootstrappedPayObService" -type Bootstrapper struct { -} +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { @@ -43,7 +44,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - ctx[BootstrappedPayObService] = NewEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, queueSrv, setupMintListener, bindContract) + ctx[BootstrappedPayObService] = newEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, queueSrv, setupMintListener, bindContract) // queue task task := newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext) queueSrv.RegisterTaskType(task.TaskTypeName(), task) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 32ed55795..7405fd4c1 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -42,7 +42,7 @@ type Config interface { type ethereumPaymentObligationContract interface { // Mint method abstracts Mint method on the contract - Mint(opts *bind.TransactOpts, to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, merkleRoot [32]byte, collaboratorField string, values [5]string, salts [5][32]byte, proofs [5][][32]byte) (*types.Transaction, error) + Mint(opts *bind.TransactOpts, to common.Address, tokenID *big.Int, tokenURI string, anchorID *big.Int, merkleRoot [32]byte, collaboratorField string, values [5]string, salts [5][32]byte, proofs [5][][32]byte) (*types.Transaction, error) } // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum @@ -52,14 +52,14 @@ type ethereumPaymentObligation struct { ethClient ethereum.Client config Config queue *queue.Server - setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) + setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error) bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) } -// NewEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func NewEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, +// newEthereumPaymentObligation creates ethereumPaymentObligation given the parameters +func newEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, queue *queue.Server, - setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { + setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ registry: registry, identityService: identityService, @@ -119,9 +119,12 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, deposi } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { +func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) { requestData, err := s.prepareMintRequest(documentID, depositAddress, proofFields) + if err != nil { + return nil, fmt.Errorf("failed to prepare mint request: %v", err) + } opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { @@ -155,8 +158,8 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, // setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code // about successful minting of an NFt -func setupMintListener(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *WatchTokenMinted, err error) { - confirmations = make(chan *WatchTokenMinted) +func setupMintListener(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error) { + confirmations = make(chan *watchTokenMinted) conn := ethereum.GetClient() h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) @@ -177,13 +180,13 @@ func setupMintListener(config Config, qs *queue.Server, tokenID *big.Int, regist } // waitAndRouteNFTApprovedEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes queue.TaskResult, tokenID *big.Int, confirmations chan<- *WatchTokenMinted) { +func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes queue.TaskResult, tokenID *big.Int, confirmations chan<- *watchTokenMinted) { _, err := asyncRes.Get(timeout) - confirmations <- &WatchTokenMinted{tokenID, err} + confirmations <- &watchTokenMinted{tokenID, err} } // sendMintTransaction sends the actual transaction to mint the NFT -func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (err error) { +func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) error { tx, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, requestData.MerkleRoot, requestData.CollaboratorField, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { @@ -192,7 +195,7 @@ func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPayment log.Infof("Sent off tx to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", requestData.TokenID, requestData.AnchorID, requestData.To, tx.Hash(), tx.Nonce(), tx.CheckNonce()) log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return + return nil } func (s *ethereumPaymentObligation) getIdentityAddress() (common.Address, error) { diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 2b6e3a605..a4462d85b 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -178,8 +178,8 @@ func TestPaymentObligationService(t *testing.T) { docService, paymentOb, idService, ethClient, mockCfg := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) - confirmations := make(chan *WatchTokenMinted) - service := NewEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, nil, func(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (chan *WatchTokenMinted, error) { + confirmations := make(chan *watchTokenMinted) + service := newEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, nil, func(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (chan *watchTokenMinted, error) { return confirmations, nil }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil @@ -201,8 +201,8 @@ func TestPaymentObligationService(t *testing.T) { func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProof { return &documents.DocumentProof{ - DocumentId: coreDoc.DocumentIdentifier, - VersionId: coreDoc.CurrentVersion, + DocumentID: coreDoc.DocumentIdentifier, + VersionID: coreDoc.CurrentVersion, State: "state", FieldProofs: []*proofspb.Proof{ { diff --git a/nft/handler_test.go b/nft/handler_test.go index 147318d64..480ab7bce 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -19,9 +19,9 @@ type MockPaymentObligationService struct { mock.Mock } -func (m *MockPaymentObligationService) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) { +func (m *MockPaymentObligationService) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) { args := m.Called(documentID, registryAddress, depositAddress, proofFields) - return args.Get(0).(chan *WatchTokenMinted), args.Error(1) + return args.Get(0).(chan *watchTokenMinted), args.Error(1) } func TestNFTMint_success(t *testing.T) { @@ -29,14 +29,14 @@ func TestNFTMint_success(t *testing.T) { mockService := &MockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) - confirmations := make(chan *WatchTokenMinted) + confirmations := make(chan *watchTokenMinted) mockService. On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(confirmations, nil) tokID := big.NewInt(1) go func() { - confirmations <- &WatchTokenMinted{tokID, nil} + confirmations <- &watchTokenMinted{tokID, nil} }() handler := grpcHandler{mockService} @@ -59,7 +59,7 @@ func TestNFTMint_ServiceError(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &MockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) - confirmations := make(chan *WatchTokenMinted) + confirmations := make(chan *watchTokenMinted) mockService. On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(confirmations, errors.New("service error")) diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 44624156c..3804b8950 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -5,16 +5,13 @@ import ( "fmt" "time" - "github.com/centrifuge/go-centrifuge/ethereum" - - "github.com/ethereum/go-ethereum/common" - - "github.com/centrifuge/gocelery" - "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" ) const ( @@ -131,9 +128,7 @@ func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { } for { - iter, err := filter.FilterPaymentObligationMinted( - fOpts, - ) + iter, err := filter.FilterPaymentObligationMinted(fOpts) if err != nil { return nil, centerrors.Wrap(err, "failed to start filtering token minted logs") } @@ -144,11 +139,9 @@ func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { return iter.Event, nil } - if err != utils.EventNotFound { + if err != utils.ErrEventNotFound { return nil, err } time.Sleep(100 * time.Millisecond) } - - return nil, fmt.Errorf("failed to filter nft minted events") } diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go index 20a6061c8..075bdf828 100644 --- a/nft/minting_confirmation_task_test.go +++ b/nft/minting_confirmation_task_test.go @@ -23,7 +23,7 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { registryAddressParam: registryAddress, } - decoded, err := utils.SimulateJsonDecodeForGocelery(kwargs) + decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) assert.Nil(t, err, "json decode should not thrown an error") err = task.ParseKwargs(decoded) assert.Nil(t, err, "parsing should be successful") @@ -59,7 +59,7 @@ func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { } for i, test := range tests { - decoded, err := utils.SimulateJsonDecodeForGocelery(test) + decoded, err := utils.SimulateJSONDecodeForGocelery(test) assert.Nil(t, err, "json decode should not thrown an error") err = task.ParseKwargs(decoded) assert.Error(t, err, "test case %v: parsing should fail", i) diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index b2a7c074b..b833a7fd1 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -6,10 +6,10 @@ import "math/big" type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *WatchTokenMinted, error) + MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) } -type WatchTokenMinted struct { +type watchTokenMinted struct { TokenID *big.Int Err error } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 8b9348a84..2b4fda9a0 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -9,9 +9,11 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" ) -type Bootstrapper struct { -} +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} +// Bootstrap runs the severs. +// Note: this is a blocking call. func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { srvs, err := getServers(c) if err != nil { @@ -36,8 +38,6 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { return err } } - - return nil } func getServers(ctx map[string]interface{}) ([]Server, error) { diff --git a/node/node.go b/node/node.go index 0699e3bea..a1042b37a 100644 --- a/node/node.go +++ b/node/node.go @@ -1,4 +1,4 @@ -// node provides utilities to control all long running background services on Centrifuge node +// Package node provides utilities to control all long running background services on Centrifuge node package node import ( @@ -26,12 +26,14 @@ type Node struct { services []Server } +// NewNode returns a new Node with given services. func NewNode(services []Server) *Node { return &Node{ services: services, } } +// Name returns "CentNode". func (n *Node) Name() string { return "CentNode" } @@ -39,6 +41,7 @@ func (n *Node) Name() string { // Start starts all services that are wired in the Node and waits for further actions depending on errors or commands from upstream. func (n *Node) Start(ctx context.Context, startupErr chan<- error) { ctxCh, cancel := context.WithCancel(ctx) + defer cancel() childErr := make(chan error) var wg sync.WaitGroup wg.Add(len(n.services)) diff --git a/notification/notification.go b/notification/notification.go index 16588b681..b50feb68a 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -1,6 +1,9 @@ package notification import ( + "fmt" + "net/http" + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/jsonpb" @@ -9,33 +12,42 @@ import ( var log = logging.Logger("notification-api") +// EventType is the type of the notification. type EventType int +// Status defines the status of the notification. type Status int +// Constants defined for notification delivery. const ( ReceivedPayload EventType = 1 Failure Status = 0 Success Status = 1 ) +// Config defines methods required for this package. type Config interface { GetReceiveEventNotificationEndpoint() string } +// Sender defines methods that can handle a notification. type Sender interface { Send(notification *notificationpb.NotificationMessage) (Status, error) } -func NewWebhookSender(config Config) *WebhookSender { - return &WebhookSender{config} +// NewWebhookSender returns an implementation of a Sender that sends notifications through webhooks. +func NewWebhookSender(config Config) Sender { + return webhookSender{config} } -type WebhookSender struct { +// NewWebhookSender implements Sender. +// Sends notification through a webhook defined. +type webhookSender struct { config Config } -func (wh *WebhookSender) Send(notification *notificationpb.NotificationMessage) (Status, error) { +// Send sends notification to the defined webhook. +func (wh webhookSender) Send(notification *notificationpb.NotificationMessage) (Status, error) { url := wh.config.GetReceiveEventNotificationEndpoint() if url == "" { log.Warningf("Webhook URL not defined, manually fetch received document") @@ -44,21 +56,24 @@ func (wh *WebhookSender) Send(notification *notificationpb.NotificationMessage) payload, err := wh.constructPayload(notification) if err != nil { - log.Error(err) return Failure, err } - httpStatusCode, err := utils.SendPOSTRequest(url, "application/json", payload) - if httpStatusCode != 200 { + statusCode, err := utils.SendPOSTRequest(url, "application/json", payload) + if err != nil { return Failure, err } + if statusCode != http.StatusOK { + return Failure, fmt.Errorf("failed to send webhook: status = %v", statusCode) + } + log.Infof("Sent Webhook Notification with Payload [%v] to [%s]", notification, url) return Success, nil } -func (wh *WebhookSender) constructPayload(notification *notificationpb.NotificationMessage) ([]byte, error) { +func (wh webhookSender) constructPayload(notification *notificationpb.NotificationMessage) ([]byte, error) { marshaler := jsonpb.Marshaler{} payload, err := marshaler.MarshalToString(notification) if err != nil { diff --git a/notification/notification_test.go b/notification/notification_test.go index abd393fa5..3bc3d3e8e 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -48,7 +48,7 @@ func TestWebhookConstructPayload(t *testing.T) { Recorded: ts, } - whs := WebhookSender{} + whs := webhookSender{} bresult, err := whs.constructPayload(notificationMessage) assert.Nil(t, err, "Should not error out") diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 48e1e3352..14db0e294 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -8,7 +8,10 @@ import ( "github.com/centrifuge/go-centrifuge/documents" ) -const BootstrappedP2PClient string = "BootstrappedP2PClient" +// Bootstrapped constants that are used as key in bootstrap context +const ( + BootstrappedP2PClient string = "BootstrappedP2PClient" +) // Bootstrapper implements Bootstrapper with p2p details type Bootstrapper struct{} diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 383722f4f..c70a162a5 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,10 +5,9 @@ package p2p import ( "testing" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/stretchr/testify/assert" ) diff --git a/p2p/client.go b/p2p/client.go index fc515ea2c..192c6387b 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -18,6 +18,7 @@ import ( "google.golang.org/grpc" ) +// Client defines methods that can be implemented by any type handling p2p communications. type Client interface { OpenClient(target string) (p2ppb.P2PServiceClient, error) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error @@ -52,7 +53,8 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { // make a new stream from host B to host A with timeout // Retrial is handled internally, connection request will be cancelled by the connection timeout context - ctx, _ := context.WithTimeout(context.Background(), s.config.GetP2PConnectionTimeout()) + ctx, cancel := context.WithTimeout(context.Background(), s.config.GetP2PConnectionTimeout()) + defer cancel() g, err := s.protocol.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) @@ -62,8 +64,8 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID) (*p2ppb.SignatureResponse, error) { - senderId, err := s.config.GetIdentityID() +func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { + senderID, err := s.config.GetIdentityID() if err != nil { return nil, err } @@ -71,7 +73,7 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService header := p2ppb.CentrifugeHeader{ NetworkIdentifier: s.config.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), - SenderCentrifugeId: senderId, + SenderCentrifugeId: senderID, } req := &p2ppb.SignatureRequest{ @@ -79,7 +81,7 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService Document: &doc, } - log.Infof("Requesting signature from %s\n", receiverCentId) + log.Infof("Requesting signature from %s\n", receiverCentID) resp, err := client.RequestDocumentSignature(ctx, req) if err != nil { @@ -91,7 +93,7 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService return nil, version.IncompatibleVersionError(resp.CentNodeVersion) } - err = identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiverCentId) + err = identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiverCentID) if err != nil { return nil, centerrors.New(code.AuthenticationFailed, err.Error()) } @@ -101,8 +103,7 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService return nil, centerrors.New(code.AuthenticationFailed, "signature invalid") } - log.Infof("Signature successfully received from %s\n", receiverCentId) - + log.Infof("Signature successfully received from %s\n", receiverCentID) return resp, nil } @@ -111,8 +112,8 @@ type signatureResponseWrap struct { err error } -func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentId identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, identityService, doc, client, receiverCentId) +func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, identityService, doc, client, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, diff --git a/p2p/server.go b/p2p/server.go index da119b1ec..dc99ecb67 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -27,6 +27,7 @@ import ( var log = logging.Logger("p2p-server") +// Config defines methods that are required for the package p2p. type Config interface { GetP2PExternalIP() string GetP2PPort() int @@ -119,20 +120,21 @@ func (s *p2pServer) runDHT(ctx context.Context, h host.Host) error { // First, announce ourselves as participating in this topic log.Info("Announcing ourselves...") - tctx, _ := context.WithTimeout(ctx, time.Second*10) + tctx, cancel := context.WithTimeout(ctx, time.Second*10) if err := dhtClient.Provide(tctx, cidPref, true); err != nil { // Important to keep this as Non-Fatal error, otherwise it will fail for a node that behaves as well as bootstrap one log.Infof("Error: %s\n", err.Error()) } + cancel() // Now, look for others who have announced log.Info("Searching for other peers ...") - tctx, _ = context.WithTimeout(ctx, time.Second*10) + tctx, cancel = context.WithTimeout(ctx, time.Second*10) peers, err := dhtClient.FindProviders(tctx, cidPref) if err != nil { log.Error(err) } - + cancel() log.Infof("Found %d peers!\n", len(peers)) // Now connect to them, so they are added to the PeerStore @@ -144,10 +146,11 @@ func (s *p2pServer) runDHT(ctx context.Context, h host.Host) error { continue } - tctx, _ := context.WithTimeout(ctx, time.Second*5) + tctx, cancel := context.WithTimeout(ctx, time.Second*5) if err := h.Connect(tctx, pe); err != nil { log.Info("Failed to connect to peer: ", err) } + cancel() } log.Info("Bootstrapping and discovery complete!") diff --git a/p2p/validator.go b/p2p/validator.go index 5ea6f35ab..f282ffcbf 100644 --- a/p2p/validator.go +++ b/p2p/validator.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/version" ) +// Validator defines method that must be implemented by any validator type. type Validator interface { // Validate validates p2p requests Validate(header *p2ppb.CentrifugeHeader) error diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index 10b67f834..ee1021218 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -7,10 +7,12 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) +// Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct { context map[string]interface{} } +// Bootstrap initiates the queue. func (b *Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") diff --git a/queue/server.go b/queue/server.go index c79e445b1..2f5302751 100644 --- a/queue/server.go +++ b/queue/server.go @@ -1,16 +1,16 @@ package queue import ( - "sync" - "context" "errors" + "sync" "time" "github.com/centrifuge/gocelery" logging "github.com/ipfs/go-log" ) +// Constants are commonly used by all the tasks through kwargs. const ( BlockHeightParam string = "BlockHeight" TimeoutParam string = "Timeout" @@ -46,13 +46,13 @@ type TaskResult interface { // Server represents the queue server currently implemented based on gocelery type Server struct { config Config - lock sync.RWMutex + lock sync.RWMutex queue *gocelery.CeleryClient taskTypes []TaskType } // TaskTypeName of the queue server -func (qs *Server) Name() string { +func (qs *Server) TaskTypeName() string { return "QueueServer" } diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index c0dc0aa98..82ee57aae 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -7,11 +7,13 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) -const BootstrappedLevelDb string = "BootstrappedLevelDb" +// BootstrappedLevelDB is a key mapped to levelDB in the boot +const BootstrappedLevelDB string = "BootstrappedLevelDB" -type Bootstrapper struct { -} +// Bootstrapper implements bootstrapper.Bootstrapper. +type Bootstrapper struct{} +// Bootstrap initialises the levelDB. func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config not initialised") @@ -23,6 +25,6 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return fmt.Errorf("failed to init level db: %v", err) } - context[BootstrappedLevelDb] = levelDB + context[BootstrappedLevelDB] = levelDB return nil } diff --git a/storage/leveldb.go b/storage/leveldb.go index 0c6143ad4..4af6cc92d 100644 --- a/storage/leveldb.go +++ b/storage/leveldb.go @@ -16,7 +16,7 @@ var levelDBInstance *leveldb.DB // lock to guard the levelDB instance var lock sync.Mutex -// GetStorage is a singleton implementation returning the default database as configured +// NewLevelDBStorage is a singleton implementation returning the default database as configured. func NewLevelDBStorage(path string) (*leveldb.DB, error) { if levelDBInstance != nil { return nil, fmt.Errorf("db already open") diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index 858d6dd44..bbcb7de88 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -22,7 +22,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { } log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) - context[BootstrappedLevelDb] = levelDB + context[BootstrappedLevelDB] = levelDB return nil } diff --git a/utils/constants.go b/utils/constants.go index f4792fddb..c88f06370 100644 --- a/utils/constants.go +++ b/utils/constants.go @@ -1,5 +1,6 @@ package utils +// Constants that are common across packages. const ( PublicKey = "PUBLIC KEY" PrivateKey = "PRIVATE KEY" diff --git a/utils/events.go b/utils/events.go index f80610c30..299b771b6 100644 --- a/utils/events.go +++ b/utils/events.go @@ -2,8 +2,8 @@ package utils import "fmt" -// EventNotFound when event is not found and need to retry -var EventNotFound = fmt.Errorf("event not found") +// ErrEventNotFound when event is not found and need to retry +var ErrEventNotFound = fmt.Errorf("event not found") // EventIterator contains functions that make events listening more easier type EventIterator interface { @@ -13,7 +13,7 @@ type EventIterator interface { } // LookForEvent checks if the iterator is ready with the Event -// if no event is found, returns EventNotFound +// if no event is found, returns ErrEventNotFound // returns iter.Error when iterator errored out func LookForEvent(iter EventIterator) (err error) { defer iter.Close() @@ -25,5 +25,5 @@ func LookForEvent(iter EventIterator) (err error) { return iter.Error() } - return EventNotFound + return ErrEventNotFound } diff --git a/utils/events_test.go b/utils/events_test.go index 6519b3efb..22fdf5e74 100644 --- a/utils/events_test.go +++ b/utils/events_test.go @@ -37,7 +37,7 @@ func TestLookForEvent_event_not_found(t *testing.T) { iter := &mockIterator{} err := LookForEvent(iter) assert.NotNil(t, err, "error should be non nil") - assert.Equal(t, err, EventNotFound) + assert.Equal(t, err, ErrEventNotFound) } func TestLookForEvent_success(t *testing.T) { diff --git a/utils/httputils.go b/utils/httputils.go index bf47d42c3..7030ffbd7 100644 --- a/utils/httputils.go +++ b/utils/httputils.go @@ -1,13 +1,10 @@ package utils import ( - "github.com/go-errors/errors" - logging "github.com/ipfs/go-log" "gopkg.in/resty.v1" ) -var log = logging.Logger("http-utils") - +// SendPOSTRequest sends post with data to given URL. func SendPOSTRequest(url string, contentType string, payload []byte) (statusCode int, err error) { resp, err := resty.R(). SetHeader("Content-Type", contentType). @@ -15,12 +12,8 @@ func SendPOSTRequest(url string, contentType string, payload []byte) (statusCode Post(url) if err != nil { - log.Error(err) - return - } - if resp.StatusCode() != 200 { - err = errors.Errorf("%s", resp.Status()) + return statusCode, err } - statusCode = resp.StatusCode() - return + + return resp.StatusCode(), nil } diff --git a/utils/time.go b/utils/time.go index 334f74e1f..1338b04c9 100644 --- a/utils/time.go +++ b/utils/time.go @@ -6,6 +6,7 @@ import ( "github.com/golang/protobuf/ptypes/timestamp" ) +// ToTimestamp converts time.Time to timestamp.TimeStamp. func ToTimestamp(time time.Time) *timestamp.Timestamp { return ×tamp.Timestamp{ Seconds: int64(time.Second()), diff --git a/utils/tools.go b/utils/tools.go index cd3403651..8e78b3b64 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +// ContainsBigIntInSlice checks if value is present in list. func ContainsBigIntInSlice(value *big.Int, list []*big.Int) bool { for _, v := range list { if v.Cmp(value) == 0 { @@ -25,10 +26,10 @@ func SliceToByte32(in []byte) (out [32]byte, err error) { return [32]byte{}, errors.New("input exceeds length of 32") } copy(out[:], in) - return + return out, nil } -// +// IsEmptyAddress checks if the addr is empty. func IsEmptyAddress(addr common.Address) bool { return addr.Hex() == "0x0000000000000000000000000000000000000000" } @@ -46,12 +47,12 @@ func SliceOfByteSlicesToHexStringSlice(byteSlices [][]byte) []string { func Byte32ToSlice(in [32]byte) []byte { if IsEmptyByte32(in) { return []byte{} - } else { - return in[:] } + + return in[:] } -// Check32BytesFilled takes multiple []byte slices and ensures they are all of length 32 and don't contain all 0x0 bytes. +// CheckMultiple32BytesFilled takes multiple []byte slices and ensures they are all of length 32 and don't contain all 0x0 bytes. func CheckMultiple32BytesFilled(b []byte, bs ...[]byte) bool { bs = append(bs, b) for _, v := range bs { @@ -80,6 +81,7 @@ func RandomByte32() (out [32]byte) { return } +// IsEmptyByte32 checks if the source is empty. func IsEmptyByte32(source [32]byte) bool { sl := make([]byte, 32) copy(sl, source[:32]) @@ -102,6 +104,7 @@ func IsEmptyByteSlice(s []byte) bool { return true } +// IsSameByteSlice checks if a and b contains same bytes. func IsSameByteSlice(a []byte, b []byte) bool { if a == nil && b == nil { return true @@ -124,7 +127,7 @@ func IsSameByteSlice(a []byte, b []byte) bool { return true } -// ByteFixedToBigInt convert bute slices to big.Int (bigendian) +// ByteSliceToBigInt convert bute slices to big.Int (bigendian) func ByteSliceToBigInt(slice []byte) *big.Int { bi := new(big.Int) bi.SetBytes(slice) @@ -138,17 +141,19 @@ func ByteFixedToBigInt(bytes []byte, size int) *big.Int { return bi } -// Useful for tests -func SimulateJsonDecodeForGocelery(kwargs map[string]interface{}) (map[string]interface{}, error) { +// SimulateJSONDecodeForGocelery encodes and decodes the kwargs. +func SimulateJSONDecodeForGocelery(kwargs map[string]interface{}) (map[string]interface{}, error) { t1 := gocelery.TaskMessage{Kwargs: kwargs} encoded, err := t1.Encode() if err != nil { return nil, err } + t2, err := gocelery.DecodeTaskMessage(encoded) return t2.Kwargs, err } +// IsValidByteSliceForLength checks if the len(slice) == length. func IsValidByteSliceForLength(slice []byte, length int) bool { return len(slice) == length } diff --git a/version/bootstrapper.go b/version/bootstrapper.go index 33df94c42..33c111146 100644 --- a/version/bootstrapper.go +++ b/version/bootstrapper.go @@ -1,8 +1,9 @@ package version -type Bootstrapper struct { -} +// Bootstrapper implements bootstrapper.Bootstrapper +type Bootstrapper struct{} +// Bootstrap logs the cent node version. func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { log.Infof("Running cent node on version: %s", GetVersion()) return nil diff --git a/version/check.go b/version/check.go index 8424d98f7..dda535bd5 100644 --- a/version/check.go +++ b/version/check.go @@ -21,7 +21,7 @@ func checkMajorCompatibility(versionString string) (match bool, err error) { return v.Major() == GetVersion().Major(), nil } -// checkVersion checks if the peer node version matches with the current node +// CheckVersion checks if the peer node version matches with the current node. func CheckVersion(peerVersion string) bool { compatible, err := checkMajorCompatibility(peerVersion) if err != nil { diff --git a/version/version.go b/version/version.go index 3bc2c7479..e171338ef 100644 --- a/version/version.go +++ b/version/version.go @@ -12,13 +12,12 @@ var gitCommit = "master" // CentrifugeNodeVersion is the current version of the app const CentrifugeNodeVersion = "0.0.1-alpha" +// GetVersion returns current cent node version in semvar format. func GetVersion() *semver.Version { - v, err := semver.NewVersion(fmt.Sprintf("%s+%s", CentrifugeNodeVersion, gitCommit)) if err != nil { log.Panicf("Invalid CentrifugeNodeVersion specified: %s", CentrifugeNodeVersion) } return v - } From 8b321c3bcc4a1cbab2d613b7cc3a268358e7b531 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 26 Nov 2018 19:33:32 +0100 Subject: [PATCH 045/220] Fixing merging issue with an earlier pr (#480) * Fixing merging issue with earlier pr * Fix --- queue/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queue/server.go b/queue/server.go index 2f5302751..8469ac2c9 100644 --- a/queue/server.go +++ b/queue/server.go @@ -51,8 +51,8 @@ type Server struct { taskTypes []TaskType } -// TaskTypeName of the queue server -func (qs *Server) TaskTypeName() string { +// Name of the queue server +func (qs *Server) Name() string { return "QueueServer" } From 42af1385321100f4833f77cdeca8f94164fb57b8 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 28 Nov 2018 13:58:22 +0100 Subject: [PATCH 046/220] Fix cmds that were broken (#494) * Fix cmds that were broken * Imports --- cmd/create_config.go | 7 ++++--- cmd/manage_identities.go | 6 ++++-- cmd/root.go | 21 ++++++++++++++++++--- node/bootstrapper.go | 2 +- node/node.go | 4 ++-- node/node_test.go | 6 +++--- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/cmd/create_config.go b/cmd/create_config.go index 1fc73b559..e1bb7d8eb 100644 --- a/cmd/create_config.go +++ b/cmd/create_config.go @@ -82,18 +82,18 @@ func init() { v, err := config.CreateConfigFile(data) if err != nil { - panic(err) + log.Fatalf("error: %v", err) } log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) - ctx := baseBootstrap(v.ConfigFileUsed()) + ctx, canc, _ := commandBootstrap(v.ConfigFileUsed()) cfg := ctx[config.BootstrappedConfig].(*config.Configuration) generateKeys(cfg) idService := ctx[identity.BootstrappedIDService].(identity.Service) id, err := createIdentity(idService) if err != nil { - panic(err) + log.Fatalf("error: %v", err) } v.Set("identityId", id.String()) @@ -109,6 +109,7 @@ func init() { if err != nil { log.Fatalf("error: %v", err) } + canc() }, } diff --git a/cmd/manage_identities.go b/cmd/manage_identities.go index 60f857e1d..810311917 100644 --- a/cmd/manage_identities.go +++ b/cmd/manage_identities.go @@ -17,7 +17,7 @@ var createIdentityCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file cfgFile = ensureConfigFile() - ctx := baseBootstrap(cfgFile) + ctx, canc, _ := commandBootstrap(cfgFile) var centID identity.CentID var err error if centIDString == "" { @@ -44,6 +44,7 @@ var createIdentityCmd = &cobra.Command{ panic(err) } log.Infof("Identity created [%s]", watchIdentity.Identity.CentID()) + canc() }, } @@ -55,7 +56,7 @@ var addKeyCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { //cmd requires a config file cfgFile = ensureConfigFile() - ctx := baseBootstrap(cfgFile) + ctx, canc, _ := commandBootstrap(cfgFile) var purposeInt int switch purpose { @@ -75,6 +76,7 @@ var addKeyCmd = &cobra.Command{ panic(err) } + canc() return }, } diff --git a/cmd/root.go b/cmd/root.go index 21c648de1..64c788e11 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,11 +1,15 @@ package cmd import ( + "context" "fmt" "os" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context" + c "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/node" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" "github.com/mitchellh/go-homedir" @@ -86,7 +90,7 @@ func setCentrifugeLoggers() { } func runBootstrap(cfgFile string) { - mb := context.MainBootstrapper{} + mb := c.MainBootstrapper{} mb.PopulateRunBootstrappers() ctx := map[string]interface{}{} ctx[config.BootstrappedConfigFile] = cfgFile @@ -98,7 +102,7 @@ func runBootstrap(cfgFile string) { } func baseBootstrap(cfgFile string) map[string]interface{} { - mb := context.MainBootstrapper{} + mb := c.MainBootstrapper{} mb.PopulateBaseBootstrappers() ctx := map[string]interface{}{} ctx[config.BootstrappedConfigFile] = cfgFile @@ -109,3 +113,14 @@ func baseBootstrap(cfgFile string) map[string]interface{} { } return ctx } + +func commandBootstrap(cfgFile string) (map[string]interface{}, context.CancelFunc, error) { + ctx := baseBootstrap(cfgFile) + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + // init node with only the queue server which is needed by commands + n := node.New([]node.Server{queueSrv}) + cx, canc := context.WithCancel(context.Background()) + e := make(chan error) + go n.Start(cx, e) + return ctx, canc, nil +} diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 2b4fda9a0..24cdb02a3 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -20,7 +20,7 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { return fmt.Errorf("failed to load servers: %v", err) } - n := NewNode(srvs) + n := New(srvs) feedback := make(chan error) // may be we can pass a context that exists in c here ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, c)) diff --git a/node/node.go b/node/node.go index a1042b37a..dfc09aaec 100644 --- a/node/node.go +++ b/node/node.go @@ -26,8 +26,8 @@ type Node struct { services []Server } -// NewNode returns a new Node with given services. -func NewNode(services []Server) *Node { +// New returns a new Node with given services. +func New(services []Server) *Node { return &Node{ services: services, } diff --git a/node/node_test.go b/node/node_test.go index 403b5b671..67fc0351c 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -51,7 +51,7 @@ func (s *MockService) Start(ctx context.Context, wg *sync.WaitGroup, startupErr func TestNode_StartHappy(t *testing.T) { // create node with two mocked out services services := []Server{&MockService{mustReturnStartErr: false}, &MockService{mustReturnStartErr: false}} - n := NewNode(services) + n := New(services) errChan := make(chan error) ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond) go n.Start(ctx, errChan) @@ -65,7 +65,7 @@ func TestNode_StartHappy(t *testing.T) { func TestNode_StartContextCancel(t *testing.T) { // create node with two mocked out services services := []Server{&MockService{mustReturnStartErr: false}, &MockService{mustReturnStartErr: false}} - n := NewNode(services) + n := New(services) errChan := make(chan error) ctx, canc := context.WithCancel(context.TODO()) go n.Start(ctx, errChan) @@ -82,7 +82,7 @@ func TestNode_StartContextCancel(t *testing.T) { func TestNode_StartChildError(t *testing.T) { // create node with two mocked out services services := []Server{&MockService{mustReturnStartErr: true}, &MockService{mustReturnStartErr: false}} - n := NewNode(services) + n := New(services) errChan := make(chan error) ctx, _ := context.WithCancel(context.TODO()) go n.Start(ctx, errChan) From 75979d324498d623454331e49951432422e1c817 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 29 Nov 2018 17:26:39 +0100 Subject: [PATCH 047/220] Remove storage.levelDBInstance global (#524) * Remove storage.levelDBInstance global * fix tests * fix tests * imports --- documents/invoice/bootstrapper.go | 6 ++- documents/invoice/repository.go | 6 +-- documents/invoice/repository_test.go | 19 ++++++++- documents/invoice/service_test.go | 42 +++++++++---------- documents/purchaseorder/bootstrapper.go | 8 ++-- documents/purchaseorder/repository.go | 6 +-- documents/purchaseorder/repository_test.go | 17 +++++++- documents/purchaseorder/service_test.go | 48 +++++++++++----------- storage/leveldb.go | 47 +-------------------- storage/leveldb_test.go | 17 +------- storage/test_bootstrapper.go | 15 ++++--- 11 files changed, 105 insertions(+), 126 deletions(-) diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 67c1405fe..22d9874c0 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -25,7 +26,8 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[storage.BootstrappedLevelDB]; !ok { + ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + if !ok { return errors.New("initializing LevelDB repository failed") } @@ -50,7 +52,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService(cfg, getRepository(ldb), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/repository.go b/documents/invoice/repository.go index 8d5a213dc..00d997c62 100644 --- a/documents/invoice/repository.go +++ b/documents/invoice/repository.go @@ -2,7 +2,7 @@ package invoice import ( "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" ) // repository is the invoice repository @@ -11,11 +11,11 @@ type repository struct { } // getRepository returns the implemented documents.legacyRepo for invoices -func getRepository() documents.Repository { +func getRepository(ldb *leveldb.DB) documents.Repository { return &repository{ documents.LevelDBRepository{ KeyPrefix: "invoice", - LevelDB: storage.GetLevelDBStorage(), + LevelDB: ldb, }, } } diff --git a/documents/invoice/repository_test.go b/documents/invoice/repository_test.go index ab66d5859..a961a3c62 100644 --- a/documents/invoice/repository_test.go +++ b/documents/invoice/repository_test.go @@ -5,12 +5,14 @@ package invoice import ( "testing" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) func TestRepository(t *testing.T) { - repo := getRepository() + repo := testRepo() invRepo := repo.(*repository) assert.Equal(t, invRepo.KeyPrefix, "invoice") assert.NotNil(t, invRepo.LevelDB, "missing leveldb instance") @@ -46,7 +48,20 @@ func TestRepository(t *testing.T) { } func TestRepository_getRepository(t *testing.T) { - r := getRepository() + r := testRepo() assert.NotNil(t, r) assert.Equal(t, "invoice", r.(*repository).KeyPrefix) } + +var testRepoGlobal documents.Repository + +func testRepo() documents.Repository { + if testRepoGlobal == nil { + ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + if err != nil { + panic(err) + } + testRepoGlobal = getRepository(ldb) + } + return testRepoGlobal +} diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 7703889db..318d5f587 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -45,14 +45,14 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) + srv := DefaultService(&config.Configuration{}, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(&config.Configuration{}, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) + return idService, DefaultService(&config.Configuration{}, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) } func createMockDocument() (*Invoice, error) { @@ -67,13 +67,13 @@ func createMockDocument() (*Invoice, error) { NextVersion: nextIdentifier, }, } - err := getRepository().Create(documentIdentifier, inv1) + err := testRepo().Create(documentIdentifier, inv1) return inv1, err } func TestService_DeriveFromCoreDocument(t *testing.T) { // nil doc - invSrv := service{repo: getRepository()} + invSrv := service{repo: testRepo()} _, err := invSrv.DeriveFromCoreDocument(nil) assert.Error(t, err, "must fail to derive") @@ -136,7 +136,7 @@ func TestService_GetLastVersion(t *testing.T) { }, } - err = getRepository().Create(doc.CoreDocument.NextVersion, inv2) + err = testRepo().Create(doc.CoreDocument.NextVersion, inv2) assert.Nil(t, err) mod2, err := invSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -157,7 +157,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := getRepository().Create(currentVersion, inv) + err := testRepo().Create(currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -176,7 +176,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := getRepository().Create(currentVersion, inv) + err := testRepo().Create(currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(documentIdentifier, currentVersion) @@ -199,7 +199,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := getRepository().Create(documentIdentifier, inv) + err := testRepo().Create(documentIdentifier, inv) assert.Nil(t, err) exists := invSrv.Exists(documentIdentifier) @@ -213,7 +213,7 @@ func TestService_Exists(t *testing.T) { func TestService_Create(t *testing.T) { ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) - invSrv := service{repo: getRepository()} + invSrv := service{repo: testRepo()} // calculate data root fails m, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) @@ -249,8 +249,8 @@ func TestService_Create(t *testing.T) { newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, getRepository().Exists(newCD.DocumentIdentifier)) - assert.True(t, getRepository().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(newCD.CurrentVersion)) } func TestService_DeriveInvoiceData(t *testing.T) { @@ -273,7 +273,7 @@ func TestService_DeriveInvoiceData(t *testing.T) { func TestService_DeriveInvoiceResponse(t *testing.T) { // success - invSrv := service{repo: getRepository()} + invSrv := service{repo: testRepo()} payload := testingdocuments.CreateInvoicePayload() contextHeader, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -326,7 +326,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = getRepository().Update(i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) @@ -438,7 +438,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { } if !skipSave { - err = getRepository().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -476,7 +476,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { if err != nil { return nil, err } - err = getRepository().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -521,7 +521,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = getRepository().Create(id, old) + err = testRepo().Create(id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ Sender: "0x010101010101", @@ -565,7 +565,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { } func TestService_Update(t *testing.T) { - invSrv := service{repo: getRepository()} + invSrv := service{repo: testRepo()} ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -594,7 +594,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) inv.(*Invoice).CoreDocument = cd - getRepository().Create(cd.CurrentVersion, inv) + testRepo().Create(cd.CurrentVersion, inv) // calculate data root fails model = &mockModel{} @@ -633,9 +633,9 @@ func TestService_Update(t *testing.T) { newCD, err := inv.PackCoreDocument() assert.Nil(t, err) - assert.True(t, getRepository().Exists(newCD.DocumentIdentifier)) - assert.True(t, getRepository().Exists(newCD.CurrentVersion)) - assert.True(t, getRepository().Exists(newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(newCD.PreviousVersion)) newData, err = invSrv.DeriveInvoiceData(inv) assert.Nil(t, err) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 3533bcca5..989328236 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -24,8 +25,9 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - if _, ok := ctx[storage.BootstrappedLevelDB]; !ok { - return errors.New("could not initialize purchase order repository") + ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + if !ok { + return errors.New("initializing LevelDB repository failed") } p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) @@ -49,7 +51,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(cfg, getRepository(), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService(cfg, getRepository(ldb), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/repository.go b/documents/purchaseorder/repository.go index 079e04f03..1d01a624a 100644 --- a/documents/purchaseorder/repository.go +++ b/documents/purchaseorder/repository.go @@ -2,7 +2,7 @@ package purchaseorder import ( "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" ) // repository is the purchase order repository @@ -11,11 +11,11 @@ type repository struct { } // getRepository returns the implemented documents.legacyRepo for purchase orders -func getRepository() documents.Repository { +func getRepository(ldb *leveldb.DB) documents.Repository { return &repository{ documents.LevelDBRepository{ KeyPrefix: "purchaseorder", - LevelDB: storage.GetLevelDBStorage(), + LevelDB: ldb, }, } } diff --git a/documents/purchaseorder/repository_test.go b/documents/purchaseorder/repository_test.go index f2e4d62bb..3cd3e1db2 100644 --- a/documents/purchaseorder/repository_test.go +++ b/documents/purchaseorder/repository_test.go @@ -5,11 +5,26 @@ package purchaseorder import ( "testing" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" ) func TestRepository_getRepository(t *testing.T) { - r := getRepository() + r := testRepo() assert.NotNil(t, r) assert.Equal(t, "purchaseorder", r.(*repository).KeyPrefix) } + +var testRepoGlobal documents.Repository + +func testRepo() documents.Repository { + if testRepoGlobal == nil { + ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + if err != nil { + panic(err) + } + testRepoGlobal = getRepository(ldb) + } + return testRepoGlobal +} diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 80ae08eb7..f0e1d5bed 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -44,11 +44,11 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(nil, getRepository(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return idService, DefaultService(nil, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func TestService_Update(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -77,7 +77,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) po.(*PurchaseOrder).CoreDocument = cd - getRepository().Create(cd.CurrentVersion, po) + testRepo().Create(cd.CurrentVersion, po) // calculate data root fails model = &testingdocuments.MockModel{} @@ -116,9 +116,9 @@ func TestService_Update(t *testing.T) { newCD, err := po.PackCoreDocument() assert.Nil(t, err) - assert.True(t, getRepository().Exists(newCD.DocumentIdentifier)) - assert.True(t, getRepository().Exists(newCD.CurrentVersion)) - assert.True(t, getRepository().Exists(newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(newCD.PreviousVersion)) newData, err = poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -126,7 +126,7 @@ func TestService_Update(t *testing.T) { } func TestService_DeriveFromUpdatePayload(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} // nil payload doc, err := poSrv.DeriveFromUpdatePayload(nil, nil) @@ -164,7 +164,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = getRepository().Create(id, old) + err = testRepo().Create(id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "0x010203040506", @@ -245,7 +245,7 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { func TestService_DeriveFromCoreDocument(t *testing.T) { // nil doc - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} _, err := poSrv.DeriveFromCoreDocument(nil) assert.Error(t, err, "must fail to derive") @@ -264,7 +264,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { func TestService_Create(t *testing.T) { ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} // calculate data root fails m, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) @@ -301,8 +301,8 @@ func TestService_Create(t *testing.T) { newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, getRepository().Exists(newCD.DocumentIdentifier)) - assert.True(t, getRepository().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(newCD.CurrentVersion)) } func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, error) { @@ -353,7 +353,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er } if !skipSave { - err = getRepository().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -398,7 +398,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = getRepository().Update(i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) @@ -452,7 +452,7 @@ func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseO if err != nil { return nil, err } - err = getRepository().Create(model.CoreDocument.CurrentVersion, model) + err = testRepo().Create(model.CoreDocument.CurrentVersion, model) if err != nil { return nil, err } @@ -564,12 +564,12 @@ func createMockDocument() (*PurchaseOrder, error) { NextVersion: nextIdentifier, }, } - err := getRepository().Create(documentIdentifier, model) + err := testRepo().Create(documentIdentifier, model) return model, err } func TestService_GetCurrentVersion(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) @@ -589,7 +589,7 @@ func TestService_GetCurrentVersion(t *testing.T) { }, } - err = getRepository().Create(doc.CoreDocument.NextVersion, po2) + err = testRepo().Create(doc.CoreDocument.NextVersion, po2) assert.Nil(t, err) mod2, err := poSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -601,7 +601,7 @@ func TestService_GetCurrentVersion(t *testing.T) { } func TestService_GetVersion_invalid_version(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} currentVersion := utils.RandomSlice(32) po := &PurchaseOrder{ @@ -611,7 +611,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := getRepository().Create(currentVersion, po) + err := testRepo().Create(currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -620,7 +620,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { } func TestService_GetVersion(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) @@ -631,7 +631,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := getRepository().Create(currentVersion, po) + err := testRepo().Create(currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(documentIdentifier, currentVersion) @@ -654,7 +654,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := getRepository().Create(documentIdentifier, po) + err := testRepo().Create(documentIdentifier, po) assert.Nil(t, err) exists := poSrv.Exists(documentIdentifier) @@ -681,7 +681,7 @@ func TestService_RequestDocumentSignature(t *testing.T) { } func TestService_calculateDataRoot(t *testing.T) { - poSrv := service{repo: getRepository()} + poSrv := service{repo: testRepo()} ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) diff --git a/storage/leveldb.go b/storage/leveldb.go index 4af6cc92d..05b100406 100644 --- a/storage/leveldb.go +++ b/storage/leveldb.go @@ -1,60 +1,17 @@ package storage import ( - "fmt" - "sync" - logging "github.com/ipfs/go-log" "github.com/syndtr/goleveldb/leveldb" ) var log = logging.Logger("storage") -// levelDBInstance is levelDB instance -var levelDBInstance *leveldb.DB - -// lock to guard the levelDB instance -var lock sync.Mutex - // NewLevelDBStorage is a singleton implementation returning the default database as configured. func NewLevelDBStorage(path string) (*leveldb.DB, error) { - if levelDBInstance != nil { - return nil, fmt.Errorf("db already open") - } - - lock.Lock() - defer lock.Unlock() i, err := leveldb.OpenFile(path, nil) if err != nil { - log.Fatal(err) - } - - levelDBInstance = i - return levelDBInstance, nil -} - -// GetLevelDBStorage returns levelDB instance if initialised -// panics if not initialised -func GetLevelDBStorage() *leveldb.DB { - if levelDBInstance == nil { - log.Fatalf("LevelDB not initialised") + return nil, err } - - return levelDBInstance -} - -// CloseLevelDBStorage closes any open instance of levelDB -func CloseLevelDBStorage() { - if levelDBInstance == nil { - return - } - - lock.Lock() - defer lock.Unlock() - err := levelDBInstance.Close() - if err != nil { - log.Infof("failed to close the level DB: %v", err) - } - - levelDBInstance = nil + return i, nil } diff --git a/storage/leveldb_test.go b/storage/leveldb_test.go index 01e218d89..66831495e 100644 --- a/storage/leveldb_test.go +++ b/storage/leveldb_test.go @@ -9,23 +9,8 @@ import ( ) func TestNewLevelDBStorage(t *testing.T) { - path := getRandomTestStoragePath() + path := GetRandomTestStoragePath() db, err := NewLevelDBStorage(path) assert.Nil(t, err) assert.NotNil(t, db) - assert.NotNil(t, levelDBInstance) - assert.Equal(t, db, levelDBInstance) - - gdb := GetLevelDBStorage() - assert.NotNil(t, gdb) - assert.Equal(t, db, gdb) - - // fail - db, err = NewLevelDBStorage(path) - assert.Error(t, err) - assert.Contains(t, err.Error(), "db already open") - assert.Nil(t, db) - - CloseLevelDBStorage() - assert.Nil(t, levelDBInstance) } diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index bbcb7de88..7058a88cc 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -7,31 +7,34 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" + "github.com/syndtr/goleveldb/leveldb" ) const testStoragePath = "/tmp/centrifuge_data.leveldb_TESTING" -func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { - rs := getRandomTestStoragePath() +var db *leveldb.DB + +func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { + rs := GetRandomTestStoragePath() cfg := context[config.BootstrappedConfig].(*config.Configuration) cfg.SetDefault("storage.Path", rs) log.Info("Set storage.Path to:", cfg.GetStoragePath()) - levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) + db, err = NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return fmt.Errorf("failed to init level db: %v", err) } log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) - context[BootstrappedLevelDB] = levelDB + context[BootstrappedLevelDB] = db return nil } func (*Bootstrapper) TestTearDown() error { - CloseLevelDBStorage() + db.Close() // os.RemoveAll(config.Config.GetStoragePath()) return nil } -func getRandomTestStoragePath() string { +func GetRandomTestStoragePath() string { return fmt.Sprintf("%s_%x", testStoragePath, utils.RandomByte32()) } From 7d5ca1ee6ac37c160282a6982314afd51eb5fafe Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 29 Nov 2018 17:37:50 +0100 Subject: [PATCH 048/220] Rename `go-centrifuge` to `centrifuge` (#525) Fixes #493 --- Dockerfile | 4 ++-- Makefile | 8 ++++---- build/scripts/docker/entrypoint.sh | 2 +- cmd/{ => centrifuge}/create_config.go | 2 +- cmd/{ => centrifuge}/generate_signing_key.go | 2 +- cmd/centrifuge/main.go | 5 +++++ cmd/{ => centrifuge}/manage_identities.go | 2 +- cmd/{ => centrifuge}/root.go | 3 +-- cmd/{ => centrifuge}/run.go | 2 +- cmd/{ => centrifuge}/sign_message.go | 2 +- cmd/{ => centrifuge}/verify_message.go | 2 +- cmd/{ => centrifuge}/version.go | 2 +- main.go | 9 --------- 13 files changed, 20 insertions(+), 25 deletions(-) rename cmd/{ => centrifuge}/create_config.go (99%) rename cmd/{ => centrifuge}/generate_signing_key.go (99%) create mode 100644 cmd/centrifuge/main.go rename cmd/{ => centrifuge}/manage_identities.go (99%) rename cmd/{ => centrifuge}/root.go (98%) rename cmd/{ => centrifuge}/run.go (96%) rename cmd/{ => centrifuge}/sign_message.go (99%) rename cmd/{ => centrifuge}/verify_message.go (99%) rename cmd/{ => centrifuge}/version.go (96%) delete mode 100644 main.go diff --git a/Dockerfile b/Dockerfile index e8a9dbff3..a641718df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,14 +5,14 @@ RUN apk update && apk add --no-cache openssh git jq curl gcc libc-dev build-base ADD . /go/src/github.com/centrifuge/go-centrifuge WORKDIR /go/src/github.com/centrifuge/go-centrifuge -RUN go install -ldflags "-X github.com/centrifuge/go-centrifuge/version.gitCommit=`git rev-parse HEAD`" ./... +RUN go install -ldflags "-X github.com/centrifuge/go-centrifuge/version.gitCommit=`git rev-parse HEAD`" ./cmd/centrifuge/... FROM alpine:latest RUN apk update && apk add --no-cache jq curl WORKDIR /root/ -COPY --from=builder /go/bin/go-centrifuge . +COPY --from=builder /go/bin/centrifuge . COPY build/scripts/docker/entrypoint.sh /root VOLUME ["/root/config"] diff --git a/Makefile b/Makefile index 81ad72844..b9b02c23f 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ install-deps: ## Install Dependencies @curl -L https://git.io/vp6lP | sh @mv ./bin/* $(GOPATH)/bin/; rm -rf ./bin -lint-check: ## formats go code +lint-check: ## runs linters on go code @gometalinter --disable-all --enable=golint --enable=goimports --enable=vet --enable=nakedret \ --enable=staticcheck --vendor --skip=resources --skip=testingutils --skip=protobufs --deadline=1m ./...; @@ -60,7 +60,7 @@ vendorinstall: ## Installs all protobuf dependencies with go-vendorinstall install: ## Builds and Install binary for development install: install-deps vendorinstall - @go install ./... + @go install ./cmd/centrifuge/... install-xgo: ## Install XGO @echo "Ensuring XGO is installed" @@ -70,8 +70,8 @@ build-linux-amd64: ## Build linux/amd64 build-linux-amd64: install-xgo @echo "Building amd64 with flags [${LD_FLAGS}]" @mkdir -p build/linux-amd64 - @xgo -go 1.11.x -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} . - @mv build/linux-amd64/go-centrifuge-linux-amd64 build/linux-amd64/go-centrifuge + @xgo -go 1.11.x -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} ./cmd/centrifuge/ + @mv build/linux-amd64/centrifuge-linux-amd64 build/linux-amd64/centrifuge @tar -zcvf cent-api-linux-amd64-${TAG}.tar.gz -C build/linux-amd64/ . build-docker: ## Build Docker Image diff --git a/build/scripts/docker/entrypoint.sh b/build/scripts/docker/entrypoint.sh index 5cca2e683..f5834c4bc 100755 --- a/build/scripts/docker/entrypoint.sh +++ b/build/scripts/docker/entrypoint.sh @@ -4,4 +4,4 @@ set -x CENT_MODE=${CENT_MODE:-run} -/root/go-centrifuge ${CENT_MODE} --config /root/.centrifuge/config/config.yaml $@ +/root/centrifuge ${CENT_MODE} --config /root/.centrifuge/config/config.yaml $@ diff --git a/cmd/create_config.go b/cmd/centrifuge/create_config.go similarity index 99% rename from cmd/create_config.go rename to cmd/centrifuge/create_config.go index e1bb7d8eb..9e890cd8d 100644 --- a/cmd/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "os" diff --git a/cmd/generate_signing_key.go b/cmd/centrifuge/generate_signing_key.go similarity index 99% rename from cmd/generate_signing_key.go rename to cmd/centrifuge/generate_signing_key.go index c89b48fad..5ed688490 100644 --- a/cmd/generate_signing_key.go +++ b/cmd/centrifuge/generate_signing_key.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "github.com/centrifuge/go-centrifuge/keytools" diff --git a/cmd/centrifuge/main.go b/cmd/centrifuge/main.go new file mode 100644 index 000000000..736ef3102 --- /dev/null +++ b/cmd/centrifuge/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + Execute() +} diff --git a/cmd/manage_identities.go b/cmd/centrifuge/manage_identities.go similarity index 99% rename from cmd/manage_identities.go rename to cmd/centrifuge/manage_identities.go index 810311917..02a732eb6 100644 --- a/cmd/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "io/ioutil" diff --git a/cmd/root.go b/cmd/centrifuge/root.go similarity index 98% rename from cmd/root.go rename to cmd/centrifuge/root.go index 64c788e11..327cdf1ca 100644 --- a/cmd/root.go +++ b/cmd/centrifuge/root.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "context" @@ -25,7 +25,6 @@ var verbose bool var rootCmd = &cobra.Command{ Use: "centrifuge", Short: "Centrifuge protocol node", - Long: `POC for centrifuge app`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, diff --git a/cmd/run.go b/cmd/centrifuge/run.go similarity index 96% rename from cmd/run.go rename to cmd/centrifuge/run.go index e7ddd061c..a67e99a1e 100644 --- a/cmd/run.go +++ b/cmd/centrifuge/run.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "github.com/spf13/cobra" diff --git a/cmd/sign_message.go b/cmd/centrifuge/sign_message.go similarity index 99% rename from cmd/sign_message.go rename to cmd/centrifuge/sign_message.go index 449df1ad5..a69ef7892 100644 --- a/cmd/sign_message.go +++ b/cmd/centrifuge/sign_message.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "fmt" diff --git a/cmd/verify_message.go b/cmd/centrifuge/verify_message.go similarity index 99% rename from cmd/verify_message.go rename to cmd/centrifuge/verify_message.go index bb15325ee..5424a171b 100644 --- a/cmd/verify_message.go +++ b/cmd/centrifuge/verify_message.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "fmt" diff --git a/cmd/version.go b/cmd/centrifuge/version.go similarity index 96% rename from cmd/version.go rename to cmd/centrifuge/version.go index 1b3df46ad..dd2938bf7 100644 --- a/cmd/version.go +++ b/cmd/centrifuge/version.go @@ -1,4 +1,4 @@ -package cmd +package main import ( "fmt" diff --git a/main.go b/main.go deleted file mode 100644 index 8033083b8..000000000 --- a/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/centrifuge/go-centrifuge/cmd" -) - -func main() { - cmd.Execute() -} From 839689be99bef0ac132f402fed298db81ebf8dc0 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 29 Nov 2018 17:55:25 +0100 Subject: [PATCH 049/220] use http jsonrpc (#522) --- README.md | 4 ++-- build/configs/default_config.yaml | 2 +- build/scripts/test-dependencies/test-ethereum/env_vars.sh | 2 +- cmd/centrifuge/create_config.go | 2 +- config/configuration_test.go | 2 +- resources/data.go | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ed30c0a11..41e30bd97 100644 --- a/README.md +++ b/README.md @@ -189,8 +189,8 @@ Let it catch up for a while until is fully synced with the remote peer - In go-centrifuge project run: - ./build/scripts/docker/run.sh rinkeby - Wait until node is in sync with remote peer (1-2 hours): - - geth attach ws://localhost:9546 --exec "net.peerCount" > 0 (rinkeby takes additional time to sync as it needs a peer to pull from, and has shortage of full node peers) - - geth attach ws://localhost:9546 --exec "eth.syncing" -> false + - geth attach http://localhost:9545 --exec "net.peerCount" > 0 (rinkeby takes additional time to sync as it needs a peer to pull from, and has shortage of full node peers) + - geth attach http://localhost:9545 --exec "eth.syncing" -> false - Run tests: - To run only integration tests: - CENT_CENTRIFUGENETWORK='russianhill' TEST_TARGET_ENVIRONMENT='rinkeby' CENT_ETHEREUM_ACCOUNTS_MAIN_KEY='$JSON_KEY' CENT_ETHEREUM_ACCOUNTS_MAIN_PASSWORD="$PASS" CENT_ETHEREUM_ACCOUNTS_MAIN_ADDRESS="$ADDR" ./build/scripts/tests/run_integration_tests.sh diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index c28a87c48..d1016c613 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -65,7 +65,7 @@ ethereum: # Selects which ethereum account to use of the ones provided in the custom config file defaultAccountName: "main" # Location of the ethereum client node (we require ws or ipc to be able to catch events) - nodeURL: ws://localhost:9546 + nodeURL: http://localhost:9545 # Default gas price gasPrice: 1000000000 # Default gas limit diff --git a/build/scripts/test-dependencies/test-ethereum/env_vars.sh b/build/scripts/test-dependencies/test-ethereum/env_vars.sh index cdbc769d5..b38a38efe 100755 --- a/build/scripts/test-dependencies/test-ethereum/env_vars.sh +++ b/build/scripts/test-dependencies/test-ethereum/env_vars.sh @@ -7,7 +7,7 @@ IDENTITY=CentTestEth GETH_DOCKER_CONTAINER_NAME="geth-node" CENT_ETHEREUM_CONTRACTS_DIR=${PARENT_DIR}/vendor/github.com/centrifuge/centrifuge-ethereum-contracts CENT_ETHEREUM_CONTEXTWAITTIMEOUT="180s" -CENT_ETHEREUM_NODEURL=${CENT_ETHEREUM_NODEURL:-ws://localhost:$WS_PORT} +CENT_ETHEREUM_NODEURL=${CENT_ETHEREUM_NODEURL:-http://localhost:$RPC_PORT} CENT_ETHEREUM_GASLIMIT=4712388 CENT_ETHEREUM_GASPRICE=1000000000 CENT_ETHEREUM_GETH_START_TIMEOUT=${CENT_ETHEREUM_GETH_START_TIMEOUT_OVERRIDE:-600} # In Seconds, default 10 minutes diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index 9e890cd8d..b3b2cf402 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -114,7 +114,7 @@ func init() { } createConfigCmd.Flags().StringVarP(&targetDataDir, "targetdir", "t", home+"/datadir", "Target Data Dir") - createConfigCmd.Flags().StringVarP(ðNodeURL, "ethnodeurl", "e", "ws://127.0.0.1:9546", "URL of Ethereum Client Node") + createConfigCmd.Flags().StringVarP(ðNodeURL, "ethnodeurl", "e", "http://127.0.0.1:9545", "URL of Ethereum Client Node") createConfigCmd.Flags().StringVarP(&accountKeyPath, "accountkeypath", "z", home+"/datadir/main.key", "Path of Ethereum Account Key JSON file") createConfigCmd.Flags().StringVarP(&accountPassword, "accountpwd", "k", "", "Ethereum Account Password") createConfigCmd.Flags().Int64VarP(&apiPort, "apiPort", "a", 8082, "Api Port") diff --git a/config/configuration_test.go b/config/configuration_test.go index 62b786368..939603873 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -26,7 +26,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { "accountKeyPath": accountKeyPath, "accountPassword": "pwrd", "network": "russianhill", - "ethNodeURL": "ws://127.0.0.1:9546", + "ethNodeURL": "http://127.0.0.1:9545", "bootstraps": []string{"/ip4/127.0.0.1/bootstrap1", "/ip4/127.0.0.1/bootstrap2"}, "apiPort": int64(8082), "p2pPort": int64(38202), diff --git a/resources/data.go b/resources/data.go index 64c5cf020..2548ab5f7 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x59\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xae\xd2\xe0\x92\xdc\x92\x5c\x8f\xf9\xf5\x1b\xf2\x83\x06\x7a\x60\x37\x36\x62\x76\x38\x29\xac\xcc\x2f\x5f\xdf\xa7\x4a\xde\xc1\x29\xd6\xa2\x6b\x02\x28\xdc\x60\x63\xdb\x35\x9a\x00\x01\x7d\x30\x18\x40\x2c\x85\x36\x3e\x80\xd3\xe6\x01\xab\xfd\x4c\xa2\x09\x4e\xd7\xdd\x12\x2f\x30\x6c\xad\x7b\x98\x83\xeb\xbc\xd7\xc2\xac\x74\xd3\xcc\x7a\x30\x6d\x10\xc2\x0a\x41\x8d\xb8\x66\xb0\xf4\x10\x56\x22\xc0\xc9\x23\x02\xac\x85\x36\x21\xe2\xcf\x26\x93\xf9\x0c\xe0\x1d\x9c\x5b\x29\x9a\x3e\x05\x6d\x96\x20\xad\x09\x4e\xc8\x00\x42\x29\x87\xde\xa3\x07\x83\xa8\x20\x58\xa8\x10\x3c\x06\xd8\xea\xb0\x02\x34\x1b\xd8\x08\xa7\x45\xd5\xa0\x3f\x9c\xc1\xe4\x1f\x21\x01\xb4\x9a\x03\x63\xac\x3f\x63\x58\xa1\xc3\x6e\x3d\x56\xf0\x8b\x9a\x43\xc1\x8a\xe1\xae\xb2\x36\xf8\xe0\x44\x7b\x89\xe8\xfc\xe0\x0b\xf0\x1e\x0e\x8e\x74\x9b\x1e\x25\x34\x3f\x24\x87\xe4\x30\x39\x0a\xb2\x3d\x62\x05\x25\xf4\x48\xb7\xb5\x3f\xba\x5a\xdf\x5c\xed\xaa\xed\x43\x77\x7f\x77\x77\x5a\x77\x7f\xdc\x54\xbb\xb3\xe3\x05\xde\x5c\x9c\x9c\xdb\x3f\xf6\xfb\x2c\x2b\x36\x57\x66\xf9\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\xcb\x26\xd8\xaf\x35\x3f\xbb\xe0\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xfa\xed\xb2\x4b\xf8\x6f\xad\xfa\x89\x3d\xfc\x6a\x93\x1b\xb6\x5e\x89\xd5\xe5\x87\xec\x1a\x33\x93\x0c\xb0\x53\xbb\x8e\xa7\x6e\x4d\x45\x68\x85\x26\xe8\xb0\xff\x28\x64\xb0\x6e\x3f\x87\x83\x83\x17\x37\x0b\x5c\x6a\x1f\x9e\x5d\x09\x23\x57\xd6\x2d\xb0\xb5\x5e\xbf\xf0\x6a\xc5\x3e\x52\xe5\x5f\x55\xa3\x97\x22\x68\x6b\xfa\xbb\x7e\x80\x9f\x85\x36\x7f\x4a\xa7\x71\xce\x33\x78\xca\x9a\x21\xc1\x77\x70\xd1\xad\xd1\x69\x09\xbf\x9c\x82\xad\x7b\x06\x3d\xe1\xca\x77\xcf\x61\x98\x59\x32\x7a\x7d\x98\x26\x06\x8d\xf6\x21\x7a\x1a\xab\xf0\x47\xb2\xb5\xce\x6e\x74\x7f\x61\x7b\xec\x27\x09\x4c\xe9\xfd\x17\x0c\x60\xd9\x21\xa5\xd9\x21\x25\xe4\x30\xa5\x2f\x59\x90\xd0\x53\xf6\xc9\xda\xdb\x73\xad\xe5\xd5\xd7\xed\xcd\xea\xe6\xc3\x1d\xdf\x7d\x92\x97\xf6\xbc\xe6\x8b\xab\xbb\x5f\x3f\xb6\xdb\x3a\x71\x79\xb6\x3d\xdf\xd1\xfb\x05\x6b\x4f\x54\xf2\x92\x0b\x63\x80\x82\x1f\xd2\x84\xbc\x16\xe0\xea\xfe\xf3\x71\xf1\xd3\xe5\xcf\x6e\x73\x76\xff\xa1\xdc\xaa\x07\xfb\x45\x1e\x1f\xaf\x4f\xee\x7f\x6e\x4b\xdc\xef\xef\xd3\xeb\xb3\x62\xf9\xd1\xb1\xd5\xcd\xc5\x6f\x07\x63\x9f\xce\x46\xd6\x4f\x9d\x8c\x6d\x7e\x0f\x8b\x51\xd7\xaf\xe8\x22\x1d\x9d\xcf\x45\x6c\x11\x28\x6c\x1b\xbb\x47\x05\xd7\x6b\xe1\x02\x9c\x8c\x54\xf3\x50\x5b\xd7\x37\x75\xa9\x37\x68\x9e\xb5\xf3\x47\x3a\xc2\xab\x7c\x24\xbb\x92\x28\x5a\xa6\x59\x9e\x60\xce\x8a\x94\xf2\x32\x17\x9c\x57\xb9\x28\x4b\x41\x4a\xa5\xb8\xcc\x99\x62\x19\x57\x6f\x30\x97\xec\x4a\xce\x89\x24\xac\x54\x2c\x49\xd2\x8c\x89\x9a\xa8\xac\x90\x19\xe7\x3c\xa7\x4c\x95\x92\xd6\x22\x57\x1c\xe5\x1b\x1c\x27\xbb\xbc\x2e\xb2\x54\xd5\xa2\x2c\x48\x42\x55\x5e\x8b\x2c\x93\x05\x61\x55\x25\x28\xe5\xa4\x92\x0a\x31\xad\x32\x54\x6f\xa9\x81\xec\x78\x99\xd0\x82\xf0\x3c\xaf\x32\x8a\x4c\x8a\x3c\x41\x42\x19\xa2\xa2\xaa\x60\xb5\x28\x6b\x21\x59\xc5\xd3\xaa\xd7\x4d\x85\xce\x88\x66\x85\x7a\xb9\x0a\xfe\x7f\x13\x05\xfd\x3f\x8a\xe2\x2f\x96\xc4\xdf\x24\x88\x4f\x76\x23\xcc\xab\x72\xa0\x7f\x81\x1e\xde\x90\x43\x91\x55\x8c\xd6\xb9\x60\x75\x4a\xd2\x22\xa9\x13\xca\x58\x4a\xd2\x84\xe7\x44\x16\xb2\x42\x92\xd7\xb9\xca\x4b\xf9\xa6\x1c\xb2\x54\x20\xcb\x59\x4d\x4a\x5e\x8b\x9a\xaa\x8a\x57\x85\x48\x79\x9e\xe4\x92\x54\x65\x81\xb2\x16\x24\xcf\x94\x7a\x53\x0e\x69\x9a\xd6\x3c\x2d\x91\x91\x3c\x4d\x29\xe6\x5c\xca\x3a\x67\x79\xca\x39\x66\xb4\x4e\x38\x29\xab\xb2\xa0\x9c\xbc\x2d\x07\xc1\x14\xab\xd2\xac\x4e\x29\x25\x09\xa7\x24\x51\xb9\x54\xa9\xa4\x95\xa4\x49\xce\x79\x96\x16\x4c\x95\x04\xf9\xc1\x6c\xf6\x0e\x22\xd5\xde\x07\xfb\xbe\x45\x74\xb1\x6d\xb5\x5e\x76\xae\xc7\xf2\xb3\x96\xb6\xc3\xaa\x70\xa3\xd7\x68\xbb\x00\xdb\x15\x1a\xb0\x2d\x9a\x71\x63\x30\x28\x7b\xcb\x48\xec\x08\xe0\x67\x30\x7d\x1e\x5d\xe6\x70\xc0\x88\xef\x23\x5d\x75\xd8\xe1\x8b\x10\xfd\x08\x85\xdf\x1b\xb9\x72\xd6\xd8\xce\x47\xad\x48\xf4\x5e\x9b\xe5\xec\x5b\x74\x18\x12\x18\xf6\x1d\xdf\x4f\xdb\x74\xeb\x0a\x5d\x54\x5b\x24\x0c\x3a\x7f\x24\xad\xf1\x51\xc0\xa3\xf2\xb6\x51\x57\x15\x82\x68\x1a\x2b\x45\x40\x05\x22\x80\x0f\xc2\x85\xae\x9d\x41\xf4\xbf\x1d\x1c\xe7\x40\x7b\xf4\x8f\x0e\xd1\x43\xd7\xc2\xc9\xe5\x17\x90\x7b\xd9\xa0\x1f\x4a\x1d\x02\x80\xf6\xb0\x15\xba\x5f\x93\x62\xbe\xb8\x41\x13\x62\xa9\xc3\xf5\xad\xd0\x7d\xb5\x9f\xaf\xe7\x90\xc4\x42\x1f\x29\xef\x5b\x94\xba\xd6\xf2\x79\xd1\xb3\x89\xf2\x43\x69\xd7\xd8\x60\x24\xf3\x76\xa5\xe5\xea\x51\x0e\x20\xa4\xb4\x5d\xfc\x4d\xb7\xd0\x79\x9c\x5e\x25\x1b\x9b\x30\x3e\x27\x0a\xb4\xe9\x3f\xca\xce\x07\xbb\x1e\x83\x40\xad\x1b\x9c\xc1\xb4\x16\x1e\x0f\x30\x17\x62\x8d\x73\x38\x88\xab\xe0\xc1\xe3\xf2\x17\x93\x99\x80\x1f\xe3\xca\x46\xc7\x55\x22\x3e\x64\xf0\x8f\x2d\x82\xc3\x6f\x9d\x76\x08\x5b\x0f\xd6\x81\x6e\xe5\xb8\x11\xc6\x05\x30\x1e\xa5\x08\x31\xed\xbe\x25\xff\x8c\xdd\xb5\x0a\xbf\x2c\xce\xe7\xb0\xf5\xf3\xa3\xa3\x38\x80\x66\x65\x7d\x98\x97\x59\xca\xa7\x51\xf6\xfb\xea\x52\xc4\x4a\xb4\x8c\xc9\x2e\x85\xbf\x8c\xc7\x39\x24\x64\xfa\xfb\xc1\xb8\xd1\x6b\x1d\x06\xe3\xf3\x78\x9c\x43\x9a\x27\x94\x15\xc5\x33\x8a\x06\xdb\xcf\x6a\x20\x96\xf9\x5e\x57\x70\xc2\x78\xd1\xd3\x75\xaa\x40\xa9\x61\xbf\x15\x50\x35\x56\x3e\x80\x30\x6a\x2c\x04\x82\xd3\xcb\x25\x3a\x54\x03\xa1\x03\xee\xc2\x34\xe6\x81\xd4\x9c\x44\x56\xbf\x16\xd8\xa1\x50\x60\x4d\xb3\x8f\x62\x99\xa8\x3e\x2d\xf9\x53\x4a\xdf\xa1\x17\x28\xd4\x73\xf8\x24\x1b\xd1\x2f\xe2\x1c\x9e\xe6\xde\x5a\xdb\xc0\x5a\xec\xc0\x61\x70\x7a\xf8\x4d\xf1\x68\x14\x88\x67\x66\x76\x83\x6e\x06\xd1\x70\x31\xd8\xcd\x81\x8e\x3d\xfd\x73\x48\x6d\x02\xba\x8d\x68\x7a\xdc\xfd\x40\x7f\x11\x13\x94\x9d\x73\xfd\x72\xf9\xc4\x63\x25\x3c\x54\x88\x71\xfb\x0c\x28\x43\xdf\xa6\x09\x20\xc6\x8b\xaf\x19\x1d\x2b\x38\xd5\xbe\xe7\x4a\x8f\xe8\xed\xfa\x07\xae\x79\x50\x16\x8c\x0d\xe0\xbb\xb6\xb5\x2e\x40\xd8\xf5\x19\x89\x56\xc7\xff\x2f\x76\x97\xd6\x36\xc7\x32\x3e\x0a\x67\x26\x22\xa9\x39\x04\xd7\x61\x54\x9a\x30\x7b\x50\x58\x75\xcb\xe5\xf8\x20\x45\x01\xf4\xf2\x5f\x5a\x88\x41\x66\xfd\xed\x20\xb4\xb6\x75\xb6\xee\xc7\xf3\xe8\x32\x83\xe1\xeb\x1c\x6a\xd1\x78\x9c\xfd\x3b\x00\x00\xff\xff\xbc\x1e\x8e\x26\xa6\x0d\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x5b\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xb6\x35\xb8\x24\xb7\x24\xd7\x63\x7e\xfd\x86\xfc\xa0\x81\x1e\xd8\x8d\x8d\x98\x1d\x4e\x0a\x2b\xf3\xcb\xd7\xf7\xa9\x92\x77\x70\x8a\x15\xef\x5b\x0f\x12\x37\xd8\x9a\x6e\x8d\xda\x83\x47\xe7\x35\x7a\xe0\x35\x57\xda\x79\xb0\x4a\x3f\x60\xb9\x5f\x08\xd4\xde\xaa\xaa\xaf\xf1\x02\xfd\xd6\xd8\x87\x25\xd8\xde\x39\xc5\x75\xa3\xda\x76\x31\x80\x29\x8d\xe0\x1b\x04\x39\xe1\xea\xd1\xd2\x81\x6f\xb8\x87\x93\x47\x04\x58\x73\xa5\x7d\xc0\x5f\xcc\x26\xcb\x05\xc0\x3b\x38\x37\x82\xb7\x43\x0a\x4a\xd7\x20\x8c\xf6\x96\x0b\x0f\x5c\x4a\x8b\xce\xa1\x03\x8d\x28\xc1\x1b\x28\x11\x1c\x7a\xd8\x2a\xdf\x00\xea\x0d\x6c\xb8\x55\xbc\x6c\xd1\x1d\x2e\x60\xf6\x0f\x90\x00\x4a\x2e\x81\x52\x3a\x9c\xd1\x37\x68\xb1\x5f\x4f\x15\xfc\x22\x97\x90\xd3\x7c\xbc\x2b\x8d\xf1\xce\x5b\xde\x5d\x22\x5a\x37\xfa\x02\xbc\x87\x83\x23\xd5\x25\x47\x31\xc9\x0e\xa3\xc3\xe8\x30\x3e\xf2\xa2\x3b\xa2\x39\x89\xc8\x91\xea\x2a\x77\x74\xb5\xbe\xb9\xda\x95\xdb\x87\xfe\xfe\xee\xee\xb4\xea\xff\xb8\x29\x77\x67\xc7\x2b\xbc\xb9\x38\x39\x37\x7f\xec\xf7\x69\x9a\x6f\xae\x74\xfd\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\x4b\x67\xd8\xaf\x15\x3b\xbb\x60\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xf2\xed\xb2\x8f\xd9\x6f\x9d\xfc\x89\x3e\xfc\x6a\xe2\x1b\xba\x6e\x78\x73\xf9\x21\xbd\xc6\x54\xc7\x23\xec\xdc\xae\xe3\xb9\x5b\x73\x11\x4a\xa2\xf6\xca\xef\x3f\x72\xe1\x8d\xdd\x2f\xe1\xe0\xe0\xc5\xcd\x0a\x6b\xe5\xfc\xb3\x2b\xae\x45\x63\xec\x0a\x3b\xe3\xd4\x0b\xaf\x8e\xef\x03\x55\xfe\x55\xb6\xaa\xe6\x5e\x19\x3d\xdc\x0d\x03\xfc\xcc\x95\xfe\x53\x3a\x4d\x73\x5e\xc0\x53\xd6\x8c\x09\xbe\x83\x8b\x7e\x8d\x56\x09\xf8\xe5\x14\x4c\x35\x30\xe8\x09\x57\xbe\x7b\x8e\xc3\x4c\xe3\xc9\xeb\xc3\x3c\x31\x68\x95\xf3\xc1\x53\x1b\x89\x3f\x92\xad\xb3\x66\xa3\x86\x0b\x33\x60\x3f\x49\x60\x4e\xef\xbf\x60\x00\x4d\x0f\x09\x49\x0f\x49\x14\x1d\x26\xe4\x25\x0b\x62\x72\x4a\x3f\x19\x73\x7b\xae\x94\xb8\xfa\xba\xbd\x69\x6e\x3e\xdc\xb1\xdd\x27\x71\x69\xce\x2b\xb6\xba\xba\xfb\xf5\x63\xb7\xad\x62\x9b\xa5\xdb\xf3\x1d\xb9\x5f\xd1\xee\x44\xc6\x2f\xb9\x30\x05\xc8\xd9\x21\x89\xa3\xd7\x02\x5c\xdd\x7f\x3e\xce\x7f\xba\xfc\xd9\x6e\xce\xee\x3f\x14\x5b\xf9\x60\xbe\x88\xe3\xe3\xf5\xc9\xfd\xcf\x5d\x81\xfb\xfd\x7d\x72\x7d\x96\xd7\x1f\x2d\x6d\x6e\x2e\x7e\x3b\x98\xfa\x74\x36\xb1\x7e\xee\x64\x68\xf3\x7b\x58\x4d\xba\x7e\x45\x17\xc9\xe4\x7c\xce\x43\x8b\x40\x62\xd7\x9a\x3d\x4a\xb8\x5e\x73\xeb\xe1\x64\xa2\x9a\x83\xca\xd8\xa1\xa9\xb5\xda\xa0\x7e\xd6\xce\x1f\xe9\x08\xaf\xf2\x31\xda\x15\x91\x24\x45\x92\x66\x31\x66\x34\x4f\x08\x2b\x32\xce\x58\x99\xf1\xa2\xe0\x51\x21\x25\x13\x19\x95\x34\x65\xf2\x0d\xe6\x46\xbb\x82\xb1\x48\x44\xb4\x90\x34\x8e\x93\x94\xf2\x2a\x92\x69\x2e\x52\xc6\x58\x46\xa8\x2c\x04\xa9\x78\x26\x19\x8a\x37\x38\x1e\xed\xb2\x2a\x4f\x13\x59\xf1\x22\x8f\x62\x22\xb3\x8a\xa7\xa9\xc8\x23\x5a\x96\x9c\x10\x16\x95\x42\x22\x26\x65\x8a\xf2\x2d\x35\x44\x3b\x56\xc4\x24\x8f\x58\x96\x95\x29\x41\x2a\x78\x16\x63\x44\x28\xa2\x24\x32\xa7\x15\x2f\x2a\x2e\x68\xc9\x92\x72\xd0\x4d\x89\x56\xf3\xb6\x41\x55\x37\xde\xfd\x6f\xa2\x20\xff\x47\x51\xfc\xc5\x92\xf8\x9b\x04\xf1\xc9\x6c\xb8\x7e\x55\x0e\xe4\x2f\xd0\xc3\x1b\x72\xc8\xd3\x92\x92\x2a\xe3\xb4\x4a\xa2\x24\x8f\xab\x98\x50\x9a\x44\x49\xcc\xb2\x48\xe4\xa2\xc4\x28\xab\x32\x99\x15\xe2\x4d\x39\xa4\x09\x47\x9a\xd1\x2a\x2a\x58\xc5\x2b\x22\x4b\x56\xe6\x3c\x61\x59\x9c\x89\xa8\x2c\x72\x14\x15\x8f\xb2\x54\xca\x37\xe5\x90\x24\x49\xc5\x92\x02\x69\x94\x25\x09\xc1\x8c\x09\x51\x65\x34\x4b\x18\xc3\x94\x54\x31\x8b\x8a\xb2\xc8\x09\x8b\xde\x96\x03\xa7\x92\x96\x49\x5a\x25\x84\x44\x31\x23\x51\x2c\x33\x21\x13\x41\x4a\x41\xe2\x8c\xb1\x34\xc9\xa9\x2c\x22\x64\x07\x8b\xc5\x3b\x08\x54\x7b\xef\xcd\xfb\x0e\xd1\x86\xb6\x55\xaa\xee\xed\x80\xe5\x16\x1d\xe9\xc6\x55\xe1\x46\xad\xd1\xf4\x1e\xb6\x0d\x6a\x30\x1d\xea\x69\x63\xd0\x28\x06\xcb\x40\xec\x00\xe0\x16\x30\x7f\x9e\x5c\x96\x70\x40\x23\x37\x44\xba\xea\xb1\xc7\x17\x21\x86\x11\x72\xb7\xd7\xa2\xb1\x46\x9b\xde\x05\xad\x08\x74\x4e\xe9\x7a\xf1\x2d\x38\x8c\x09\x8c\xfb\x8e\x1b\xa6\xad\xfb\x75\x89\x36\xa8\x2d\x10\x06\xad\x3b\x12\x46\xbb\x20\xe0\x49\x79\xdb\xa0\xab\x12\x81\xb7\xad\x11\xdc\xa3\x04\xee\xc1\x79\x6e\x7d\xdf\x2d\x20\xf8\xdf\x8e\x8e\x4b\x20\x03\xfa\x47\x8b\xe8\xa0\xef\xe0\xe4\xf2\x0b\x88\xbd\x68\xd1\x8d\xa5\x8e\x01\x40\x39\xd8\x72\x35\xac\x49\x21\x5f\xdc\xa0\xf6\xa1\xd4\xf1\xfa\x96\xab\xa1\xda\xcf\xd7\x4b\x88\x43\xa1\x8f\x94\x77\x1d\x0a\x55\x29\xf1\xbc\xe8\xc5\x4c\xf9\xb1\xb4\x6b\x6c\x31\x90\x79\xdb\x28\xd1\x3c\xca\x01\xb8\x10\xa6\x0f\xbf\xe9\x06\x7a\x87\xf3\xab\x64\x42\x13\xa6\xe7\x44\x82\xd2\xc3\x47\xd1\x3b\x6f\xd6\x53\x10\xa8\x54\x8b\x0b\x98\xd7\xc2\xe3\x11\xe6\x82\xaf\x71\x09\x07\x61\x15\x3c\x78\x5c\xfe\x42\x32\x33\xf0\x63\x5c\xd1\xaa\xb0\x4a\x84\x87\x0c\xfe\xb1\x45\xb0\xf8\xad\x57\x16\x61\xeb\xc0\x58\x50\x9d\x98\x36\xc2\xb0\x00\x86\xa3\xe0\x3e\xa4\x3d\xb4\xe4\x9f\xa1\xbb\x46\xe2\x97\xd5\xf9\x12\x1a\xef\xbb\xe5\xd1\x51\x18\x41\xdb\x18\xe7\x97\x45\x9a\xa4\xf3\x30\x87\x8d\xb5\xe6\xa1\x16\x25\x42\xba\x35\x77\x97\xe1\xb8\x84\x38\x9a\xff\x7e\x30\x6e\xd5\x5a\xf9\xd1\xf8\x3c\x1c\x97\x90\x64\x31\xa1\x79\xfe\x8c\xa4\xde\x0c\xd3\x1a\xa9\xa5\xbf\x57\xe6\x2d\xd7\x8e\x0f\x84\x9d\x6b\x90\x72\xdc\x70\x39\x94\xad\x11\x0f\xc0\xb5\x9c\x4a\x01\x6f\x55\x5d\xa3\x45\x39\x52\xda\xe3\xce\xcf\x83\x1e\x69\xcd\xa2\xc0\xeb\xd7\x02\x5b\xe4\x12\x8c\x6e\xf7\x41\x2e\x33\xd9\xe7\x35\x7f\x4e\xe9\x3b\xf4\x0a\xb9\x7c\x0e\x1f\xa7\x13\xfa\x45\x98\xc4\xd3\xdc\x3b\x63\x5a\x58\xf3\x1d\x58\xf4\x56\x8d\xbf\x2a\x0e\xb5\x04\xfe\xcc\xcc\x6c\xd0\x2e\x20\x18\xae\x46\xbb\x25\x90\xa9\xa7\x7f\x0e\xa9\xb4\x47\xbb\xe1\xed\x80\xbb\x1f\x05\xc0\x43\x82\xa2\xb7\x76\x58\x2f\x9f\x78\x34\xdc\x41\x89\x18\xf6\x4f\x8f\xc2\x0f\x6d\x9a\x01\x42\xbc\xf0\x9e\x91\xa9\x82\x53\xe5\x06\xb6\x0c\x88\xce\xac\x7f\x60\x9b\x03\x69\x40\x1b\x0f\xae\xef\x3a\x63\x3d\xf8\xdd\x90\x11\xef\x54\xf8\x0f\x63\x77\x69\x4c\x7b\x2c\xc2\xb3\x70\xa6\x03\x92\x5c\x82\xb7\x3d\x06\xad\x71\xbd\x07\x89\x65\x5f\xd7\xd3\x93\x14\x24\x30\x3c\x00\xb5\x81\x10\x64\x31\xdc\x8e\x52\xeb\x3a\x6b\xaa\x61\x3c\x8f\x2e\x0b\x18\xbf\x2e\xa1\xe2\xad\xc3\xc5\xbf\x03\x00\x00\xff\xff\x12\x91\x2c\x71\xa8\x0d\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3494, mode: os.FileMode(420), modTime: time.Unix(1542883920, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3496, mode: os.FileMode(420), modTime: time.Unix(1543495615, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From a14c78117d67b8d70c5742df0975ccb5ca68a463 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 30 Nov 2018 15:15:07 +0100 Subject: [PATCH 050/220] NFT: unlimited amount of proofs and no collaborator extra field (#526) * added new gobinding and refactored for handler tests * refactored nft servic tests * refactored integration tests * formatting --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- nft/ethereum_payment_obligation.go | 79 +-- nft/ethereum_payment_obligation_contract.go | 503 ++++++++------------ nft/ethereum_payment_obligation_test.go | 43 +- nft/payment_obligation_integration_test.go | 94 ++-- 6 files changed, 296 insertions(+), 429 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 3e6f9ab61..8075e7cf1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -49,11 +49,11 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - digest = "1:8f8c3deed3c1e42a1fbe03b386408023f376f388297294b683125ae4bb90324a" + digest = "1:4542fc4bb0f0bab4d9fad7bf85ca7152cf706eb0ccb1f501899f625af6865d34" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "d9a240d86d05350de86c26ed23d72b45562ae155" + revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] digest = "1:d12e66a9500785cff8a8245bd8a138efff96ed3c1d0551b845cecdc25af57f90" diff --git a/Gopkg.toml b/Gopkg.toml index d751f6d1e..fa50f3605 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -32,7 +32,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - revision = "d9a240d86d05350de86c26ed23d72b45562ae155" + revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[constraint]] name = "github.com/Masterminds/semver" diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 7405fd4c1..5ffe3a055 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -6,8 +6,6 @@ import ( "fmt" "math/big" - "regexp" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -26,10 +24,6 @@ import ( var log = logging.Logger("nft") -const amountOfProofs = 5 - -var regexCollaborators, _ = regexp.Compile("collaborators\\[[0-9]+\\]") - // Config is an interface to configurations required by nft package type Config interface { GetIdentityID() ([]byte, error) @@ -42,7 +36,7 @@ type Config interface { type ethereumPaymentObligationContract interface { // Mint method abstracts Mint method on the contract - Mint(opts *bind.TransactOpts, to common.Address, tokenID *big.Int, tokenURI string, anchorID *big.Int, merkleRoot [32]byte, collaboratorField string, values [5]string, salts [5][32]byte, proofs [5][][32]byte) (*types.Transaction, error) + Mint(opts *bind.TransactOpts, to common.Address, tokenID *big.Int, tokenURI string, anchorID *big.Int, merkleRoot [32]byte, values []string, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) } // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum @@ -104,12 +98,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, deposi return nil, nil } - collaboratorField, err := getCollaboratorProofField(proofFields) - if err != nil { - return nil, err - } - - requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash, collaboratorField) + requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash) if err != nil { return nil, err } @@ -188,7 +177,7 @@ func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes queue.TaskResu // sendMintTransaction sends the actual transaction to mint the NFT func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) error { tx, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, - requestData.MerkleRoot, requestData.CollaboratorField, requestData.Values, requestData.Salts, requestData.Proofs) + requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { return err } @@ -234,21 +223,18 @@ type MintRequest struct { // MerkleRoot is the root hash of the merkle proof/doc MerkleRoot [32]byte - //CollaboratorField contains the value of the collaborator leaf - CollaboratorField string - // Values are the values of the leafs that is being proved Will be converted to string and concatenated for proof verification as outlined in precise-proofs library. - Values [amountOfProofs]string + Values []string // salts are the salts for the field that is being proved Will be concatenated for proof verification as outlined in precise-proofs library. - Salts [amountOfProofs][32]byte + Salts [][32]byte // Proofs are the documents proofs that are needed - Proofs [amountOfProofs][][32]byte + Proofs [][][32]byte } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte, collaboratorField string) (*MintRequest, error) { +func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (*MintRequest, error) { tokenID := utils.ByteSliceToBigInt(utils.RandomSlice(256)) tokenURI := "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" proofData, err := createProofData(proofs) @@ -257,30 +243,26 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo } return &MintRequest{ - To: to, - TokenID: tokenID, - TokenURI: tokenURI, - AnchorID: anchorID.BigInt(), - MerkleRoot: rootHash, - CollaboratorField: collaboratorField, - Values: proofData.Values, - Salts: proofData.Salts, - Proofs: proofData.Proofs}, nil + To: to, + TokenID: tokenID, + TokenURI: tokenURI, + AnchorID: anchorID.BigInt(), + MerkleRoot: rootHash, + Values: proofData.Values, + Salts: proofData.Salts, + Proofs: proofData.Proofs}, nil } type proofData struct { - Values [amountOfProofs]string - Salts [amountOfProofs][32]byte - Proofs [amountOfProofs][][32]byte + Values []string + Salts [][32]byte + Proofs [][][32]byte } func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { - if len(proofspb) > amountOfProofs { - return nil, fmt.Errorf("no more than %v field proofs are accepted", amountOfProofs) - } - var values [amountOfProofs]string - var salts [amountOfProofs][32]byte - var proofs [amountOfProofs][][32]byte + var values = make([]string, len(proofspb)) + var salts = make([][32]byte, len(proofspb)) + var proofs = make([][][32]byte, len(proofspb)) for i, p := range proofspb { values[i] = p.Value @@ -313,25 +295,6 @@ func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { return property, nil } -// getCollaborator returns the needed collaboratorField for a PaymentObligation NFT -// In the current contract implementation the proofField for collaborator is a separated parameter -// pattern: 'collaborators' + '[i]' -// examples: 'collaborators[0]','collaborators[1]', etc -func getCollaboratorProofField(proofFields []string) (string, error) { - - for _, proofField := range proofFields { - - match := regexCollaborators.MatchString(proofField) - - if match { - return proofField, nil - } - } - - return "", fmt.Errorf("proof_fields should contain a collaborator. (example: 'collaborators[0]')") - -} - func bindContract(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return NewEthereumPaymentObligationContract(address, client.GetEthClient()) } diff --git a/nft/ethereum_payment_obligation_contract.go b/nft/ethereum_payment_obligation_contract.go index 140f3e6a5..9338fbf35 100644 --- a/nft/ethereum_payment_obligation_contract.go +++ b/nft/ethereum_payment_obligation_contract.go @@ -16,7 +16,7 @@ import ( ) // EthereumPaymentObligationContractABI is the input ABI used to generate the binding from. -const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"InterfaceId_ERC165\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes4\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"exists\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_name\",\"type\":\"string\"},{\"name\":\"_symbol\",\"type\":\"string\"},{\"name\":\"_anchorRegistry\",\"type\":\"address\"},{\"name\":\"_identityRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_tokenURI\",\"type\":\"string\"},{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_collaboratorField\",\"type\":\"string\"},{\"name\":\"_values\",\"type\":\"string[5]\"},{\"name\":\"_salts\",\"type\":\"bytes32[5]\"},{\"name\":\"_proofs\",\"type\":\"bytes32[][5]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"string\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"dueDate\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mandatoryFields\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_anchorRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_tokenURI\",\"type\":\"string\"},{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_values\",\"type\":\"string[]\"},{\"name\":\"_salts\",\"type\":\"bytes32[]\"},{\"name\":\"_proofs\",\"type\":\"bytes32[][]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"string\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"dueDate\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // EthereumPaymentObligationContract is an auto generated Go binding around an Ethereum contract. type EthereumPaymentObligationContract struct { @@ -160,32 +160,6 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTrans return _EthereumPaymentObligationContract.Contract.contract.Transact(opts, method, params...) } -// InterfaceIdERC165 is a free data retrieval call binding the contract method 0x19fa8f50. -// -// Solidity: function InterfaceId_ERC165() constant returns(bytes4) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) InterfaceIdERC165(opts *bind.CallOpts) ([4]byte, error) { - var ( - ret0 = new([4]byte) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "InterfaceId_ERC165") - return *ret0, err -} - -// InterfaceIdERC165 is a free data retrieval call binding the contract method 0x19fa8f50. -// -// Solidity: function InterfaceId_ERC165() constant returns(bytes4) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) InterfaceIdERC165() ([4]byte, error) { - return _EthereumPaymentObligationContract.Contract.InterfaceIdERC165(&_EthereumPaymentObligationContract.CallOpts) -} - -// InterfaceIdERC165 is a free data retrieval call binding the contract method 0x19fa8f50. -// -// Solidity: function InterfaceId_ERC165() constant returns(bytes4) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) InterfaceIdERC165() ([4]byte, error) { - return _EthereumPaymentObligationContract.Contract.InterfaceIdERC165(&_EthereumPaymentObligationContract.CallOpts) -} - // AnchorRegistry is a free data retrieval call binding the contract method 0x5a180c0a. // // Solidity: function anchorRegistry() constant returns(address) @@ -214,80 +188,54 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(_owner address) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) BalanceOf(opts *bind.CallOpts, _owner common.Address) (*big.Int, error) { +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { var ( ret0 = new(*big.Int) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "balanceOf", _owner) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "balanceOf", owner) return *ret0, err } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(_owner address) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) BalanceOf(_owner common.Address) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, _owner) +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(_owner address) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) BalanceOf(_owner common.Address) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, _owner) -} - -// Exists is a free data retrieval call binding the contract method 0x4f558e79. -// -// Solidity: function exists(_tokenId uint256) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) Exists(opts *bind.CallOpts, _tokenId *big.Int) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "exists", _tokenId) - return *ret0, err -} - -// Exists is a free data retrieval call binding the contract method 0x4f558e79. -// -// Solidity: function exists(_tokenId uint256) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Exists(_tokenId *big.Int) (bool, error) { - return _EthereumPaymentObligationContract.Contract.Exists(&_EthereumPaymentObligationContract.CallOpts, _tokenId) -} - -// Exists is a free data retrieval call binding the contract method 0x4f558e79. -// -// Solidity: function exists(_tokenId uint256) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) Exists(_tokenId *big.Int) (bool, error) { - return _EthereumPaymentObligationContract.Contract.Exists(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetApproved(opts *bind.CallOpts, _tokenId *big.Int) (common.Address, error) { +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( ret0 = new(common.Address) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getApproved", _tokenId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getApproved", tokenId) return *ret0, err } // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetApproved(_tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetApproved(_tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. @@ -340,28 +288,54 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(_owner address, _operator address) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) IsApprovedForAll(opts *bind.CallOpts, _owner common.Address, _operator common.Address) (bool, error) { +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { var ( ret0 = new(bool) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "isApprovedForAll", _owner, _operator) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "isApprovedForAll", owner, operator) return *ret0, err } // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(_owner address, _operator address) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) IsApprovedForAll(_owner common.Address, _operator common.Address) (bool, error) { - return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, _owner, _operator) +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) } // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(_owner address, _operator address) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) IsApprovedForAll(_owner common.Address, _operator common.Address) (bool, error) { - return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, _owner, _operator) +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) +} + +// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. +// +// Solidity: function mandatoryFields( uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) MandatoryFields(opts *bind.CallOpts, arg0 *big.Int) (string, error) { + var ( + ret0 = new(string) + ) + out := ret0 + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "mandatoryFields", arg0) + return *ret0, err +} + +// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. +// +// Solidity: function mandatoryFields( uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) MandatoryFields(arg0 *big.Int) (string, error) { + return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) +} + +// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. +// +// Solidity: function mandatoryFields( uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) MandatoryFields(arg0 *big.Int) (string, error) { + return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) } // Name is a free data retrieval call binding the contract method 0x06fdde03. @@ -392,54 +366,54 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) OwnerOf(opts *bind.CallOpts, _tokenId *big.Int) (common.Address, error) { +// Solidity: function ownerOf(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( ret0 = new(common.Address) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "ownerOf", _tokenId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "ownerOf", tokenId) return *ret0, err } // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) OwnerOf(_tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function ownerOf(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(_tokenId uint256) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) OwnerOf(_tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function ownerOf(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(_interfaceId bytes4) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) SupportsInterface(opts *bind.CallOpts, _interfaceId [4]byte) (bool, error) { +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var ( ret0 = new(bool) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "supportsInterface", _interfaceId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "supportsInterface", interfaceId) return *ret0, err } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(_interfaceId bytes4) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SupportsInterface(_interfaceId [4]byte) (bool, error) { - return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, _interfaceId) +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(_interfaceId bytes4) constant returns(bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) SupportsInterface(_interfaceId [4]byte) (bool, error) { - return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, _interfaceId) +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } // Symbol is a free data retrieval call binding the contract method 0x95d89b41. @@ -468,213 +442,156 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle return _EthereumPaymentObligationContract.Contract.Symbol(&_EthereumPaymentObligationContract.CallOpts) } -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(_index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenByIndex(opts *bind.CallOpts, _index *big.Int) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenByIndex", _index) - return *ret0, err -} - -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(_index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenByIndex(_index *big.Int) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, _index) -} - -// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. -// -// Solidity: function tokenByIndex(_index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenByIndex(_index *big.Int) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, _index) -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(_owner address, _index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenOfOwnerByIndex(opts *bind.CallOpts, _owner common.Address, _index *big.Int) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenOfOwnerByIndex", _owner, _index) - return *ret0, err -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(_owner address, _index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenOfOwnerByIndex(_owner common.Address, _index *big.Int) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, _owner, _index) -} - -// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. -// -// Solidity: function tokenOfOwnerByIndex(_owner address, _index uint256) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenOfOwnerByIndex(_owner common.Address, _index *big.Int) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, _owner, _index) -} - // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(_tokenId uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenURI(opts *bind.CallOpts, _tokenId *big.Int) (string, error) { +// Solidity: function tokenURI(tokenId uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { var ( ret0 = new(string) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenURI", _tokenId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenURI", tokenId) return *ret0, err } // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(_tokenId uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenURI(_tokenId *big.Int) (string, error) { - return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function tokenURI(tokenId uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenURI(tokenId *big.Int) (string, error) { + return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(_tokenId uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenURI(_tokenId *big.Int) (string, error) { - return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, _tokenId) +// Solidity: function tokenURI(tokenId uint256) constant returns(string) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenURI(tokenId *big.Int) (string, error) { + return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function totalSupply() constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "totalSupply") - return *ret0, err +// Solidity: function approve(to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "approve", to, tokenId) } -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function totalSupply() constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TotalSupply() (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TotalSupply(&_EthereumPaymentObligationContract.CallOpts) +// Solidity: function approve(to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } -// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function totalSupply() constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TotalSupply() (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.TotalSupply(&_EthereumPaymentObligationContract.CallOpts) +// Solidity: function approve(to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. // -// Solidity: function approve(_to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Approve(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "approve", _to, _tokenId) +// Solidity: function initialize() returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Initialize(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "initialize") } -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. // -// Solidity: function approve(_to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Approve(_to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId) +// Solidity: function initialize() returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Initialize() (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts) } -// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. // -// Solidity: function approve(_to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Approve(_to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId) +// Solidity: function initialize() returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Initialize() (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts) } -// Mint is a paid mutator transaction binding the contract method 0xcb40425f. +// Mint is a paid mutator transaction binding the contract method 0x093b02fe. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) } -// Mint is a paid mutator transaction binding the contract method 0xcb40425f. +// Mint is a paid mutator transaction binding the contract method 0x093b02fe. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) } -// Mint is a paid mutator transaction binding the contract method 0xcb40425f. +// Mint is a paid mutator transaction binding the contract method 0x093b02fe. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _collaboratorField string, _values string[5], _salts bytes32[5], _proofs bytes32[][5]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _collaboratorField string, _values [5]string, _salts [5][32]byte, _proofs [5][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _collaboratorField, _values, _salts, _proofs) +// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(_from address, _to address, _tokenId uint256, _data bytes) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, _from common.Address, _to common.Address, _tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "safeTransferFrom", _from, _to, _tokenId, _data) +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "safeTransferFrom", from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(_from address, _to address, _tokenId uint256, _data bytes) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SafeTransferFrom(_from common.Address, _to common.Address, _tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, _from, _to, _tokenId, _data) +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(_from address, _to address, _tokenId uint256, _data bytes) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SafeTransferFrom(_from common.Address, _to common.Address, _tokenId *big.Int, _data []byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, _from, _to, _tokenId, _data) +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(_to address, _approved bool) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, _to common.Address, _approved bool) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "setApprovalForAll", _to, _approved) +// Solidity: function setApprovalForAll(to address, approved bool) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, to common.Address, approved bool) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "setApprovalForAll", to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(_to address, _approved bool) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SetApprovalForAll(_to common.Address, _approved bool) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, _to, _approved) +// Solidity: function setApprovalForAll(to address, approved bool) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(_to address, _approved bool) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SetApprovalForAll(_to common.Address, _approved bool) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, _to, _approved) +// Solidity: function setApprovalForAll(to address, approved bool) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(_from address, _to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) TransferFrom(opts *bind.TransactOpts, _from common.Address, _to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "transferFrom", _from, _to, _tokenId) +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "transferFrom", from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(_from address, _to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TransferFrom(_from common.Address, _to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, _from, _to, _tokenId) +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(_from address, _to address, _tokenId uint256) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) TransferFrom(_from common.Address, _to common.Address, _tokenId *big.Int) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, _from, _to, _tokenId) +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } // EthereumPaymentObligationContractApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the EthereumPaymentObligationContract contract. @@ -754,23 +671,23 @@ type EthereumPaymentObligationContractApproval struct { // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(_owner indexed address, _approved indexed address, _tokenId indexed uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApproval(opts *bind.FilterOpts, _owner []common.Address, _approved []common.Address, _tokenId []*big.Int) (*EthereumPaymentObligationContractApprovalIterator, error) { +// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractApprovalIterator, error) { - var _ownerRule []interface{} - for _, _ownerItem := range _owner { - _ownerRule = append(_ownerRule, _ownerItem) + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) } - var _approvedRule []interface{} - for _, _approvedItem := range _approved { - _approvedRule = append(_approvedRule, _approvedItem) + var approvedRule []interface{} + for _, approvedItem := range approved { + approvedRule = append(approvedRule, approvedItem) } - var _tokenIdRule []interface{} - for _, _tokenIdItem := range _tokenId { - _tokenIdRule = append(_tokenIdRule, _tokenIdItem) + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "Approval", _ownerRule, _approvedRule, _tokenIdRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) if err != nil { return nil, err } @@ -779,23 +696,23 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(_owner indexed address, _approved indexed address, _tokenId indexed uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApproval, _owner []common.Address, _approved []common.Address, _tokenId []*big.Int) (event.Subscription, error) { +// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApproval, owner []common.Address, approved []common.Address, tokenId []*big.Int) (event.Subscription, error) { - var _ownerRule []interface{} - for _, _ownerItem := range _owner { - _ownerRule = append(_ownerRule, _ownerItem) + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) } - var _approvedRule []interface{} - for _, _approvedItem := range _approved { - _approvedRule = append(_approvedRule, _approvedItem) + var approvedRule []interface{} + for _, approvedItem := range approved { + approvedRule = append(approvedRule, approvedItem) } - var _tokenIdRule []interface{} - for _, _tokenIdItem := range _tokenId { - _tokenIdRule = append(_tokenIdRule, _tokenIdItem) + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "Approval", _ownerRule, _approvedRule, _tokenIdRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) if err != nil { return nil, err } @@ -904,19 +821,19 @@ type EthereumPaymentObligationContractApprovalForAll struct { // FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: e ApprovalForAll(_owner indexed address, _operator indexed address, _approved bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, _owner []common.Address, _operator []common.Address) (*EthereumPaymentObligationContractApprovalForAllIterator, error) { +// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*EthereumPaymentObligationContractApprovalForAllIterator, error) { - var _ownerRule []interface{} - for _, _ownerItem := range _owner { - _ownerRule = append(_ownerRule, _ownerItem) + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) } - var _operatorRule []interface{} - for _, _operatorItem := range _operator { - _operatorRule = append(_operatorRule, _operatorItem) + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "ApprovalForAll", _ownerRule, _operatorRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "ApprovalForAll", ownerRule, operatorRule) if err != nil { return nil, err } @@ -925,19 +842,19 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: e ApprovalForAll(_owner indexed address, _operator indexed address, _approved bool) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApprovalForAll, _owner []common.Address, _operator []common.Address) (event.Subscription, error) { +// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApprovalForAll, owner []common.Address, operator []common.Address) (event.Subscription, error) { - var _ownerRule []interface{} - for _, _ownerItem := range _owner { - _ownerRule = append(_ownerRule, _ownerItem) + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) } - var _operatorRule []interface{} - for _, _operatorItem := range _operator { - _operatorRule = append(_operatorRule, _operatorItem) + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "ApprovalForAll", _ownerRule, _operatorRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "ApprovalForAll", ownerRule, operatorRule) if err != nil { return nil, err } @@ -1170,23 +1087,23 @@ type EthereumPaymentObligationContractTransfer struct { // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(_from indexed address, _to indexed address, _tokenId indexed uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterTransfer(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _tokenId []*big.Int) (*EthereumPaymentObligationContractTransferIterator, error) { +// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractTransferIterator, error) { - var _fromRule []interface{} - for _, _fromItem := range _from { - _fromRule = append(_fromRule, _fromItem) + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) } - var _toRule []interface{} - for _, _toItem := range _to { - _toRule = append(_toRule, _toItem) + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) } - var _tokenIdRule []interface{} - for _, _tokenIdItem := range _tokenId { - _tokenIdRule = append(_tokenIdRule, _tokenIdItem) + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "Transfer", _fromRule, _toRule, _tokenIdRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) if err != nil { return nil, err } @@ -1195,23 +1112,23 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(_from indexed address, _to indexed address, _tokenId indexed uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractTransfer, _from []common.Address, _to []common.Address, _tokenId []*big.Int) (event.Subscription, error) { +// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractTransfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) { - var _fromRule []interface{} - for _, _fromItem := range _from { - _fromRule = append(_fromRule, _fromItem) + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) } - var _toRule []interface{} - for _, _toItem := range _to { - _toRule = append(_toRule, _toItem) + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) } - var _tokenIdRule []interface{} - for _, _tokenIdItem := range _tokenId { - _tokenIdRule = append(_tokenIdRule, _tokenIdItem) + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) } - logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "Transfer", _fromRule, _toRule, _tokenIdRule) + logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) if err != nil { return nil, err } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index a4462d85b..62c0ca426 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -54,9 +54,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [amountOfProofs]string{"value1", "value2"}, - Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: []string{"value1", "value2"}, + Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, nil, }, @@ -77,9 +77,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [amountOfProofs]string{"value1", "value2"}, - Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: []string{"value1", "value2"}, + Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, errors.New("input exceeds length of 32"), }, @@ -100,9 +100,9 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [amountOfProofs]string{"value1", "value2"}, - Proofs: [amountOfProofs][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, - Salts: [amountOfProofs][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, + Values: []string{"value1", "value2"}, + Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, + Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, errors.New("input exceeds length of 32"), }, @@ -127,7 +127,7 @@ type MockPaymentObligation struct { mock.Mock } -func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, collaboratorField string, _values [amountOfProofs]string, _salts [amountOfProofs][32]byte, _proofs [amountOfProofs][][32]byte) (*types.Transaction, error) { +func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { args := m.Called(opts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) return args.Get(0).(*types.Transaction), args.Error(1) } @@ -239,26 +239,3 @@ func decodeHex(hex string) []byte { h, _ := hexutil.Decode(hex) return h } - -func TestGetCollaboratorProofField(t *testing.T) { - - proofField, err := getCollaboratorProofField([]string{"fuu", "foo", "collaborators[0]"}) - assert.Nil(t, err, "getCollaboratorProofField should not throw an error") - assert.Equal(t, "collaborators[0]", proofField, "proofField should contain the correct field") - - proofField, err = getCollaboratorProofField([]string{"fuu", "foo"}) - assert.Error(t, err, "getCollaboratorProofField should throw an error") - assert.Equal(t, "", proofField, "proofField should be empty") - - proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators"}) - assert.Error(t, err, "getCollaboratorProofField should throw an error") - assert.Equal(t, "", proofField, "proofField should be empty") - - proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators[a]"}) - assert.Error(t, err, "getCollaboratorProofField should throw an error") - assert.Equal(t, "", proofField, "proofField should be empty") - - proofField, err = getCollaboratorProofField([]string{"fuu", "foo", "collaborators[12345678]"}) - assert.Nil(t, err, "getCollaboratorProofField should not throw an error") - assert.Equal(t, "collaborators[12345678]", proofField, "proofField should contain the correct field") -} diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 1ff28459f..43381da8e 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,8 +3,18 @@ package nft_test import ( + "context" "os" "testing" + "time" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/header" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/stretchr/testify/assert" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" @@ -43,45 +53,45 @@ func TestMain(m *testing.M) { os.Exit(result) } -//func TestPaymentObligationService_mint(t *testing.T) { -// // create identity -// log.Debug("Create Identity for Testing") -// testingidentity.CreateIdentityWithKeys(cfg, idService) -// -// // create invoice (anchor) -// service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) -// assert.Nil(t, err, "should not error out when getting invoice service") -// contextHeader, err := header.NewContextHeader(context.Background(), cfg) -// assert.Nil(t, err) -// invoiceService := service.(invoice.Service) -// dueDate := time.Now().Add(4 * 24 * time.Hour) -// model, err := invoiceService.DeriveFromCreatePayload( -// &invoicepb.InvoiceCreatePayload{ -// Collaborators: []string{}, -// Data: &invoicepb.InvoiceData{ -// InvoiceNumber: "2132131", -// GrossAmount: 123, -// NetAmount: 123, -// Currency: "EUR", -// DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, -// }, -// }, contextHeader) -// assert.Nil(t, err, "should not error out when creating invoice model") -// modelUpdated, err := invoiceService.Create(contextHeader, model) -// -// // get ID -// ID, err := modelUpdated.ID() -// assert.Nil(t, err, "should not error out when getting invoice ID") -// // call mint -// // assert no error -// confirmations, err := payOb.MintNFT( -// ID, -// cfg.GetContractAddress("paymentObligation").String(), -// "0xf72855759a39fb75fc7341139f5d7a3974d4da08", -// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "document_type", "collaborators[0]"}, -// ) -// assert.Nil(t, err, "should not error out when minting an invoice") -// tokenConfirm := <-confirmations -// assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") -// assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") -//} +func TestPaymentObligationService_mint(t *testing.T) { + // create identity + log.Debug("Create Identity for Testing") + testingidentity.CreateIdentityWithKeys(cfg, idService) + + // create invoice (anchor) + service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) + assert.Nil(t, err, "should not error out when getting invoice service") + contextHeader, err := header.NewContextHeader(context.Background(), cfg) + assert.Nil(t, err) + invoiceService := service.(invoice.Service) + dueDate := time.Now().Add(4 * 24 * time.Hour) + model, err := invoiceService.DeriveFromCreatePayload( + &invoicepb.InvoiceCreatePayload{ + Collaborators: []string{}, + Data: &invoicepb.InvoiceData{ + InvoiceNumber: "2132131", + GrossAmount: 123, + NetAmount: 123, + Currency: "EUR", + DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, + }, + }, contextHeader) + assert.Nil(t, err, "should not error out when creating invoice model") + modelUpdated, err := invoiceService.Create(contextHeader, model) + + // get ID + ID, err := modelUpdated.ID() + assert.Nil(t, err, "should not error out when getting invoice ID") + // call mint + // assert no error + confirmations, err := payOb.MintNFT( + ID, + cfg.GetContractAddress("paymentObligation").String(), + "0xf72855759a39fb75fc7341139f5d7a3974d4da08", + []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, + ) + assert.Nil(t, err, "should not error out when minting an invoice") + tokenConfirm := <-confirmations + assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") + assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") +} From 60c181ce2f7dfa7e57a039565ee2050f3c845384 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 3 Dec 2018 14:15:21 +0100 Subject: [PATCH 051/220] Integration testing framework(Testworld) first iteration (#512) * Fixing merging issue with earlier pr * V1 * Peer init works * Remove storage.levelDBInstance global * Testworld mods * fix tests * fix tests * imports * First working hosts * First successful Testworld tests * Added Robert and the park hosts in a nicer way * Fix linting issues * Fix gitignore * Review comments --- .gitignore | 1 + Gopkg.lock | 171 +++++++++++++++++- Gopkg.toml | 9 +- build/configs/default_config.yaml | 10 +- build/scripts/migrate.sh | 40 +++++ build/scripts/test_wrapper.sh | 31 +--- build/scripts/tests/run_testworld.sh | 19 ++ cmd/centrifuge/create_config.go | 100 +++-------- cmd/centrifuge/manage_identities.go | 13 +- cmd/centrifuge/root.go | 42 ----- cmd/centrifuge/run.go | 7 +- cmd/common.go | 146 ++++++++++++++++ config/configuration.go | 12 ++ node/bootstrapper.go | 18 +- node/node.go | 2 +- p2p/client.go | 2 +- testworld/httputils.go | 47 +++++ testworld/keystore | 1 + testworld/park.go | 248 +++++++++++++++++++++++++++ testworld/park_test.go | 69 ++++++++ testworld/peerconfigs/.gitkeep | 0 testworld/util.go | 74 ++++++++ testworld/util_test.go.test | 21 +++ 23 files changed, 911 insertions(+), 172 deletions(-) create mode 100755 build/scripts/migrate.sh create mode 100755 build/scripts/tests/run_testworld.sh create mode 100644 cmd/common.go create mode 100644 testworld/httputils.go create mode 100644 testworld/keystore create mode 100644 testworld/park.go create mode 100644 testworld/park_test.go create mode 100644 testworld/peerconfigs/.gitkeep create mode 100644 testworld/util.go create mode 100644 testworld/util_test.go.test diff --git a/.gitignore b/.gitignore index 3ab321839..e16b3c59a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ coverage/ coverage.txt *.swp *.swo +testworld/peerconfigs/* \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock index 8075e7cf1..d21eaa10d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -21,6 +21,14 @@ pruneopts = "UT" revision = "5312a61534124124185d41f09206b9fef1d88403" +[[projects]] + digest = "1:2aff5edb9bccd2974090fddb17ca7ab05a3f5c983db567c30c7f0b53404f5783" + name = "github.com/ajg/form" + packages = ["."] + pruneopts = "UT" + revision = "cc2954064ec9ea8d93917f0f87456e11d7b881ad" + version = "v1.5" + [[projects]] digest = "1:1156cfea0ff969858f6027df95c15ca5e802556b466aebeedaf53dde3b301db3" name = "github.com/allegro/bigcache" @@ -144,6 +152,14 @@ revision = "27e633ca943ee9f49614b9ea074667227402b571" source = "github.com/centrifuge/go-ethereum" +[[projects]] + digest = "1:af43bdaaf86655a2343f113e9b293bbc16b12099eaeb223982bbe4d4c22ba14d" + name = "github.com/fatih/structs" + packages = ["."] + pruneopts = "UT" + revision = "4966fc68f5b7593aafa6cbbba2d65ec6e1416047" + version = "v1.1.0" + [[projects]] digest = "1:d1341a04a4443bba8c8af76ec6c3960206074490a1284b4853ff5a88a66c63b7" name = "github.com/fd/go-nat" @@ -160,6 +176,22 @@ revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" version = "v1.4.7" +[[projects]] + branch = "master" + digest = "1:99409b277e9cd3f00284f8898e43b517956514108d1b220efc60ef05c8a8fd58" + name = "github.com/gavv/httpexpect" + packages = ["."] + pruneopts = "UT" + revision = "bdde308713130a703436e014ff782958c251d20a" + +[[projects]] + branch = "master" + digest = "1:fbc02c2b3b78e6bc30228f3bae582f1fcea74a050cbdbf42f24eff12bef8eab4" + name = "github.com/gavv/monotime" + packages = ["."] + pruneopts = "UT" + revision = "6f8212e8d10df7383609d3c377ca08884d8f3ec0" + [[projects]] digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" name = "github.com/ghodss/yaml" @@ -244,6 +276,14 @@ revision = "9c11da706d9b7902c6da69c592f75637793fe121" version = "v2.0.0" +[[projects]] + digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690" + name = "github.com/google/go-querystring" + packages = ["query"] + pruneopts = "UT" + revision = "44c6ddd0a2342c386950e880b658017258da92fc" + version = "v1.0.0" + [[projects]] digest = "1:3a26588bc48b96825977c1b3df964f8fd842cd6860cc26370588d3563433cf11" name = "github.com/google/uuid" @@ -365,6 +405,14 @@ pruneopts = "UT" revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca" +[[projects]] + digest = "1:a3ce4de79566c21e93cb6934797fdaa587ad3fc6a964708ab77babe54ea67188" + name = "github.com/imkira/go-interpol" + packages = ["."] + pruneopts = "UT" + revision = "5accad8134979a6ac504d456a6c7f1c53da237ca" + version = "v1.1.0" + [[projects]] digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" name = "github.com/inconshreveable/mousetrap" @@ -474,6 +522,26 @@ pruneopts = "UT" revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b" +[[projects]] + digest = "1:aaa8e0e7e35d92e21daed3f241832cee73d15ca1cd3302ba3843159a959a7eac" + name = "github.com/klauspost/compress" + packages = [ + "flate", + "gzip", + "zlib", + ] + pruneopts = "UT" + revision = "30be6041bed523c18e269a700ebd9c2ea9328574" + version = "v1.4.1" + +[[projects]] + digest = "1:2d643962fac133904694fffa959bc3c5dcfdcee38c6f5ffdd99a3c93eb9c835c" + name = "github.com/klauspost/cpuid" + packages = ["."] + pruneopts = "UT" + revision = "e7e905edc00ea8827e58662220139109efea09db" + version = "v1.2.0" + [[projects]] digest = "1:f3f143e9085a1fbff293e8f131f35c6f9d6b2023002fd719a08655b1a9c6e745" name = "github.com/libp2p/go-addr-util" @@ -844,6 +912,14 @@ revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8" version = "v1.0.0" +[[projects]] + digest = "1:7aefb397a53fc437c90f0fdb3e1419c751c5a3a165ced52325d5d797edf1aca6" + name = "github.com/moul/http2curl" + packages = ["."] + pruneopts = "UT" + revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d" + version = "v1.0.0" + [[projects]] branch = "master" digest = "1:b9b9f43a8a410d633e6547f89e830926741070941f2243d4d3a0bb154f565c9e" @@ -983,6 +1059,25 @@ pruneopts = "UT" revision = "36e9d2ebbde5e3f13ab2e25625fd453271d6522e" +[[projects]] + branch = "master" + digest = "1:45ed9e09a140c93e437e1e9634258040148f2cd18b28758a21b084002eca8c8c" + name = "github.com/savaki/jq" + packages = [ + ".", + "scanner", + ] + pruneopts = "UT" + revision = "0e6baecebbf8a24a6590d3fc8232165008d6e5d8" + +[[projects]] + digest = "1:d917313f309bda80d27274d53985bc65651f81a5b66b820749ac7f8ef061fd04" + name = "github.com/sergi/go-diff" + packages = ["diffmatchpatch"] + pruneopts = "UT" + revision = "1744e2970ca51c86172c8190fadad617561ed6e7" + version = "v1.0.0" + [[projects]] digest = "1:919bb3aa6d9d0b67648c219fa4925312bc3c2872da19e818fa769e9c97a2b643" name = "github.com/spaolacci/murmur3" @@ -1059,11 +1154,12 @@ version = "v0.1.1" [[projects]] - digest = "1:15a4a7e5afac3cea801fa24831fce3bf3b5bd3620cbf8355a07b7dbf06877883" + digest = "1:cf4fdb98e23a565bd82473027d37512a3d5b186fba3a1895d7e8401d8ce3ffe1" name = "github.com/stretchr/testify" packages = [ "assert", "mock", + "require", ] pruneopts = "UT" revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" @@ -1089,6 +1185,26 @@ pruneopts = "UT" revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd" +[[projects]] + digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59" + name = "github.com/valyala/bytebufferpool" + packages = ["."] + pruneopts = "UT" + revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7" + version = "v1.0.0" + +[[projects]] + digest = "1:15ad8a80098fcc7a194b9db6b26d74072a852e4faa957848c8118193d3c69230" + name = "github.com/valyala/fasthttp" + packages = [ + ".", + "fasthttputil", + "stackless", + ] + pruneopts = "UT" + revision = "e5f51c11919d4f66400334047b897ef0a94c6f3c" + version = "v20180529" + [[projects]] branch = "master" digest = "1:98fa13beefbf581ec173561adad6374c460631593b4bdcf03adc29cd18e5d2f5" @@ -1175,6 +1291,30 @@ pruneopts = "UT" revision = "cb29a700b01dc3c2fdd743c00cf54685056bb62a" +[[projects]] + branch = "master" + digest = "1:f4e5276a3b356f4692107047fd2890f2fe534f4feeb6b1fd2f6dfbd87f1ccf54" + name = "github.com/xeipuuv/gojsonpointer" + packages = ["."] + pruneopts = "UT" + revision = "4e3ac2762d5f479393488629ee9370b50873b3a6" + +[[projects]] + branch = "master" + digest = "1:dc6a6c28ca45d38cfce9f7cb61681ee38c5b99ec1425339bfc1e1a7ba769c807" + name = "github.com/xeipuuv/gojsonreference" + packages = ["."] + pruneopts = "UT" + revision = "bd5ef7bd5415a7ac448318e64f11a24cd21e594b" + +[[projects]] + digest = "1:41bd4de0a27c0b7affef4083bc8f86501b4c7d891f95809a0fb758a23eb5e78f" + name = "github.com/xeipuuv/gojsonschema" + packages = ["."] + pruneopts = "UT" + revision = "da425ebb7609ba06a0f395fc8a254d1c303364a0" + version = "v1.0" + [[projects]] digest = "1:778500e3634377cb6660543afa4646c12a3a33aefadd3e1d269e24e57d75a3d7" name = "github.com/xsleonard/go-merkle" @@ -1182,6 +1322,33 @@ pruneopts = "UT" revision = "fbb7cafc5ae411e13e718172f5af7917ad6c3ed7" +[[projects]] + branch = "master" + digest = "1:ac3d942a027d57fbfc5c13791cfaaa4b30729674fea88f2e03190b777c2b674e" + name = "github.com/yalp/jsonpath" + packages = ["."] + pruneopts = "UT" + revision = "5cc68e5049a040829faef3a44c00ec4332f6dec7" + +[[projects]] + digest = "1:52ccbcf36804b0beb5677a8994bd4ac740b71d1d6fe38c02b113dabdda51bf6d" + name = "github.com/yudai/gojsondiff" + packages = [ + ".", + "formatter", + ] + pruneopts = "UT" + revision = "7b1b7adf999dab73a6eb02669c3d82dbb27a3dd6" + version = "1.0.0" + +[[projects]] + branch = "master" + digest = "1:0d4822d3440c9b5992704bb357061fff7ab60daa85d92dec02b81b78e4908db7" + name = "github.com/yudai/golcs" + packages = ["."] + pruneopts = "UT" + revision = "ecda9a501e8220fae3b4b600c3db4b0ba22cfc68" + [[projects]] digest = "1:b5a8fada1cb985bd2b823735e9ec922c4ecd7252880cbea5921d0a9343be648e" name = "golang.org/x/crypto" @@ -1374,6 +1541,7 @@ "github.com/ethereum/go-ethereum/event", "github.com/ethereum/go-ethereum/log", "github.com/ethereum/go-ethereum/rpc", + "github.com/gavv/httpexpect", "github.com/go-errors/errors", "github.com/golang/protobuf/jsonpb", "github.com/golang/protobuf/proto", @@ -1403,6 +1571,7 @@ "github.com/multiformats/go-multihash", "github.com/paralin/go-libp2p-grpc", "github.com/roboll/go-vendorinstall", + "github.com/savaki/jq", "github.com/spf13/cast", "github.com/spf13/cobra", "github.com/spf13/viper", diff --git a/Gopkg.toml b/Gopkg.toml index fa50f3605..e99796376 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -294,4 +294,11 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [prune] go-tests = true - unused-packages = true \ No newline at end of file + unused-packages = true +[[constraint]] + branch = "master" + name = "github.com/savaki/jq" + +[[constraint]] + branch = "master" + name = "github.com/gavv/httpexpect" diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index d1016c613..fd45aeacd 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -7,8 +7,8 @@ networks: id: 333 ethereumNetworkId: 8383 bootstrapPeers: - - "/ip4/127.0.0.1/tcp/38202/ipfs/QmTQxbwkuZYYDfuzTbxEAReTNCLozyy558vQngVvPMjLYk" - - "/ip4/127.0.0.1/tcp/38203/ipfs/QmVf6EN6mkqWejWKW2qPu16XpdG3kJo1T3mhahPB5Se5n1" + - "/ip4/127.0.0.1/tcp/38202/ipfs/QmTQxbwkuZYYDfuzTbxEAReTNCLozyy558vQngVvPMjLYk" + - "/ip4/127.0.0.1/tcp/38203/ipfs/QmVf6EN6mkqWejWKW2qPu16XpdG3kJo1T3mhahPB5Se5n1" contractAddresses: identityFactory: "" identityRegistry: "" @@ -21,8 +21,8 @@ networks: id: 51 # Bootstrap list of nodes that Centrifuge provides to the russianhill testnet bootstrapPeers: - - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" - - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" + - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" + - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" # Ethereum network ID - Rinkeby ethereumNetworkId: 4 # Latest deployed Smart Contracts for the given testnet @@ -35,7 +35,7 @@ networks: bernalheights: # Numeric ID of the Centrifuge network id: 52 - # Bootstrap list of nodes that Centrifuge provides to the russianhill testnet + # Bootstrap list of nodes that Centrifuge provides to the bernalheights testnet bootstrapPeers: - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" diff --git a/build/scripts/migrate.sh b/build/scripts/migrate.sh new file mode 100755 index 000000000..e232aeed7 --- /dev/null +++ b/build/scripts/migrate.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Allow passing parent directory as a parameter +PARENT_DIR=$1 +if [ -z ${PARENT_DIR} ]; +then + echo "PARENT DIR $1" + PARENT_DIR = `pwd` +fi + +# Even if other `env_vars.sh` might hold this variable +# Let's not count on it and be clear instead +if [ -z ${CENT_ETHEREUM_CONTRACTS_DIR} ]; then + CENT_ETHEREUM_CONTRACTS_DIR=${PARENT_DIR}/vendor/github.com/centrifuge/centrifuge-ethereum-contracts +fi + +# Assure that all the dependencies for the contracts are installed +npm install --pwd ${CENT_ETHEREUM_CONTRACTS_DIR} --prefix=${CENT_ETHEREUM_CONTRACTS_DIR} + +# `truffle migrate` will fail if not executed in the sub-dir +cd ${CENT_ETHEREUM_CONTRACTS_DIR} +# Clear up previous build +rm -Rf ./build + + +LOCAL_ETH_CONTRACT_ADDRESSES="${CENT_ETHEREUM_CONTRACTS_DIR}/deployments/local.json" +if [ ! -e $LOCAL_ETH_CONTRACT_ADDRESSES ]; then + echo "$LOCAL_ETH_CONTRACT_ADDRESSES doesn't exist. Probably no migrations run yet. Forcing migrations." + FORCE_MIGRATE='true' +fi + +if [[ "X${FORCE_MIGRATE}" == "Xtrue" ]]; +then + echo "Running the Solidity contracts migrations for local geth" + ${CENT_ETHEREUM_CONTRACTS_DIR}/scripts/migrate.sh localgeth +else + echo "Not migrating the Solidity contracts" +fi + +cd ${PARENT_DIR} \ No newline at end of file diff --git a/build/scripts/test_wrapper.sh b/build/scripts/test_wrapper.sh index 23647e8ba..03b27d3d2 100755 --- a/build/scripts/test_wrapper.sh +++ b/build/scripts/test_wrapper.sh @@ -29,38 +29,9 @@ done ############################################################ ################# Prepare for tests ######################## -# Even if other `env_vars.sh` might hold this variable -# Let's not count on it and be clear instead -if [ -z ${CENT_ETHEREUM_CONTRACTS_DIR} ]; then - CENT_ETHEREUM_CONTRACTS_DIR=${PARENT_DIR}/vendor/github.com/centrifuge/centrifuge-ethereum-contracts -fi - -# Assure that all the dependencies for the contracts are installed -npm install --pwd ${CENT_ETHEREUM_CONTRACTS_DIR} --prefix=${CENT_ETHEREUM_CONTRACTS_DIR} - -# `truffle migrate` will fail if not executed in the sub-dir -cd ${CENT_ETHEREUM_CONTRACTS_DIR} -# Clear up previous build -rm -Rf ./build - - -LOCAL_ETH_CONTRACT_ADDRESSES="${CENT_ETHEREUM_CONTRACTS_DIR}/deployments/local.json" -if [ ! -e $LOCAL_ETH_CONTRACT_ADDRESSES ]; then - echo "$LOCAL_ETH_CONTRACT_ADDRESSES doesn't exist. Probably no migrations run yet. Forcing migrations." - FORCE_MIGRATE='true' -fi - -if [[ "X${FORCE_MIGRATE}" == "Xtrue" ]]; -then - echo "Running the Solidity contracts migrations for local geth" - ${CENT_ETHEREUM_CONTRACTS_DIR}/scripts/migrate.sh localgeth -else - echo "Not migrating the Solidity contracts" -fi +${PARENT_DIR}/build/scripts/migrate.sh status=$? -cd ${PARENT_DIR} - ############################################################ ################# Run Tests ################################ diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh new file mode 100755 index 000000000..5420e36e3 --- /dev/null +++ b/build/scripts/tests/run_testworld.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo "Running Testworld" + +status=$? +for d in $(go list -tags=testworld ./... | grep -v vendor); do + output="go test -race -coverprofile=profile.out -covermode=atomic -tags=testworld $d 2>&1" + eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done + if [ ${PIPESTATUS[0]} -ne 0 ]; then + status=1 + fi + + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done + +exit $status diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index b3b2cf402..a96969957 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -3,9 +3,7 @@ package main import ( "os" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools" + "github.com/centrifuge/go-centrifuge/cmd" "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" ) @@ -20,41 +18,6 @@ var p2pPort int64 var bootstraps []string var txPoolAccess bool -func createIdentity(idService identity.Service) (identity.CentID, error) { - centID := identity.RandomCentID() - _, confirmations, err := idService.CreateIdentity(centID) - if err != nil { - return [identity.CentIDLength]byte{}, err - } - _ = <-confirmations - - return centID, nil -} - -func generateKeys(config config.Config) { - p2pPub, p2pPvt := config.GetSigningKeyPair() - ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() - keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") -} - -func addKeys(idService identity.Service) error { - err := idService.AddKeyFromConfig(identity.KeyPurposeP2P) - if err != nil { - panic(err) - } - err = idService.AddKeyFromConfig(identity.KeyPurposeSigning) - if err != nil { - panic(err) - } - err = idService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) - if err != nil { - panic(err) - } - return nil -} - func init() { home, err := homedir.Dir() if err != nil { @@ -66,50 +29,29 @@ func init() { Use: "createconfig", Short: "Configures Node", Long: ``, - Run: func(cmd *cobra.Command, args []string) { - - data := map[string]interface{}{ - "targetDataDir": targetDataDir, - "accountKeyPath": accountKeyPath, - "accountPassword": accountPassword, - "network": network, - "ethNodeURL": ethNodeURL, - "bootstraps": bootstraps, - "apiPort": apiPort, - "p2pPort": p2pPort, - "txpoolaccess": txPoolAccess, - } - - v, err := config.CreateConfigFile(data) - if err != nil { - log.Fatalf("error: %v", err) - } - log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) - - ctx, canc, _ := commandBootstrap(v.ConfigFileUsed()) - cfg := ctx[config.BootstrappedConfig].(*config.Configuration) - generateKeys(cfg) - - idService := ctx[identity.BootstrappedIDService].(identity.Service) - id, err := createIdentity(idService) - if err != nil { - log.Fatalf("error: %v", err) - } - - v.Set("identityId", id.String()) - err = v.WriteConfig() - if err != nil { - log.Fatalf("error: %v", err) - } - cfg.Set("identityId", id.String()) - - log.Infof("Identity created [%s] [%x]", id.String(), id) - - err = addKeys(idService) + Run: func(c *cobra.Command, args []string) { + err := cmd.CreateConfig(targetDataDir, + ethNodeURL, + accountKeyPath, + accountPassword, + network, + apiPort, + p2pPort, + bootstraps, + txPoolAccess, + nil) if err != nil { + log.Info(targetDataDir, + accountKeyPath, + accountPassword, + network, + ethNodeURL, + apiPort, + p2pPort, + bootstraps, + txPoolAccess) log.Fatalf("error: %v", err) } - canc() }, } diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index 02a732eb6..b3836f721 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -3,6 +3,7 @@ package main import ( "io/ioutil" + "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/identity" "github.com/spf13/cobra" ) @@ -14,10 +15,10 @@ var createIdentityCmd = &cobra.Command{ Use: "createidentity", Short: "creates identity with signing key as p2p id against ethereum", Long: "", - Run: func(cmd *cobra.Command, args []string) { - //cmd requires a config file + Run: func(cm *cobra.Command, args []string) { + //cm requires a config file cfgFile = ensureConfigFile() - ctx, canc, _ := commandBootstrap(cfgFile) + ctx, canc, _ := cmd.CommandBootstrap(cfgFile) var centID identity.CentID var err error if centIDString == "" { @@ -53,10 +54,10 @@ var addKeyCmd = &cobra.Command{ Use: "addkey", Short: "add a signing key as p2p id against ethereum", Long: "add a signing key as p2p id against ethereum", - Run: func(cmd *cobra.Command, args []string) { - //cmd requires a config file + Run: func(cm *cobra.Command, args []string) { + //cm requires a config file cfgFile = ensureConfigFile() - ctx, canc, _ := commandBootstrap(cfgFile) + ctx, canc, _ := cmd.CommandBootstrap(cfgFile) var purposeInt int switch purpose { diff --git a/cmd/centrifuge/root.go b/cmd/centrifuge/root.go index 327cdf1ca..80046f0e8 100644 --- a/cmd/centrifuge/root.go +++ b/cmd/centrifuge/root.go @@ -1,15 +1,9 @@ package main import ( - "context" "fmt" "os" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - c "github.com/centrifuge/go-centrifuge/context" - "github.com/centrifuge/go-centrifuge/node" - "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" "github.com/mitchellh/go-homedir" @@ -87,39 +81,3 @@ func setCentrifugeLoggers() { logging.SetAllLoggers(gologging.INFO) } - -func runBootstrap(cfgFile string) { - mb := c.MainBootstrapper{} - mb.PopulateRunBootstrappers() - ctx := map[string]interface{}{} - ctx[config.BootstrappedConfigFile] = cfgFile - err := mb.Bootstrap(ctx) - if err != nil { - // application must not continue to run - panic(err) - } -} - -func baseBootstrap(cfgFile string) map[string]interface{} { - mb := c.MainBootstrapper{} - mb.PopulateBaseBootstrappers() - ctx := map[string]interface{}{} - ctx[config.BootstrappedConfigFile] = cfgFile - err := mb.Bootstrap(ctx) - if err != nil { - // application must not continue to run - panic(err) - } - return ctx -} - -func commandBootstrap(cfgFile string) (map[string]interface{}, context.CancelFunc, error) { - ctx := baseBootstrap(cfgFile) - queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - // init node with only the queue server which is needed by commands - n := node.New([]node.Server{queueSrv}) - cx, canc := context.WithCancel(context.Background()) - e := make(chan error) - go n.Start(cx, e) - return ctx, canc, nil -} diff --git a/cmd/centrifuge/run.go b/cmd/centrifuge/run.go index a67e99a1e..26c23f1e7 100644 --- a/cmd/centrifuge/run.go +++ b/cmd/centrifuge/run.go @@ -1,6 +1,7 @@ package main import ( + "github.com/centrifuge/go-centrifuge/cmd" "github.com/spf13/cobra" ) @@ -9,11 +10,11 @@ var runCmd = &cobra.Command{ Use: "run", Short: "run a centrifuge node", Long: ``, - Run: func(cmd *cobra.Command, args []string) { - //cmd requires a config file + Run: func(cm *cobra.Command, args []string) { + //cm requires a config file cfgFile := ensureConfigFile() // the following call will block - runBootstrap(cfgFile) + cmd.RunBootstrap(cfgFile) }, } diff --git a/cmd/common.go b/cmd/common.go new file mode 100644 index 000000000..4553d2fa0 --- /dev/null +++ b/cmd/common.go @@ -0,0 +1,146 @@ +package cmd + +import ( + "context" + + logging "github.com/ipfs/go-log" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + c "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/keytools" + "github.com/centrifuge/go-centrifuge/node" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" +) + +var log = logging.Logger("centrifuge-cmd") + +func createIdentity(idService identity.Service) (identity.CentID, error) { + centID := identity.RandomCentID() + _, confirmations, err := idService.CreateIdentity(centID) + if err != nil { + return [identity.CentIDLength]byte{}, err + } + _ = <-confirmations + + return centID, nil +} + +func generateKeys(config config.Config) { + p2pPub, p2pPvt := config.GetSigningKeyPair() + ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() + keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") + keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") + keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") +} + +func addKeys(idService identity.Service) error { + err := idService.AddKeyFromConfig(identity.KeyPurposeP2P) + if err != nil { + panic(err) + } + err = idService.AddKeyFromConfig(identity.KeyPurposeSigning) + if err != nil { + panic(err) + } + err = idService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + if err != nil { + panic(err) + } + return nil +} + +// CreateConfig creates a config file using provide parameters and the default config +func CreateConfig( + targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, + apiPort, p2pPort int64, + bootstraps []string, + txPoolAccess bool, + smartContractAddrs *config.SmartContractAddresses) error { + + data := map[string]interface{}{ + "targetDataDir": targetDataDir, + "accountKeyPath": accountKeyPath, + "accountPassword": accountPassword, + "network": network, + "ethNodeURL": ethNodeURL, + "bootstraps": bootstraps, + "apiPort": apiPort, + "p2pPort": p2pPort, + "txpoolaccess": txPoolAccess, + } + if smartContractAddrs != nil { + data["smartContractAddresses"] = smartContractAddrs + } + v, err := config.CreateConfigFile(data) + if err != nil { + return err + } + log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) + ctx, canc, _ := CommandBootstrap(v.ConfigFileUsed()) + cfg := ctx[config.BootstrappedConfig].(*config.Configuration) + generateKeys(cfg) + + idService := ctx[identity.BootstrappedIDService].(identity.Service) + id, err := createIdentity(idService) + if err != nil { + return err + } + v.Set("identityId", id.String()) + err = v.WriteConfig() + if err != nil { + return err + } + cfg.Set("identityId", id.String()) + log.Infof("Identity created [%s] [%x]", id.String(), id) + err = addKeys(idService) + if err != nil { + return err + } + canc() + db := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + db.Close() + return nil +} + +// RunBootstrap bootstraps the node for running +func RunBootstrap(cfgFile string) { + mb := c.MainBootstrapper{} + mb.PopulateRunBootstrappers() + ctx := map[string]interface{}{} + ctx[config.BootstrappedConfigFile] = cfgFile + err := mb.Bootstrap(ctx) + if err != nil { + // application must not continue to run + panic(err) + } +} + +// BaseBootstrap bootstraps the node for testing purposes mainly +func BaseBootstrap(cfgFile string) map[string]interface{} { + mb := c.MainBootstrapper{} + mb.PopulateBaseBootstrappers() + ctx := map[string]interface{}{} + ctx[config.BootstrappedConfigFile] = cfgFile + err := mb.Bootstrap(ctx) + if err != nil { + // application must not continue to run + panic(err) + } + return ctx +} + +// CommandBootstrap bootstraps the node for one time commands +func CommandBootstrap(cfgFile string) (map[string]interface{}, context.CancelFunc, error) { + ctx := BaseBootstrap(cfgFile) + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + // init node with only the queue server which is needed by commands + n := node.New([]node.Server{queueSrv}) + cx, canc := context.WithCancel(context.Background()) + e := make(chan error) + go n.Start(cx, e) + return ctx, canc, nil +} diff --git a/config/configuration.go b/config/configuration.go index 87fd265fb..007c03da6 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -341,6 +341,11 @@ func (c *Configuration) InitializeViper() { c.v.SetEnvPrefix("CENT") } +// SmartContractAddresses encapsulates the smart contract addresses ne +type SmartContractAddresses struct { + IdentityFactoryAddr, IdentityRegistryAddr, AnchorRepositoryAddr, PaymentObligationAddr string +} + // CreateConfigFile creates minimum config file with arguments func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { targetDataDir := args["targetDataDir"].(string) @@ -396,6 +401,13 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("networks."+network+".bootstrapPeers", bootstraps) } + if smartContractAddresses, ok := args["smartContractAddresses"].(*SmartContractAddresses); ok { + v.Set("networks."+network+".contractAddresses.identityFactory", smartContractAddresses.IdentityFactoryAddr) + v.Set("networks."+network+".contractAddresses.identityRegistry", smartContractAddresses.IdentityRegistryAddr) + v.Set("networks."+network+".contractAddresses.anchorRepository", smartContractAddresses.AnchorRepositoryAddr) + v.Set("networks."+network+".contractAddresses.paymentObligation", smartContractAddresses.PaymentObligationAddr) + } + v.SetConfigFile(targetDataDir + "/config.yaml") err = v.WriteConfig() diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 24cdb02a3..e953cd55e 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -7,16 +7,19 @@ import ( "os/signal" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} -// Bootstrap runs the severs. +// Bootstrap runs the servers. // Note: this is a blocking call. func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { - srvs, err := getServers(c) + srvs, err := GetServers(c) if err != nil { + cleanUp(c) return fmt.Errorf("failed to load servers: %v", err) } @@ -30,17 +33,26 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { for { select { case err := <-feedback: + cleanUp(c) panic(err) case sig := <-controlC: log.Info("Node shutting down because of ", sig) canc() + cleanUp(c) err := <-feedback return err } } } -func getServers(ctx map[string]interface{}) ([]Server, error) { +func cleanUp(c map[string]interface{}) { + // close the node db + db := c[storage.BootstrappedLevelDB].(*leveldb.DB) + db.Close() +} + +// GetServers gets the long running background services in the node as a list +func GetServers(ctx map[string]interface{}) ([]Server, error) { p2pSrv, ok := ctx[bootstrap.BootstrappedP2PServer] if !ok { return nil, fmt.Errorf("p2p server not initialized") diff --git a/node/node.go b/node/node.go index dfc09aaec..5166a9a10 100644 --- a/node/node.go +++ b/node/node.go @@ -17,7 +17,7 @@ type Server interface { Name() string // Start starts the service, expectation is that this would always be called in a separate go routine. - // WaitGroup contract should always be honoured by calling `defer wg.Done()` + // WaitGroup contract must always be honoured by calling `defer wg.Done()` Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) } diff --git a/p2p/client.go b/p2p/client.go index 192c6387b..a41e42204 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -44,7 +44,7 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { // Decapsulate the /ipfs/ part from the target // /ip4//ipfs/ becomes /ip4/ - targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerID))) + targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", pid)) targetAddr := ipfsAddr.Decapsulate(targetPeerAddr) // We have a peer ID and a targetAddr so we add it to the peer store diff --git a/testworld/httputils.go b/testworld/httputils.go new file mode 100644 index 000000000..268813ea8 --- /dev/null +++ b/testworld/httputils.go @@ -0,0 +1,47 @@ +package testworld + +import ( + "crypto/tls" + "net/http" + "testing" + "time" + + "github.com/gavv/httpexpect" +) + +func createInsecureClient(t *testing.T, baseURL string) *httpexpect.Expect { + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + config := httpexpect.Config{ + BaseURL: baseURL, + Client: &http.Client{ + Transport: transport, + Timeout: time.Second * 600, + }, + Reporter: httpexpect.NewAssertReporter(t), + Printers: []httpexpect.Printer{ + httpexpect.NewCompactPrinter(t), + }, + } + return httpexpect.WithConfig(config) +} + +func getInvoiceAndCheck(e *httpexpect.Expect, docIdentifier string, currency string) *httpexpect.Value { + objGet := e.GET("/invoice/"+docIdentifier). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + Expect().Status(http.StatusOK).JSON().NotNull() + objGet.Path("$.header.document_id").String().Equal(docIdentifier) + objGet.Path("$.data.currency").String().Equal(currency) + return objGet +} + +func createInvoice(e *httpexpect.Expect, payload map[string]interface{}) *httpexpect.Object { + obj := e.POST("/invoice"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + WithJSON(payload). + Expect().Status(http.StatusOK).JSON().Object() + return obj +} diff --git a/testworld/keystore b/testworld/keystore new file mode 100644 index 000000000..9633d521f --- /dev/null +++ b/testworld/keystore @@ -0,0 +1 @@ +{"address":"89b0a86583c4444acfd71b463e0d3c55ae1412a5","crypto":{"cipher":"aes-128-ctr","ciphertext":"c779f8379d770d92cfc1ddd4a8f31d5a0adc8f2a0b2a1401370d3630f38c0c8a","cipherparams":{"iv":"36c168e73bf980fe75b0727f890a71ad"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"de1be16e3c981944d1eca2b8b27e4e6e0b5bfb43be0376a5d8889fa679a28122"},"mac":"cc128b815555ba1ead7cae9060e8842afca8356d06455bd9a5752ba6fcc092ef"},"id":"45e060a6-d2ae-43b8-922f-44829499d37d","version":3} \ No newline at end of file diff --git a/testworld/park.go b/testworld/park.go new file mode 100644 index 000000000..667542d4a --- /dev/null +++ b/testworld/park.go @@ -0,0 +1,248 @@ +// +build testworld + +package testworld + +import ( + "context" + "fmt" + "os" + "os/signal" + + "testing" + + "time" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/cmd" + "github.com/centrifuge/go-centrifuge/config" + ctx "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/node" + "github.com/gavv/httpexpect" + logging "github.com/ipfs/go-log" +) + +var log = logging.Logger("host") + +var hostconfig = []struct { + name string + apiPort, p2pPort int64 +}{ + {"Alice", 8084, 38204}, + {"Bob", 8085, 38205}, + {"Charlie", 8086, 38206}, +} + +// hostManager is the hostManager of the hosts at Testworld (Robert) +type hostManager struct { + + // network settings + ethNodeUrl, accountKeyPath, accountPassword, network string + + txPoolAccess bool + + // contractAddresses are the addresses of centrifuge contracts on Ethereum + contractAddresses *config.SmartContractAddresses + + // bernard is the bootnode for all the hosts + bernard *host + + // niceHosts are the happy and nice hosts at the Testworld such as Teddy + niceHosts map[string]*host + + // TODO create evil hosts such as William (or Eve) + + // canc is the cancel signal for all hosts + canc context.CancelFunc +} + +func newHostManager( + ethNodeUrl, accountKeyPath, accountPassword, network string, + txPoolAccess bool, + smartContractAddrs *config.SmartContractAddresses) *hostManager { + return &hostManager{ + ethNodeUrl: ethNodeUrl, + accountKeyPath: accountKeyPath, + accountPassword: accountPassword, + network: network, + txPoolAccess: txPoolAccess, + contractAddresses: smartContractAddrs, + niceHosts: make(map[string]*host), + } +} + +func (r *hostManager) init() error { + cancCtx, canc := context.WithCancel(context.Background()) + r.bernard = r.createHost("Bernard", 8081, 38201, nil) + err := r.bernard.init() + if err != nil { + return err + } + + // start and wait for Bernard since other hosts depend on him + go r.bernard.start(cancCtx) + time.Sleep(10 * time.Second) + + bootnode, err := r.bernard.p2pURL() + if err != nil { + return err + } + + // start hosts + for _, h := range hostconfig { + r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, []string{bootnode}) + err = r.niceHosts[h.name].init() + if err != nil { + return err + } + go r.niceHosts[h.name].start(cancCtx) + } + r.canc = canc + // print host centIDs + for name, host := range r.niceHosts { + i, err := host.id() + if err != nil { + return err + } + fmt.Printf("CentID for %s is %s \n", name, i) + } + return nil +} + +func (r *hostManager) getHost(name string) *host { + if h, ok := r.niceHosts[name]; ok { + return h + } + return nil +} + +func (r *hostManager) stop() { + r.canc() +} + +func (r *hostManager) createHost(name string, apiPort, p2pPort int64, bootstraps []string) *host { + // TODO make configs selectable as settings for different networks, eg Kovan + parity + return newHost( + name, + r.ethNodeUrl, + r.accountKeyPath, + r.accountPassword, + r.network, + apiPort, p2pPort, bootstraps, + r.txPoolAccess, + r.contractAddresses, + ) +} + +type host struct { + name, dir, ethNodeUrl, accountKeyPath, accountPassword, network, + identityFactoryAddr, identityRegistryAddr, anchorRepositoryAddr, paymentObligationAddr string + apiPort, p2pPort int64 + bootstrapNodes []string + bootstrappedCtx map[string]interface{} + txPoolAccess bool + smartContractAddrs *config.SmartContractAddresses + config config.Config + identity identity.Identity + node *node.Node +} + +func newHost( + name, ethNodeUrl, accountKeyPath, accountPassword, network string, + apiPort, p2pPort int64, + bootstraps []string, + txPoolAccess bool, + smartContractAddrs *config.SmartContractAddresses, +) *host { + return &host{ + name: name, + ethNodeUrl: ethNodeUrl, + accountKeyPath: accountKeyPath, + accountPassword: accountPassword, + network: network, + apiPort: apiPort, + p2pPort: p2pPort, + bootstrapNodes: bootstraps, + txPoolAccess: txPoolAccess, + smartContractAddrs: smartContractAddrs, + dir: "peerconfigs/" + name, + } +} + +func (h *host) init() error { + err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.smartContractAddrs) + if err != nil { + return err + } + m := ctx.MainBootstrapper{} + m.PopulateBaseBootstrappers() + h.bootstrappedCtx = map[string]interface{}{ + config.BootstrappedConfigFile: h.dir + "/config.yaml", + } + err = m.Bootstrap(h.bootstrappedCtx) + if err != nil { + return err + } + h.config = h.bootstrappedCtx[config.BootstrappedConfig].(config.Config) + idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) + idBytes, err := h.config.GetIdentityID() + if err != nil { + return err + } + id, err := identity.ToCentID(idBytes) + if err != nil { + return err + } + h.identity, err = idService.LookupIdentityForID(id) + if err != nil { + return err + } + return nil +} + +func (h *host) start(c context.Context) error { + srvs, err := node.GetServers(h.bootstrappedCtx) + if err != nil { + return fmt.Errorf("failed to load servers: %v", err) + } + + h.node = node.New(srvs) + feedback := make(chan error) + // may be we can pass a context that exists in c here + cancCtx, canc := context.WithCancel(context.WithValue(c, bootstrap.NodeObjRegistry, h.bootstrappedCtx)) + go h.node.Start(cancCtx, feedback) + controlC := make(chan os.Signal, 1) + signal.Notify(controlC, os.Interrupt) + for { + select { + case err := <-feedback: + log.Error(h.name+" encountered error ", err) + return err + case sig := <-controlC: + log.Info(h.name+" shutting down because of ", sig) + canc() + err := <-feedback + return err + } + } +} + +func (h *host) createInvoice(e *httpexpect.Expect, inv map[string]interface{}) (*httpexpect.Object, error) { + return createInvoice(e, inv), nil +} + +func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { + return createInsecureClient(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) +} + +func (h *host) id() (identity.CentID, error) { + return h.identity.CentID(), nil +} + +func (h *host) p2pURL() (string, error) { + lastB58Key, err := h.identity.CurrentP2PKey() + if err != nil { + return "", err + } + return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", h.p2pPort, lastB58Key), nil +} diff --git a/testworld/park_test.go b/testworld/park_test.go new file mode 100644 index 000000000..8fa152aab --- /dev/null +++ b/testworld/park_test.go @@ -0,0 +1,69 @@ +// +build testworld + +package testworld + +import ( + "testing" + + "fmt" + "os" +) + +// TODO remember to cleanup config files generated + +var doctorFord *hostManager + +func TestMain(m *testing.M) { + // TODO start POA geth here + //runSmartContractMigrations() + contractAddresses := getSmartContractAddresses() + doctorFord = newHostManager("ws://127.0.0.1:9546", + "keystore", "", "testing", true, contractAddresses) + err := doctorFord.init() + if err != nil { + panic(err) + } + fmt.Printf("contract addresses %+v\n", contractAddresses) + result := m.Run() + doctorFord.stop() + os.Exit(result) +} + +func TestHost_Happy(t *testing.T) { + alice := doctorFord.getHost("Alice") + bob := doctorFord.getHost("Bob") + charlie := doctorFord.getHost("Charlie") + eAlice := alice.createHttpExpectation(t) + eBob := bob.createHttpExpectation(t) + eCharlie := charlie.createHttpExpectation(t) + + b, err := bob.id() + if err != nil { + t.Error(err) + } + + c, err := charlie.id() + if err != nil { + t.Error(err) + } + res, err := alice.createInvoice(eAlice, map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "GBP", + "net_amount": "40", + }, + "collaborators": []string{b.String(), c.String()}, + }) + if err != nil { + t.Error(err) + } + docIdentifier := res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + getInvoiceAndCheck(eBob, docIdentifier, "GBP") + getInvoiceAndCheck(eCharlie, docIdentifier, "GBP") + fmt.Println("Host test success") +} diff --git a/testworld/peerconfigs/.gitkeep b/testworld/peerconfigs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/testworld/util.go b/testworld/util.go new file mode 100644 index 000000000..9fb2898c4 --- /dev/null +++ b/testworld/util.go @@ -0,0 +1,74 @@ +// +build testworld + +package testworld + +import ( + "io/ioutil" + "os" + "os/exec" + "path" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/savaki/jq" +) + +// runSmartContractMigrations migrates smart contracts to localgeth +func runSmartContractMigrations() { + projDir := getProjectDir() + migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") + _, err := exec.Command(migrationScript, projDir).Output() + if err != nil { + log.Fatal(err) + } +} + +// getSmartContractAddresses finds migrated smart contract addresses for localgeth +func getSmartContractAddresses() *config.SmartContractAddresses { + projDir := getProjectDir() + deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + dat, err := ioutil.ReadFile(deployJSONFile) + if err != nil { + panic(err) + } + idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") + idRegistryAddrOp := getOpForContract(".contracts.IdentityRegistry.address") + anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") + payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") + return &config.SmartContractAddresses{ + IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), + IdentityRegistryAddr: getOpAddr(idRegistryAddrOp, dat), + AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), + PaymentObligationAddr: getOpAddr(payObAddrOp, dat), + } +} + +func getOpAddr(addrOp jq.Op, dat []byte) string { + addr, err := addrOp.Apply(dat) + if err != nil { + panic(err) + } + + // remove extra quotes inside the string + addrStr := string(addr) + if len(addrStr) > 0 && addrStr[0] == '"' { + addrStr = addrStr[1:] + } + if len(addrStr) > 0 && addrStr[len(addrStr)-1] == '"' { + addrStr = addrStr[:len(addrStr)-1] + } + return addrStr +} + +func getOpForContract(selector string) jq.Op { + addrOp, err := jq.Parse(selector) + if err != nil { + panic(err) + } + return addrOp +} + +func getProjectDir() string { + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") + return projDir +} diff --git a/testworld/util_test.go.test b/testworld/util_test.go.test new file mode 100644 index 000000000..314c290d7 --- /dev/null +++ b/testworld/util_test.go.test @@ -0,0 +1,21 @@ +// These aren't proper tests, just for checking if the util functions work + +package tests + +import ( + "testing" + "fmt" + ) + +func TestRunMigrations(t *testing.T) { + runSmartContractMigrations() +} + +func TestGetSmartContractAddresses(t *testing.T) { + //runSmartContractMigrations() + c := getSmartContractAddresses() + if c == nil { + t.Error("Failed") + } + fmt.Printf("%+v\n", c) +} \ No newline at end of file From e829f2f65fc08ab6ee4d632b8309b25979cce2f3 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 3 Dec 2018 18:09:52 +0100 Subject: [PATCH 052/220] Fix create an already updated version for first time (#527) --- documents/invoice/service.go | 9 +++++++++ documents/purchaseorder/service.go | 9 +++++++++ p2p/handler_integration_test.go | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index f343c05d9..bd6561ad4 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -19,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/signatures" + "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -351,6 +352,14 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to Unpack CoreDocument: %v", err)) } + // Logic for receiving version n (n > 1) of the document for the first time + if !s.repo.Exists(doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(doc.DocumentIdentifier, model) + if err != nil { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store local first version of the document: %v", err)) + } + } + err = s.repo.Create(doc.CurrentVersion, model) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store document: %v", err)) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 973987624..a67859d1a 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -19,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/signatures" + "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" @@ -350,6 +351,14 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to Unpack CoreDocument: %v", err)) } + // Logic for receiving version n (n > 1) of the document for the first time + if !s.repo.Exists(cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { + err = s.repo.Create(cd.DocumentIdentifier, model) + if err != nil { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store local first version of the document: %v", err)) + } + } + err = s.repo.Create(cd.CurrentVersion, model) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store document: %v", err)) diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 84e6222bd..3ff71a0ef 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -100,6 +100,22 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") } +func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { + doc := prepareDocumentForP2PHandler(t, nil) + newDoc, err := coredocument.PrepareNewVersion(*doc, nil) + assert.Nil(t, err) + assert.NotEqual(t, newDoc.DocumentIdentifier, newDoc.CurrentVersion) + updateDocumentForP2Phandler(t, newDoc) + newDoc = prepareDocumentForP2PHandler(t, newDoc) + req := getSignatureRequest(newDoc) + resp, err := handler.RequestDocumentSignature(context.Background(), req) + assert.Nil(t, err, "must be nil") + assert.NotNil(t, resp, "must be non nil") + assert.NotNil(t, resp.Signature.Signature, "must be non nil") + sig := resp.Signature + assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") +} + func TestHandler_RequestDocumentSignature(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) From eb6a53e6883ad5a43a75444de25553f1b994c794 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 4 Dec 2018 16:22:03 +0100 Subject: [PATCH 053/220] updated paymentObligation addresses for rinkeby and kovan (#530) --- build/configs/default_config.yaml | 4 ++-- resources/data.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index fd45aeacd..295650261 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -30,7 +30,7 @@ networks: identityFactory: "0x90d294571e73842697a66b7a99a09dd6c73d356d" identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" anchorRepository: "0x7f854dfa98012d7fa55c803bba2260bcdee4b5ed" - paymentObligation: "0x691280677b52e3ca71e023eed2d83fa9fac3b64b" + paymentObligation: "0xdb0581A9328664855328AdDb0E251184640f9e5D" bernalheights: # Numeric ID of the Centrifuge network @@ -46,7 +46,7 @@ networks: identityFactory: "0x85b32f7a3f40481f12334041670c8cbe07f7d79c" identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" - paymentObligation: "0xa3d3b45f422016201d7cd4c2bc217665483d90e6" + paymentObligation: "0x0417eb37941164368401D666984cED7694ABcBb1" # Peer-to-peer configurations p2p: diff --git a/resources/data.go b/resources/data.go index 2548ab5f7..23778dfc7 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x4b\x53\xe4\x38\x12\xbe\xd7\xaf\xc8\xa0\x2f\xbb\x87\x06\x5b\xb2\x65\xbb\x6e\x34\xd0\xf3\x68\x9a\x85\x82\x6e\x06\x6e\xb2\x94\xb6\x35\xb8\x24\xb7\x24\xd7\x63\x7e\xfd\x86\xfc\xa0\x81\x1e\xd8\x8d\x8d\x98\x1d\x4e\x0a\x2b\xf3\xcb\xd7\xf7\xa9\x92\x77\x70\x8a\x15\xef\x5b\x0f\x12\x37\xd8\x9a\x6e\x8d\xda\x83\x47\xe7\x35\x7a\xe0\x35\x57\xda\x79\xb0\x4a\x3f\x60\xb9\x5f\x08\xd4\xde\xaa\xaa\xaf\xf1\x02\xfd\xd6\xd8\x87\x25\xd8\xde\x39\xc5\x75\xa3\xda\x76\x31\x80\x29\x8d\xe0\x1b\x04\x39\xe1\xea\xd1\xd2\x81\x6f\xb8\x87\x93\x47\x04\x58\x73\xa5\x7d\xc0\x5f\xcc\x26\xcb\x05\xc0\x3b\x38\x37\x82\xb7\x43\x0a\x4a\xd7\x20\x8c\xf6\x96\x0b\x0f\x5c\x4a\x8b\xce\xa1\x03\x8d\x28\xc1\x1b\x28\x11\x1c\x7a\xd8\x2a\xdf\x00\xea\x0d\x6c\xb8\x55\xbc\x6c\xd1\x1d\x2e\x60\xf6\x0f\x90\x00\x4a\x2e\x81\x52\x3a\x9c\xd1\x37\x68\xb1\x5f\x4f\x15\xfc\x22\x97\x90\xd3\x7c\xbc\x2b\x8d\xf1\xce\x5b\xde\x5d\x22\x5a\x37\xfa\x02\xbc\x87\x83\x23\xd5\x25\x47\x31\xc9\x0e\xa3\xc3\xe8\x30\x3e\xf2\xa2\x3b\xa2\x39\x89\xc8\x91\xea\x2a\x77\x74\xb5\xbe\xb9\xda\x95\xdb\x87\xfe\xfe\xee\xee\xb4\xea\xff\xb8\x29\x77\x67\xc7\x2b\xbc\xb9\x38\x39\x37\x7f\xec\xf7\x69\x9a\x6f\xae\x74\xfd\x75\x73\xf9\xf9\xf7\xf3\xbb\x87\x83\xff\x08\x4b\x67\xd8\xaf\x15\x3b\xbb\x60\xeb\x87\x6f\xb7\xf8\xfb\xed\xa7\x5b\xf2\xed\xb2\x8f\xd9\x6f\x9d\xfc\x89\x3e\xfc\x6a\xe2\x1b\xba\x6e\x78\x73\xf9\x21\xbd\xc6\x54\xc7\x23\xec\xdc\xae\xe3\xb9\x5b\x73\x11\x4a\xa2\xf6\xca\xef\x3f\x72\xe1\x8d\xdd\x2f\xe1\xe0\xe0\xc5\xcd\x0a\x6b\xe5\xfc\xb3\x2b\xae\x45\x63\xec\x0a\x3b\xe3\xd4\x0b\xaf\x8e\xef\x03\x55\xfe\x55\xb6\xaa\xe6\x5e\x19\x3d\xdc\x0d\x03\xfc\xcc\x95\xfe\x53\x3a\x4d\x73\x5e\xc0\x53\xd6\x8c\x09\xbe\x83\x8b\x7e\x8d\x56\x09\xf8\xe5\x14\x4c\x35\x30\xe8\x09\x57\xbe\x7b\x8e\xc3\x4c\xe3\xc9\xeb\xc3\x3c\x31\x68\x95\xf3\xc1\x53\x1b\x89\x3f\x92\xad\xb3\x66\xa3\x86\x0b\x33\x60\x3f\x49\x60\x4e\xef\xbf\x60\x00\x4d\x0f\x09\x49\x0f\x49\x14\x1d\x26\xe4\x25\x0b\x62\x72\x4a\x3f\x19\x73\x7b\xae\x94\xb8\xfa\xba\xbd\x69\x6e\x3e\xdc\xb1\xdd\x27\x71\x69\xce\x2b\xb6\xba\xba\xfb\xf5\x63\xb7\xad\x62\x9b\xa5\xdb\xf3\x1d\xb9\x5f\xd1\xee\x44\xc6\x2f\xb9\x30\x05\xc8\xd9\x21\x89\xa3\xd7\x02\x5c\xdd\x7f\x3e\xce\x7f\xba\xfc\xd9\x6e\xce\xee\x3f\x14\x5b\xf9\x60\xbe\x88\xe3\xe3\xf5\xc9\xfd\xcf\x5d\x81\xfb\xfd\x7d\x72\x7d\x96\xd7\x1f\x2d\x6d\x6e\x2e\x7e\x3b\x98\xfa\x74\x36\xb1\x7e\xee\x64\x68\xf3\x7b\x58\x4d\xba\x7e\x45\x17\xc9\xe4\x7c\xce\x43\x8b\x40\x62\xd7\x9a\x3d\x4a\xb8\x5e\x73\xeb\xe1\x64\xa2\x9a\x83\xca\xd8\xa1\xa9\xb5\xda\xa0\x7e\xd6\xce\x1f\xe9\x08\xaf\xf2\x31\xda\x15\x91\x24\x45\x92\x66\x31\x66\x34\x4f\x08\x2b\x32\xce\x58\x99\xf1\xa2\xe0\x51\x21\x25\x13\x19\x95\x34\x65\xf2\x0d\xe6\x46\xbb\x82\xb1\x48\x44\xb4\x90\x34\x8e\x93\x94\xf2\x2a\x92\x69\x2e\x52\xc6\x58\x46\xa8\x2c\x04\xa9\x78\x26\x19\x8a\x37\x38\x1e\xed\xb2\x2a\x4f\x13\x59\xf1\x22\x8f\x62\x22\xb3\x8a\xa7\xa9\xc8\x23\x5a\x96\x9c\x10\x16\x95\x42\x22\x26\x65\x8a\xf2\x2d\x35\x44\x3b\x56\xc4\x24\x8f\x58\x96\x95\x29\x41\x2a\x78\x16\x63\x44\x28\xa2\x24\x32\xa7\x15\x2f\x2a\x2e\x68\xc9\x92\x72\xd0\x4d\x89\x56\xf3\xb6\x41\x55\x37\xde\xfd\x6f\xa2\x20\xff\x47\x51\xfc\xc5\x92\xf8\x9b\x04\xf1\xc9\x6c\xb8\x7e\x55\x0e\xe4\x2f\xd0\xc3\x1b\x72\xc8\xd3\x92\x92\x2a\xe3\xb4\x4a\xa2\x24\x8f\xab\x98\x50\x9a\x44\x49\xcc\xb2\x48\xe4\xa2\xc4\x28\xab\x32\x99\x15\xe2\x4d\x39\xa4\x09\x47\x9a\xd1\x2a\x2a\x58\xc5\x2b\x22\x4b\x56\xe6\x3c\x61\x59\x9c\x89\xa8\x2c\x72\x14\x15\x8f\xb2\x54\xca\x37\xe5\x90\x24\x49\xc5\x92\x02\x69\x94\x25\x09\xc1\x8c\x09\x51\x65\x34\x4b\x18\xc3\x94\x54\x31\x8b\x8a\xb2\xc8\x09\x8b\xde\x96\x03\xa7\x92\x96\x49\x5a\x25\x84\x44\x31\x23\x51\x2c\x33\x21\x13\x41\x4a\x41\xe2\x8c\xb1\x34\xc9\xa9\x2c\x22\x64\x07\x8b\xc5\x3b\x08\x54\x7b\xef\xcd\xfb\x0e\xd1\x86\xb6\x55\xaa\xee\xed\x80\xe5\x16\x1d\xe9\xc6\x55\xe1\x46\xad\xd1\xf4\x1e\xb6\x0d\x6a\x30\x1d\xea\x69\x63\xd0\x28\x06\xcb\x40\xec\x00\xe0\x16\x30\x7f\x9e\x5c\x96\x70\x40\x23\x37\x44\xba\xea\xb1\xc7\x17\x21\x86\x11\x72\xb7\xd7\xa2\xb1\x46\x9b\xde\x05\xad\x08\x74\x4e\xe9\x7a\xf1\x2d\x38\x8c\x09\x8c\xfb\x8e\x1b\xa6\xad\xfb\x75\x89\x36\xa8\x2d\x10\x06\xad\x3b\x12\x46\xbb\x20\xe0\x49\x79\xdb\xa0\xab\x12\x81\xb7\xad\x11\xdc\xa3\x04\xee\xc1\x79\x6e\x7d\xdf\x2d\x20\xf8\xdf\x8e\x8e\x4b\x20\x03\xfa\x47\x8b\xe8\xa0\xef\xe0\xe4\xf2\x0b\x88\xbd\x68\xd1\x8d\xa5\x8e\x01\x40\x39\xd8\x72\x35\xac\x49\x21\x5f\xdc\xa0\xf6\xa1\xd4\xf1\xfa\x96\xab\xa1\xda\xcf\xd7\x4b\x88\x43\xa1\x8f\x94\x77\x1d\x0a\x55\x29\xf1\xbc\xe8\xc5\x4c\xf9\xb1\xb4\x6b\x6c\x31\x90\x79\xdb\x28\xd1\x3c\xca\x01\xb8\x10\xa6\x0f\xbf\xe9\x06\x7a\x87\xf3\xab\x64\x42\x13\xa6\xe7\x44\x82\xd2\xc3\x47\xd1\x3b\x6f\xd6\x53\x10\xa8\x54\x8b\x0b\x98\xd7\xc2\xe3\x11\xe6\x82\xaf\x71\x09\x07\x61\x15\x3c\x78\x5c\xfe\x42\x32\x33\xf0\x63\x5c\xd1\xaa\xb0\x4a\x84\x87\x0c\xfe\xb1\x45\xb0\xf8\xad\x57\x16\x61\xeb\xc0\x58\x50\x9d\x98\x36\xc2\xb0\x00\x86\xa3\xe0\x3e\xa4\x3d\xb4\xe4\x9f\xa1\xbb\x46\xe2\x97\xd5\xf9\x12\x1a\xef\xbb\xe5\xd1\x51\x18\x41\xdb\x18\xe7\x97\x45\x9a\xa4\xf3\x30\x87\x8d\xb5\xe6\xa1\x16\x25\x42\xba\x35\x77\x97\xe1\xb8\x84\x38\x9a\xff\x7e\x30\x6e\xd5\x5a\xf9\xd1\xf8\x3c\x1c\x97\x90\x64\x31\xa1\x79\xfe\x8c\xa4\xde\x0c\xd3\x1a\xa9\xa5\xbf\x57\xe6\x2d\xd7\x8e\x0f\x84\x9d\x6b\x90\x72\xdc\x70\x39\x94\xad\x11\x0f\xc0\xb5\x9c\x4a\x01\x6f\x55\x5d\xa3\x45\x39\x52\xda\xe3\xce\xcf\x83\x1e\x69\xcd\xa2\xc0\xeb\xd7\x02\x5b\xe4\x12\x8c\x6e\xf7\x41\x2e\x33\xd9\xe7\x35\x7f\x4e\xe9\x3b\xf4\x0a\xb9\x7c\x0e\x1f\xa7\x13\xfa\x45\x98\xc4\xd3\xdc\x3b\x63\x5a\x58\xf3\x1d\x58\xf4\x56\x8d\xbf\x2a\x0e\xb5\x04\xfe\xcc\xcc\x6c\xd0\x2e\x20\x18\xae\x46\xbb\x25\x90\xa9\xa7\x7f\x0e\xa9\xb4\x47\xbb\xe1\xed\x80\xbb\x1f\x05\xc0\x43\x82\xa2\xb7\x76\x58\x2f\x9f\x78\x34\xdc\x41\x89\x18\xf6\x4f\x8f\xc2\x0f\x6d\x9a\x01\x42\xbc\xf0\x9e\x91\xa9\x82\x53\xe5\x06\xb6\x0c\x88\xce\xac\x7f\x60\x9b\x03\x69\x40\x1b\x0f\xae\xef\x3a\x63\x3d\xf8\xdd\x90\x11\xef\x54\xf8\x0f\x63\x77\x69\x4c\x7b\x2c\xc2\xb3\x70\xa6\x03\x92\x5c\x82\xb7\x3d\x06\xad\x71\xbd\x07\x89\x65\x5f\xd7\xd3\x93\x14\x24\x30\x3c\x00\xb5\x81\x10\x64\x31\xdc\x8e\x52\xeb\x3a\x6b\xaa\x61\x3c\x8f\x2e\x0b\x18\xbf\x2e\xa1\xe2\xad\xc3\xc5\xbf\x03\x00\x00\xff\xff\x12\x91\x2c\x71\xa8\x0d\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x57\xc9\x72\xdc\x38\x12\xbd\xf3\x2b\x32\xca\x97\x99\x83\x25\x70\x03\xc9\xba\x95\x16\xf7\x62\x59\x23\x95\x64\xab\xa5\x1b\x08\x24\x49\xb4\x58\x00\x0d\x80\xb5\xf4\xd7\x4f\x80\x8b\x2c\xd9\x96\x3a\x62\x26\xe6\x34\x75\x62\x10\x99\x2f\xb7\xf7\xc0\xac\x77\x70\x86\x15\xeb\x5b\x07\x02\xb7\xd8\xea\x6e\x83\xca\x81\x43\xeb\x14\x3a\x60\x35\x93\xca\x3a\x30\x52\x3d\x62\x79\x08\x38\x2a\x67\x64\xd5\xd7\x78\x89\x6e\xa7\xcd\xe3\x12\x4c\x6f\xad\x64\xaa\x91\x6d\x1b\x0c\x60\x52\x21\xb8\x06\x41\x4c\xb8\x6a\xb4\xb4\xe0\x1a\xe6\xe0\xf4\x09\x01\x36\x4c\x2a\xe7\xf1\x83\xd9\x64\x19\x00\xbc\x83\x0b\xcd\x59\x3b\xa4\x20\x55\x0d\x5c\x2b\x67\x18\x77\xc0\x84\x30\x68\x2d\x5a\x50\x88\x02\x9c\x86\x12\xc1\xa2\x83\x9d\x74\x0d\xa0\xda\xc2\x96\x19\xc9\xca\x16\xed\x51\x00\xb3\xbf\x87\x04\x90\x62\x09\x71\x1c\x0f\xcf\xe8\x1a\x34\xd8\x6f\xa6\x0a\x7e\x13\x4b\xc8\xe3\x7c\x3c\x2b\xb5\x76\xd6\x19\xd6\x5d\x21\x1a\x3b\xfa\xbe\x87\xc5\xb1\xec\x92\xe3\x30\xca\x8e\xc8\x11\x39\x0a\x8f\x1d\xef\x8e\xe3\x3c\x22\xd1\xb1\xec\x2a\x7b\x7c\xbd\xb9\xbd\xde\x97\xbb\xc7\xfe\xe1\xfe\xfe\xac\xea\xff\xba\x2d\xf7\xe7\xab\x35\xde\x5e\x9e\x5e\xe8\xbf\x0e\x87\x34\xcd\xb7\xd7\xaa\xfe\xb2\xbd\xfa\xf4\xe7\xc5\xfd\xe3\xe2\x6f\x40\xe3\x19\xf4\x4b\x45\xcf\x2f\xe9\xe6\xf1\xeb\x1d\xfe\x79\xf7\xf1\x2e\xfa\x7a\xd5\x87\xf4\x8f\x4e\xfc\x12\x3f\xfe\xae\xc3\xdb\x78\xd3\xb0\xe6\xea\x24\xbd\xc1\x54\x85\x23\xe8\xdc\xaa\xd5\xdc\xa9\xb1\x00\x5f\x3e\x2a\x27\xdd\xe1\x03\xe3\x4e\x9b\xc3\x12\x16\x8b\xef\x4e\xd6\x58\x4b\xeb\x5e\x1c\x31\xc5\x1b\x6d\xd6\xd8\x69\x2b\xbf\xf3\xea\xd8\xc1\xd3\xe4\x5f\x65\x2b\x6b\xe6\xa4\x56\xc3\xd9\x30\xbc\x4f\x4c\xaa\x9f\x52\x69\x9a\x71\x00\xcf\x19\x33\x26\xf8\x0e\x2e\xfb\x0d\x1a\xc9\xe1\xb7\x33\xd0\xd5\xc0\x9e\x67\x3c\xf9\xe6\x39\x0e\x32\x0d\x27\xaf\x93\x79\x5a\xd0\x4a\xeb\xbc\xa7\xd2\x02\x7f\x24\x5a\x67\xf4\x56\x0e\x07\x7a\xc0\x7e\x96\xc0\x9c\xde\xdf\x4e\x3f\x4e\x8f\xa2\x28\x3d\x8a\x08\x39\x4a\xa2\xef\x19\x10\x46\x67\xf1\x47\xad\xef\x2e\xa4\xe4\xd7\x5f\x76\xb7\xcd\xed\xc9\x3d\xdd\x7f\xe4\x57\xfa\xa2\xa2\xeb\xeb\xfb\xdf\x3f\x74\xbb\x2a\x34\x59\xba\xbb\xd8\x47\x0f\xeb\xb8\x3b\x15\xe1\xe2\x67\xf0\x39\x3d\x8a\x42\xf2\x1a\xfc\xf5\xc3\xa7\x55\xfe\xcb\xd5\xaf\x66\x7b\xfe\x70\x52\xec\xc4\xa3\xfe\xcc\x57\xab\xcd\xe9\xc3\xaf\x5d\x81\x87\xc3\x43\x72\x73\x9e\xd7\x1f\x4c\xdc\xdc\x5e\xfe\xb1\x98\x7a\x74\x3e\xb1\x7d\xee\xa2\x6f\xf1\x7b\x58\x4f\x7a\x7e\x45\x0f\xc9\xe4\x7c\xc1\x7c\x7b\x40\x60\xd7\xea\x03\x0a\xb8\xd9\x30\xe3\xe0\x74\xa2\x99\x85\x4a\x9b\xa1\xa1\xb5\xdc\xa2\x7a\xd1\xca\x1f\xa9\x08\xaf\x72\x91\xec\x0b\x22\xa2\x22\x49\xb3\x10\xb3\x38\x4f\x22\x5a\x64\x8c\xd2\x32\x63\x45\xc1\x48\x21\x04\xe5\x59\x2c\xe2\x94\x8a\x37\x58\x4b\xf6\x05\xa5\x84\x93\xb8\x10\x71\x18\x26\x69\xcc\x2a\x22\xd2\x9c\xa7\x94\xd2\x2c\x8a\x45\xc1\xa3\x8a\x65\x82\x22\x7f\x83\xdf\x64\x9f\x55\x79\x9a\x88\x8a\x15\x39\x09\x23\x91\x55\x2c\x4d\x79\x4e\xe2\xb2\x64\x51\x44\x49\xc9\x05\x62\x52\xa6\x28\xde\x52\x02\xd9\x8b\x92\xa4\x79\xb8\x2a\xe2\x28\xa7\x34\xc9\xd3\x34\x8e\xf2\x95\x38\x2b\xc9\x79\x94\x86\x61\x9e\xd0\x84\x54\x05\xa6\x67\x83\x66\x4a\x34\x8a\xb5\x0d\xca\xba\x71\xf6\x3f\x13\x44\xf4\x5f\x0a\xe2\x45\x0a\xff\xa7\x92\xf8\xa8\xb7\x4c\xbd\x2a\x88\xe8\x7f\xa0\x88\x37\x04\x91\xa7\x65\x1c\x55\x19\x8b\xab\x84\x24\x79\x58\x85\x51\x1c\x27\x24\x09\x69\x46\x78\xce\x4b\x24\x59\x95\x89\xac\xe0\x6f\x0a\x22\x4d\x18\xc6\x59\x5c\x91\x82\x56\xac\x8a\x44\x49\xcb\x9c\x25\x34\x0b\x33\x4e\xca\x22\x47\x5e\x31\x92\xa5\x42\xbc\x29\x88\x24\x49\x2a\x9a\x14\x18\x93\x2c\x49\x22\xcc\x28\xe7\x55\x16\x67\x09\xa5\x98\x46\x55\x48\x49\x51\x16\x79\x44\xc9\xdb\x82\x20\x49\x98\x61\x19\x67\x45\x12\x86\x34\x89\x69\x9e\x90\xf0\x8c\x52\x5a\xe4\x09\x3f\x3f\xcb\x68\x91\xac\x4e\xf8\x49\x19\x2e\x82\xe0\x1d\x78\xaa\xbd\x77\xfa\x7d\x87\x68\x7c\xdb\x2a\x59\xf7\x66\xc0\xb2\x41\x17\x75\xe3\x92\x70\x2b\x37\xa8\x7b\x07\xbb\x06\x15\xe8\x0e\xd5\xb4\x2b\x28\xe4\x83\xa5\xa7\xb6\x07\xb0\x01\xcc\xaf\x27\x97\x25\x2c\x62\x62\x87\x48\xd7\x3d\xf6\xf8\x5d\x88\x61\x84\xcc\x1e\x14\x6f\x8c\x56\xba\xb7\x5e\x2d\x1c\xad\x95\xaa\x0e\xbe\x7a\x87\x31\x81\x71\xd3\xb1\xc3\xb4\x55\xbf\x29\xd1\x78\xbd\x79\xc2\xa0\xb1\xc7\x5c\x2b\xeb\x25\x3c\x69\x6f\xe7\x3f\x35\x25\x02\x6b\x5b\xcd\x99\x43\x01\xcc\x81\x75\xcc\xb8\xbe\x0b\xc0\xfb\xdf\x8d\x8e\x4b\x88\x06\xf4\x0f\x06\xd1\x42\xdf\xc1\xe9\xd5\x67\xe0\x07\xde\xa2\x1d\x4b\x1d\x03\x80\xb4\xb0\x63\x72\x58\x90\x7c\xbe\xb8\x45\xe5\x7c\xa9\xe3\xf1\x1d\x93\x43\xb5\x9f\x6e\x96\x10\xfa\x42\x9f\x28\x6f\x3b\xe4\xb2\x92\xfc\x65\xd1\xc1\x4c\xf9\xb1\xb4\x1b\x6c\xd1\x93\x79\xd7\x48\xde\x3c\xc9\x01\x18\xe7\xba\xf7\x5f\x74\x0d\xbd\xc5\xf9\x5e\xd2\xbe\x09\xd3\x85\x22\x40\xaa\xe1\x25\xef\xad\xd3\x9b\x29\x08\x54\xb2\xc5\x00\xe6\x85\x70\x35\xc2\x5c\xb2\x0d\x2e\x61\xe1\x97\xc0\xc5\xd3\xda\xe7\x93\x99\x81\x9f\xe2\xf2\x56\xfa\x45\xc2\x5f\x65\xf0\x8f\x1d\x82\xc1\xaf\xbd\x34\x08\x3b\x0b\xda\x80\xec\xf8\xb4\x0b\xfa\xd5\xcf\x3f\x72\xe6\x7c\xda\x43\x4b\xfe\xe9\xbb\xab\x05\x7e\x5e\x5f\x2c\xa1\x71\xae\x5b\x1e\x1f\xfb\x11\xb4\x8d\xb6\x6e\x59\xa4\x49\x3a\x0f\x73\xd8\x55\x6b\xe6\x6b\x91\xdc\xa7\x5b\x33\x7b\xe5\x1f\x97\x10\x92\xf9\xf7\x83\x71\x2b\x37\xd2\x8d\xc6\x17\xfe\x71\x09\x49\x16\x46\x71\x9e\xbf\x20\xa9\xd3\xc3\xb4\x46\x6a\xa9\x6f\x95\x39\xc3\x94\x65\x03\x61\xe7\x1a\x84\x18\x77\x5b\x06\x65\xab\xf9\x23\x30\x25\xa6\x52\xc0\x19\x59\xd7\x68\x50\x8c\x94\x76\xb8\x77\xf3\xa0\x47\x5a\x53\xe2\x79\xfd\x5a\x60\x83\x4c\x80\x56\xed\xc1\xcb\x65\x26\xfb\xbc\xe0\xcf\x29\x7d\x83\x5e\x23\x13\x2f\xe1\xc3\x74\x42\xbf\xf4\x93\x78\x9e\x7b\xa7\x75\x0b\x1b\xb6\x07\x83\xce\xc8\xf1\xbb\x62\x51\x09\x60\x2f\xcc\xf4\x16\x4d\x00\xde\x70\x3d\xda\x2d\x21\x9a\x7a\xfa\x73\x48\xa9\x1c\x9a\x2d\x6b\x07\xdc\xc3\x28\x00\xe6\x13\xe4\xbd\x31\xc3\x72\xf9\xcc\xa3\x61\x16\x4a\x44\xbf\x7d\x3a\xe4\x6e\x68\xd3\x0c\xe0\xe3\xf9\xfb\x2c\x9a\x2a\x38\x93\x76\x60\xcb\x80\x68\xf5\xe6\x07\xb6\x59\x10\x1a\x94\x76\x60\xfb\xae\xd3\xc6\x81\xdb\x0f\x19\xb1\x4e\xfa\xff\x16\xfb\x2b\xad\xdb\x15\xf7\xd7\xc2\xb9\xf2\x48\x62\x09\xce\xf4\xe8\xb5\xc6\xd4\x01\x04\x96\x7d\x5d\x4f\x57\x92\x97\xc0\x70\x01\xd4\x1a\x7c\x90\x60\x38\x1d\xa5\xd6\x75\x46\x57\xc3\x78\x9e\x5c\x02\x18\xdf\x2e\xa1\x62\xad\xc5\xe0\xdf\x01\x00\x00\xff\xff\x58\x7c\x2d\x36\xa2\x0d\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3496, mode: os.FileMode(420), modTime: time.Unix(1543495615, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3490, mode: os.FileMode(420), modTime: time.Unix(1543934586, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1541606744, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + From c659571a5b92ab053b0ae1ac3df5a428e642a444 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Tue, 4 Dec 2018 17:13:43 +0100 Subject: [PATCH 054/220] use internal error for context (#531) --- coredocument/validator.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coredocument/validator.go b/coredocument/validator.go index d8fd6f3d5..0d6e76214 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -246,10 +246,12 @@ func signaturesValidator(idService identity.Service) documents.Validator { } for _, sig := range cd.Signatures { - if errI := idService.ValidateSignature(sig, cd.SigningRoot); errI != nil { + if erri := idService.ValidateSignature(sig, cd.SigningRoot); erri != nil { err = documents.AppendError( err, - documents.NewError(fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), "signature verification failed")) + documents.NewError( + fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), + fmt.Sprintf("signature verification failed: %v", erri))) } } From 11515ba5ba679a26b46f3682981f6971f9c7ee1a Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 4 Dec 2018 19:16:41 +0100 Subject: [PATCH 055/220] NFT: fixed incorrect tokenID size (#532) * NFT: fixed incorrect tokenID size * better comments --- nft/ethereum_payment_obligation.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 5ffe3a055..fceb980b0 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -235,7 +235,10 @@ type MintRequest struct { // NewMintRequest converts the parameters and returns a struct with needed parameter for minting func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (*MintRequest, error) { - tokenID := utils.ByteSliceToBigInt(utils.RandomSlice(256)) + + // tokenID is uint256 in Solidity (256 bits | max value is 2^256-1) + // tokenID should be random 32 bytes (32 byte = 256 bits) + tokenID := utils.ByteSliceToBigInt(utils.RandomSlice(32)) tokenURI := "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" proofData, err := createProofData(proofs) if err != nil { From 20dcdf8f0d9ada9a9bcf56cd13a9b79d170c2b6b Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 4 Dec 2018 19:28:56 +0100 Subject: [PATCH 056/220] Testworld iteration 2 - cleanup and more golang based env setup (#529) * Added Testworld readme * Load config from file * Testworld cleanup * Add missing build tag * Fix lint issues * Adjust the way smart contract addresses are loaded for other networks * Added kovan faq * Minor update to the readme * Review comments * Clean gitignore --- README.md | 7 +++++ build/configs/default_config.yaml | 7 +++++ testworld/README.md | 21 +++++++++++++ testworld/config.go | 27 ++++++++++++++++ testworld/configs/local.json | 7 +++++ testworld/keystore | 1 - testworld/park.go | 4 +-- testworld/park_test.go | 21 ------------- testworld/start_test.go | 51 +++++++++++++++++++++++++++++++ testworld/util.go | 40 ++++++++++++++++++++++-- testworld/util_test.go.test | 21 ------------- 11 files changed, 159 insertions(+), 48 deletions(-) create mode 100644 testworld/README.md create mode 100644 testworld/config.go create mode 100644 testworld/configs/local.json delete mode 100644 testworld/keystore create mode 100644 testworld/start_test.go delete mode 100644 testworld/util_test.go.test diff --git a/README.md b/README.md index 41e30bd97..ead0b0129 100644 --- a/README.md +++ b/README.md @@ -229,3 +229,10 @@ Generating go bindings and swagger with the following command ```bash make proto-all ``` + +## Kovan FAQ + +- With infura you get an error - "This request is not supported because your node is running with state pruning. Run with --pruning=archive.", + what to do? Run a local parity node with kovan eg: with `parity --chain=kovan --port=30304 --warp --warp-barrier 5680000 --no-ancient-blocks --no-serve-light --max-peers 250 --snapshot-peers 50 --min-peers 50 --mode active --tracing off --pruning=archive --db-compaction ssd --cache-size 4096 --jsonrpc-hosts all --jsonrpc-interface all` +- With local parity node you get an error - "Blocked connection to WebSockets server from untrusted origin: .." + what to do? Run the parity node with `--unsafe-expose` flag diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 295650261..44692806e 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -33,6 +33,13 @@ networks: paymentObligation: "0xdb0581A9328664855328AdDb0E251184640f9e5D" bernalheights: + ### + # Kovan FAQ + # - With infura you get an error - "This request is not supported because your node is running with state pruning. Run with --pruning=archive.", + # what to do? Run a local parity node with kovan eg: with `parity --chain=kovan --port=30304 --warp --warp-barrier 5680000 --no-ancient-blocks --no-serve-light --max-peers 250 --snapshot-peers 50 --min-peers 50 --mode active --tracing off --pruning=archive --db-compaction ssd --cache-size 4096 --jsonrpc-hosts all --jsonrpc-interface all` + # - With local parity node you get an error - "Blocked connection to WebSockets server from untrusted origin: .." + # what to do? Run the parity node with `--unsafe-expose` flag + ### # Numeric ID of the Centrifuge network id: 52 # Bootstrap list of nodes that Centrifuge provides to the bernalheights testnet diff --git a/testworld/README.md b/testworld/README.md new file mode 100644 index 000000000..b94174fce --- /dev/null +++ b/testworld/README.md @@ -0,0 +1,21 @@ +## Welcome to Testworld + +`"CHAOS TAKES CONTROL. WELCOME TO THE NEW WORLD. WELCOME TO TESTWORLD"` + +Testworld(loosely analogous to [Westworld](https://medium.com/@naveen101/westworld-an-introduction-cc7d29bfbe84) ;) is a simulation and test environment for centrifuge p2p network. +Here you can create, run and test nodes with various behaviours to observe how they would behave and debug any problems encountered. + +### Tutorial + +- All hosts(p2p nodes) in the Testworld are created and maintained during simulation by drFord(`park.go#hostManager`). He also ensures that the hosts and tests are properly cleaned up after each simulation run. +- Bernard(`hostManager.bernard`) is a special host that serves as the libp2p bootnode for the test network. +- `hostConfig` serves as the starting point for you to define new hosts. Please check whether an existing host can be reused for your scenario before adding new ones. +- At the start of the each test run a test config is loaded for the required Ethereum network(eg: Rinkeby or local). The host configs are defined based on this. +- The test initialisation also ensures that geth is running in the background and required smart contracts are migrated for the network. +- Refer `park_test.go` for a simple starting point to define your own simulations/tests. +- Each test scenario must be defined in a `testworld/_test.go` file and the build tag `// +build testworld` must be included at the top. +- Plus points if you write a test with a scenario that matches a scene in Westworld with node names matching the characters ;) + + + + diff --git a/testworld/config.go b/testworld/config.go new file mode 100644 index 000000000..40d5d50d1 --- /dev/null +++ b/testworld/config.go @@ -0,0 +1,27 @@ +package testworld + +import ( + "encoding/json" + "fmt" + "os" +) + +type testConfig struct { + EthNodeURL string `json:"ethNodeURL"` + AccountKeyPath string `json:"accountKeyPath"` + AccountPassword string `json:"accountPassword"` + Network string `json:"network"` + TxPoolAccess bool `json:"txPoolAccess"` +} + +func loadConfig(file string) (testConfig, error) { + var config testConfig + configFile, err := os.Open(file) + if err != nil { + fmt.Println(err.Error()) + } + defer configFile.Close() + jsonParser := json.NewDecoder(configFile) + jsonParser.Decode(&config) + return config, nil +} diff --git a/testworld/configs/local.json b/testworld/configs/local.json new file mode 100644 index 000000000..35f0215e9 --- /dev/null +++ b/testworld/configs/local.json @@ -0,0 +1,7 @@ +{ + "ethNodeURL": "ws://127.0.0.1:9546", + "accountKeyPath": "../build/scripts/test-dependencies/test-ethereum/migrateAccount.json", + "accountPassword": "", + "network" : "testing", + "txPoolAccess": true +} \ No newline at end of file diff --git a/testworld/keystore b/testworld/keystore deleted file mode 100644 index 9633d521f..000000000 --- a/testworld/keystore +++ /dev/null @@ -1 +0,0 @@ -{"address":"89b0a86583c4444acfd71b463e0d3c55ae1412a5","crypto":{"cipher":"aes-128-ctr","ciphertext":"c779f8379d770d92cfc1ddd4a8f31d5a0adc8f2a0b2a1401370d3630f38c0c8a","cipherparams":{"iv":"36c168e73bf980fe75b0727f890a71ad"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"de1be16e3c981944d1eca2b8b27e4e6e0b5bfb43be0376a5d8889fa679a28122"},"mac":"cc128b815555ba1ead7cae9060e8842afca8356d06455bd9a5752ba6fcc092ef"},"id":"45e060a6-d2ae-43b8-922f-44829499d37d","version":3} \ No newline at end of file diff --git a/testworld/park.go b/testworld/park.go index 667542d4a..59369181f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -24,7 +24,7 @@ import ( var log = logging.Logger("host") -var hostconfig = []struct { +var hostConfig = []struct { name string apiPort, p2pPort int64 }{ @@ -89,7 +89,7 @@ func (r *hostManager) init() error { } // start hosts - for _, h := range hostconfig { + for _, h := range hostConfig { r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, []string{bootnode}) err = r.niceHosts[h.name].init() if err != nil { diff --git a/testworld/park_test.go b/testworld/park_test.go index 8fa152aab..369f6bc86 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -6,29 +6,8 @@ import ( "testing" "fmt" - "os" ) -// TODO remember to cleanup config files generated - -var doctorFord *hostManager - -func TestMain(m *testing.M) { - // TODO start POA geth here - //runSmartContractMigrations() - contractAddresses := getSmartContractAddresses() - doctorFord = newHostManager("ws://127.0.0.1:9546", - "keystore", "", "testing", true, contractAddresses) - err := doctorFord.init() - if err != nil { - panic(err) - } - fmt.Printf("contract addresses %+v\n", contractAddresses) - result := m.Run() - doctorFord.stop() - os.Exit(result) -} - func TestHost_Happy(t *testing.T) { alice := doctorFord.getHost("Alice") bob := doctorFord.getHost("Bob") diff --git a/testworld/start_test.go b/testworld/start_test.go new file mode 100644 index 000000000..a1316e8bb --- /dev/null +++ b/testworld/start_test.go @@ -0,0 +1,51 @@ +// This is the starting point for all Testworld tests +// +build testworld + +package testworld + +import ( + "fmt" + "os" + "testing" + + "github.com/centrifuge/go-centrifuge/config" +) + +var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 + +// Adjust these based on local testing requirments, please revert for CI server +var configFile = "configs/local.json" +var runPOAGeth = !isRunningOnCI + +// make this false if you want to make the tests run faster locally, but revert before committing to repo +var runMigrations = !isRunningOnCI + +// doctorFord manages the hosts +var doctorFord *hostManager + +func TestMain(m *testing.M) { + c, err := loadConfig(configFile) + if err != nil { + panic(err) + } + if runPOAGeth { + // NOTE that we don't bring down geth automatically right now because this must only be used for local testing purposes + startPOAGeth() + } + if runMigrations { + runSmartContractMigrations() + } + var contractAddresses *config.SmartContractAddresses + if c.Network == "testing" { + contractAddresses = getSmartContractAddresses() + } + doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, c.TxPoolAccess, contractAddresses) + err = doctorFord.init() + if err != nil { + panic(err) + } + fmt.Printf("contract addresses %+v\n", contractAddresses) + result := m.Run() + doctorFord.stop() + os.Exit(result) +} diff --git a/testworld/util.go b/testworld/util.go index 9fb2898c4..ea2f30d03 100644 --- a/testworld/util.go +++ b/testworld/util.go @@ -8,10 +8,27 @@ import ( "os/exec" "path" + "fmt" + "github.com/centrifuge/go-centrifuge/config" "github.com/savaki/jq" ) +// startPOAGeth runs the proof of authority geth for tests +func startPOAGeth() { + // don't run if its already running + if IsPOAGethRunning() { + return + } + projDir := getProjectDir() + gethRunScript := path.Join(projDir, "build", "scripts", "docker", "run.sh") + o, err := exec.Command(gethRunScript, "dev").Output() + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s", string(o)) +} + // runSmartContractMigrations migrates smart contracts to localgeth func runSmartContractMigrations() { projDir := getProjectDir() @@ -24,9 +41,7 @@ func runSmartContractMigrations() { // getSmartContractAddresses finds migrated smart contract addresses for localgeth func getSmartContractAddresses() *config.SmartContractAddresses { - projDir := getProjectDir() - deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") - dat, err := ioutil.ReadFile(deployJSONFile) + dat, err := findContractDeployJSON() if err != nil { panic(err) } @@ -42,6 +57,16 @@ func getSmartContractAddresses() *config.SmartContractAddresses { } } +func findContractDeployJSON() ([]byte, error) { + projDir := getProjectDir() + deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + dat, err := ioutil.ReadFile(deployJSONFile) + if err != nil { + return nil, err + } + return dat, nil +} + func getOpAddr(addrOp jq.Op, dat []byte) string { addr, err := addrOp.Apply(dat) if err != nil { @@ -72,3 +97,12 @@ func getProjectDir() string { projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") return projDir } + +func IsPOAGethRunning() bool { + cmd := "docker ps -a --filter \"name=geth-node\" --filter \"status=running\" --quiet" + o, err := exec.Command("/bin/sh", "-c", cmd).Output() + if err != nil { + panic(err) + } + return len(o) != 0 +} diff --git a/testworld/util_test.go.test b/testworld/util_test.go.test deleted file mode 100644 index 314c290d7..000000000 --- a/testworld/util_test.go.test +++ /dev/null @@ -1,21 +0,0 @@ -// These aren't proper tests, just for checking if the util functions work - -package tests - -import ( - "testing" - "fmt" - ) - -func TestRunMigrations(t *testing.T) { - runSmartContractMigrations() -} - -func TestGetSmartContractAddresses(t *testing.T) { - //runSmartContractMigrations() - c := getSmartContractAddresses() - if c == nil { - t.Error("Failed") - } - fmt.Printf("%+v\n", c) -} \ No newline at end of file From b0cf886be1e2a232c06643e8b097515975e8d251 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 5 Dec 2018 10:03:13 +0100 Subject: [PATCH 057/220] Fixing unnecessary for loops that I have written around selects (#533) * Fix unnecessary for loops that I have written around selects * Remove resolved TODO --- api/server.go | 43 ++++++++++++++++++++----------------------- node/bootstrapper.go | 23 +++++++++++------------ node/node.go | 38 +++++++++++++++++++------------------- p2p/server.go | 26 ++++++++++++-------------- resources/data.go | 2 +- testworld/park.go | 22 ++++++++++------------ 6 files changed, 73 insertions(+), 81 deletions(-) diff --git a/api/server.go b/api/server.go index 9c351dc2b..675de006f 100644 --- a/api/server.go +++ b/api/server.go @@ -110,32 +110,29 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha }(startUpErrOut) // listen to context events as well as http server startup errors - for { - select { - case err := <-startUpErrOut: - // this could create an issue if the listeners are blocking. - // We need to only propagate the error if its an error other than a server closed - if err != nil && err.Error() != http.ErrServerClosed.Error() { - startupErr <- err - return - } - // most probably a graceful shutdown - log.Info(err) - return - case <-ctx.Done(): - ctxn, _ := context.WithTimeout(context.Background(), 1*time.Second) - // gracefully shutdown the server - // we can only do this because srv is thread safe - log.Info("Shutting down API server") - err := srv.Shutdown(ctxn) - if err != nil { - panic(err) - } - log.Info("API server stopped") + select { + case err := <-startUpErrOut: + // this could create an issue if the listeners are blocking. + // We need to only propagate the error if its an error other than a server closed + if err != nil && err.Error() != http.ErrServerClosed.Error() { + startupErr <- err return } + // most probably a graceful shutdown + log.Info(err) + return + case <-ctx.Done(): + ctxn, _ := context.WithTimeout(context.Background(), 1*time.Second) + // gracefully shutdown the server + // we can only do this because srv is thread safe + log.Info("Shutting down API server") + err := srv.Shutdown(ctxn) + if err != nil { + panic(err) + } + log.Info("API server stopped") + return } - } // grpcHandlerFunc returns an http.Handler that delegates to grpcServer on incoming gRPC diff --git a/node/bootstrapper.go b/node/bootstrapper.go index e953cd55e..37f9059d2 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -30,19 +30,18 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { go n.Start(ctx, feedback) controlC := make(chan os.Signal, 1) signal.Notify(controlC, os.Interrupt) - for { - select { - case err := <-feedback: - cleanUp(c) - panic(err) - case sig := <-controlC: - log.Info("Node shutting down because of ", sig) - canc() - cleanUp(c) - err := <-feedback - return err - } + select { + case err := <-feedback: + cleanUp(c) + panic(err) + case sig := <-controlC: + log.Info("Node shutting down because of ", sig) + canc() + cleanUp(c) + err := <-feedback + return err } + } func cleanUp(c map[string]interface{}) { diff --git a/node/node.go b/node/node.go index 5166a9a10..00fdcdeb2 100644 --- a/node/node.go +++ b/node/node.go @@ -48,24 +48,24 @@ func (n *Node) Start(ctx context.Context, startupErr chan<- error) { for _, s := range n.services { go s.Start(ctxCh, &wg, childErr) } - for { - select { - case errOut := <-childErr: - log.Error("Node received error from child service, stopping all child services", errOut) - // if one of the children fails to start all should stop - cancel() - // send the error upstream - startupErr <- errOut - wg.Wait() - return - case <-ctx.Done(): - log.Info("Node received context.done signal, stopping all child services") - // Note that in this case the children will also receive the done signal via the passed on context - wg.Wait() - log.Info("Node stopped all child services") - // special case to make the caller wait until servers are shutdown - startupErr <- nil - return - } + + select { + case errOut := <-childErr: + log.Error("Node received error from child service, stopping all child services", errOut) + // if one of the children fails to start all should stop + cancel() + // send the error upstream + startupErr <- errOut + wg.Wait() + return + case <-ctx.Done(): + log.Info("Node received context.done signal, stopping all child services") + // Note that in this case the children will also receive the done signal via the passed on context + wg.Wait() + log.Info("Node stopped all child services") + // special case to make the caller wait until servers are shutdown + startupErr <- nil + return } + } diff --git a/p2p/server.go b/p2p/server.go index dc99ecb67..eb9890362 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -83,21 +83,19 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch // Start DHT s.runDHT(ctx, s.host) - - for { - select { - case err := <-serveErr: - log.Infof("GRPC server error: %v", err) - s.protocol.GetGRPCServer().GracefulStop() - log.Info("GRPC server stopped") - return - case <-ctx.Done(): - log.Info("Shutting down GRPC server") - s.protocol.GetGRPCServer().GracefulStop() - log.Info("GRPC server stopped") - return - } + select { + case err := <-serveErr: + log.Infof("GRPC server error: %v", err) + s.protocol.GetGRPCServer().GracefulStop() + log.Info("GRPC server stopped") + return + case <-ctx.Done(): + log.Info("Shutting down GRPC server") + s.protocol.GetGRPCServer().GracefulStop() + log.Info("GRPC server stopped") + return } + } func (s *p2pServer) runDHT(ctx context.Context, h host.Host) error { diff --git a/resources/data.go b/resources/data.go index 23778dfc7..3b182c5d2 100644 --- a/resources/data.go +++ b/resources/data.go @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/testworld/park.go b/testworld/park.go index 59369181f..ef0e36a7f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -121,7 +121,6 @@ func (r *hostManager) stop() { } func (r *hostManager) createHost(name string, apiPort, p2pPort int64, bootstraps []string) *host { - // TODO make configs selectable as settings for different networks, eg Kovan + parity return newHost( name, r.ethNodeUrl, @@ -213,18 +212,17 @@ func (h *host) start(c context.Context) error { go h.node.Start(cancCtx, feedback) controlC := make(chan os.Signal, 1) signal.Notify(controlC, os.Interrupt) - for { - select { - case err := <-feedback: - log.Error(h.name+" encountered error ", err) - return err - case sig := <-controlC: - log.Info(h.name+" shutting down because of ", sig) - canc() - err := <-feedback - return err - } + select { + case err := <-feedback: + log.Error(h.name+" encountered error ", err) + return err + case sig := <-controlC: + log.Info(h.name+" shutting down because of ", sig) + canc() + err := <-feedback + return err } + } func (h *host) createInvoice(e *httpexpect.Expect, inv map[string]interface{}) (*httpexpect.Object, error) { From 5d3ee220cc34b132ec24c3972eba00c1b3202484 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 5 Dec 2018 12:47:20 +0100 Subject: [PATCH 058/220] Add update collaborator test (#535) * Add update collaborator test * Add update collaborator test --- testworld/document_consensus_test.go | 77 ++++++++++++++++++++++++++++ testworld/httputils.go | 16 +++++- testworld/park.go | 4 ++ testworld/park_test.go | 8 ++- utils/log_test.go | 2 + 5 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 testworld/document_consensus_test.go diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go new file mode 100644 index 000000000..74774476d --- /dev/null +++ b/testworld/document_consensus_test.go @@ -0,0 +1,77 @@ +// +build testworld + +package testworld + +import "testing" + +func TestHost_AddExternalCollaborator(t *testing.T) { + alice := doctorFord.getHost("Alice") + bob := doctorFord.getHost("Bob") + charlie := doctorFord.getHost("Charlie") + eAlice := alice.createHttpExpectation(t) + eBob := bob.createHttpExpectation(t) + eCharlie := charlie.createHttpExpectation(t) + + a, err := alice.id() + if err != nil { + t.Error(err) + } + + b, err := bob.id() + if err != nil { + t.Error(err) + } + + c, err := charlie.id() + if err != nil { + t.Error(err) + } + + // Alice shares invoice document with Bob first + res, err := alice.createInvoice(eAlice, map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "GBP", + "net_amount": "40", + }, + "collaborators": []string{b.String()}, + }) + if err != nil { + t.Error(err) + } + docIdentifier := res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + params := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "GBP", + } + getInvoiceAndCheck(eAlice, params) + getInvoiceAndCheck(eBob, params) + + // Bob updates invoice and shares with Charlie as well + res, err = bob.updateInvoice(eBob, docIdentifier, map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "USD", + "net_amount": "40", + }, + "collaborators": []string{a.String(), c.String()}, + }) + if err != nil { + t.Error(err) + } + docIdentifier = res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + params["currency"] = "USD" + getInvoiceAndCheck(eAlice, params) + getInvoiceAndCheck(eBob, params) + getInvoiceAndCheck(eCharlie, params) +} diff --git a/testworld/httputils.go b/testworld/httputils.go index 268813ea8..dc8de8dce 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -27,13 +27,16 @@ func createInsecureClient(t *testing.T, baseURL string) *httpexpect.Expect { return httpexpect.WithConfig(config) } -func getInvoiceAndCheck(e *httpexpect.Expect, docIdentifier string, currency string) *httpexpect.Value { +func getInvoiceAndCheck(e *httpexpect.Expect, params map[string]interface{}) *httpexpect.Value { + docIdentifier := params["document_id"].(string) + objGet := e.GET("/invoice/"+docIdentifier). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). Expect().Status(http.StatusOK).JSON().NotNull() objGet.Path("$.header.document_id").String().Equal(docIdentifier) - objGet.Path("$.data.currency").String().Equal(currency) + objGet.Path("$.data.currency").String().Equal(params["currency"].(string)) + return objGet } @@ -45,3 +48,12 @@ func createInvoice(e *httpexpect.Expect, payload map[string]interface{}) *httpex Expect().Status(http.StatusOK).JSON().Object() return obj } + +func updateInvoice(e *httpexpect.Expect, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { + obj := e.PUT("/invoice/"+docIdentifier). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + WithJSON(payload). + Expect().Status(http.StatusOK).JSON().Object() + return obj +} diff --git a/testworld/park.go b/testworld/park.go index ef0e36a7f..328985497 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -229,6 +229,10 @@ func (h *host) createInvoice(e *httpexpect.Expect, inv map[string]interface{}) ( return createInvoice(e, inv), nil } +func (h *host) updateInvoice(e *httpexpect.Expect, docIdentifier string, inv map[string]interface{}) (*httpexpect.Object, error) { + return updateInvoice(e, docIdentifier, inv), nil +} + func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { return createInsecureClient(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) } diff --git a/testworld/park_test.go b/testworld/park_test.go index 369f6bc86..476d519e0 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -42,7 +42,11 @@ func TestHost_Happy(t *testing.T) { if docIdentifier == "" { t.Error("docIdentifier empty") } - getInvoiceAndCheck(eBob, docIdentifier, "GBP") - getInvoiceAndCheck(eCharlie, docIdentifier, "GBP") + params := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "GBP", + } + getInvoiceAndCheck(eBob, params) + getInvoiceAndCheck(eCharlie, params) fmt.Println("Host test success") } diff --git a/utils/log_test.go b/utils/log_test.go index 2c804484d..1f3f399a6 100644 --- a/utils/log_test.go +++ b/utils/log_test.go @@ -1,3 +1,5 @@ +// +build unit + package utils import ( From e9273501ecff988b70d5db0d35701f58398d8ad7 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 6 Dec 2018 11:19:49 +0100 Subject: [PATCH 059/220] removed defaultRegistry address from service (#536) --- nft/ethereum_payment_obligation.go | 10 ++-------- nft/ethereum_payment_obligation_test.go | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index fceb980b0..a010c1ea6 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -120,14 +120,8 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, return nil, err } - var contract *EthereumPaymentObligationContract - if registryAddress == "" { - defaultRegistry := s.config.GetContractAddress("paymentObligation") - contract, err = s.bindContract(defaultRegistry, s.ethClient) - registryAddress = defaultRegistry.String() - } else { - contract, err = s.bindContract(common.HexToAddress(registryAddress), s.ethClient) - } + contract, err := s.bindContract(common.HexToAddress(registryAddress), s.ethClient) + if err != nil { return nil, err } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 62c0ca426..47162f23a 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -161,7 +161,6 @@ func TestPaymentObligationService(t *testing.T) { ).Return(&types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") - configMock.On("GetContractAddress").Return(common.HexToAddress("0xd0dbc72ae5e71382b3cc9cfdc53f6952a085db6d")) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock }, From 428d0b4f17f601bcacadcf787ade5a5d4a85d8f8 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 6 Dec 2018 12:36:07 +0100 Subject: [PATCH 060/220] update kovan boot nodes (#538) --- build/configs/default_config.yaml | 4 ++-- resources/data.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 44692806e..010aafb8f 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -44,8 +44,8 @@ networks: id: 52 # Bootstrap list of nodes that Centrifuge provides to the bernalheights testnet bootstrapPeers: - - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" - - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" + - "/ip4/104.154.18.51/tcp/38202/ipfs/12D3KooWPs6iaeUuFZNu1GxvsyBTSrTs9vtB6btMAnHFoLjbkzCa" + - "/ip4/104.155.185.237/tcp/38202/ipfs/12D3KooWPCGcwiTjoKWHfBa482UPtaeUxNLwd8zbnB1S7weAZUxZ" # Ethereum network ID - Kovan ethereumNetworkId: 42 # Latest deployed Smart Contracts for the given testnet diff --git a/resources/data.go b/resources/data.go index 3b182c5d2..8a41a817b 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x57\xc9\x72\xdc\x38\x12\xbd\xf3\x2b\x32\xca\x97\x99\x83\x25\x70\x03\xc9\xba\x95\x16\xf7\x62\x59\x23\x95\x64\xab\xa5\x1b\x08\x24\x49\xb4\x58\x00\x0d\x80\xb5\xf4\xd7\x4f\x80\x8b\x2c\xd9\x96\x3a\x62\x26\xe6\x34\x75\x62\x10\x99\x2f\xb7\xf7\xc0\xac\x77\x70\x86\x15\xeb\x5b\x07\x02\xb7\xd8\xea\x6e\x83\xca\x81\x43\xeb\x14\x3a\x60\x35\x93\xca\x3a\x30\x52\x3d\x62\x79\x08\x38\x2a\x67\x64\xd5\xd7\x78\x89\x6e\xa7\xcd\xe3\x12\x4c\x6f\xad\x64\xaa\x91\x6d\x1b\x0c\x60\x52\x21\xb8\x06\x41\x4c\xb8\x6a\xb4\xb4\xe0\x1a\xe6\xe0\xf4\x09\x01\x36\x4c\x2a\xe7\xf1\x83\xd9\x64\x19\x00\xbc\x83\x0b\xcd\x59\x3b\xa4\x20\x55\x0d\x5c\x2b\x67\x18\x77\xc0\x84\x30\x68\x2d\x5a\x50\x88\x02\x9c\x86\x12\xc1\xa2\x83\x9d\x74\x0d\xa0\xda\xc2\x96\x19\xc9\xca\x16\xed\x51\x00\xb3\xbf\x87\x04\x90\x62\x09\x71\x1c\x0f\xcf\xe8\x1a\x34\xd8\x6f\xa6\x0a\x7e\x13\x4b\xc8\xe3\x7c\x3c\x2b\xb5\x76\xd6\x19\xd6\x5d\x21\x1a\x3b\xfa\xbe\x87\xc5\xb1\xec\x92\xe3\x30\xca\x8e\xc8\x11\x39\x0a\x8f\x1d\xef\x8e\xe3\x3c\x22\xd1\xb1\xec\x2a\x7b\x7c\xbd\xb9\xbd\xde\x97\xbb\xc7\xfe\xe1\xfe\xfe\xac\xea\xff\xba\x2d\xf7\xe7\xab\x35\xde\x5e\x9e\x5e\xe8\xbf\x0e\x87\x34\xcd\xb7\xd7\xaa\xfe\xb2\xbd\xfa\xf4\xe7\xc5\xfd\xe3\xe2\x6f\x40\xe3\x19\xf4\x4b\x45\xcf\x2f\xe9\xe6\xf1\xeb\x1d\xfe\x79\xf7\xf1\x2e\xfa\x7a\xd5\x87\xf4\x8f\x4e\xfc\x12\x3f\xfe\xae\xc3\xdb\x78\xd3\xb0\xe6\xea\x24\xbd\xc1\x54\x85\x23\xe8\xdc\xaa\xd5\xdc\xa9\xb1\x00\x5f\x3e\x2a\x27\xdd\xe1\x03\xe3\x4e\x9b\xc3\x12\x16\x8b\xef\x4e\xd6\x58\x4b\xeb\x5e\x1c\x31\xc5\x1b\x6d\xd6\xd8\x69\x2b\xbf\xf3\xea\xd8\xc1\xd3\xe4\x5f\x65\x2b\x6b\xe6\xa4\x56\xc3\xd9\x30\xbc\x4f\x4c\xaa\x9f\x52\x69\x9a\x71\x00\xcf\x19\x33\x26\xf8\x0e\x2e\xfb\x0d\x1a\xc9\xe1\xb7\x33\xd0\xd5\xc0\x9e\x67\x3c\xf9\xe6\x39\x0e\x32\x0d\x27\xaf\x93\x79\x5a\xd0\x4a\xeb\xbc\xa7\xd2\x02\x7f\x24\x5a\x67\xf4\x56\x0e\x07\x7a\xc0\x7e\x96\xc0\x9c\xde\xdf\x4e\x3f\x4e\x8f\xa2\x28\x3d\x8a\x08\x39\x4a\xa2\xef\x19\x10\x46\x67\xf1\x47\xad\xef\x2e\xa4\xe4\xd7\x5f\x76\xb7\xcd\xed\xc9\x3d\xdd\x7f\xe4\x57\xfa\xa2\xa2\xeb\xeb\xfb\xdf\x3f\x74\xbb\x2a\x34\x59\xba\xbb\xd8\x47\x0f\xeb\xb8\x3b\x15\xe1\xe2\x67\xf0\x39\x3d\x8a\x42\xf2\x1a\xfc\xf5\xc3\xa7\x55\xfe\xcb\xd5\xaf\x66\x7b\xfe\x70\x52\xec\xc4\xa3\xfe\xcc\x57\xab\xcd\xe9\xc3\xaf\x5d\x81\x87\xc3\x43\x72\x73\x9e\xd7\x1f\x4c\xdc\xdc\x5e\xfe\xb1\x98\x7a\x74\x3e\xb1\x7d\xee\xa2\x6f\xf1\x7b\x58\x4f\x7a\x7e\x45\x0f\xc9\xe4\x7c\xc1\x7c\x7b\x40\x60\xd7\xea\x03\x0a\xb8\xd9\x30\xe3\xe0\x74\xa2\x99\x85\x4a\x9b\xa1\xa1\xb5\xdc\xa2\x7a\xd1\xca\x1f\xa9\x08\xaf\x72\x91\xec\x0b\x22\xa2\x22\x49\xb3\x10\xb3\x38\x4f\x22\x5a\x64\x8c\xd2\x32\x63\x45\xc1\x48\x21\x04\xe5\x59\x2c\xe2\x94\x8a\x37\x58\x4b\xf6\x05\xa5\x84\x93\xb8\x10\x71\x18\x26\x69\xcc\x2a\x22\xd2\x9c\xa7\x94\xd2\x2c\x8a\x45\xc1\xa3\x8a\x65\x82\x22\x7f\x83\xdf\x64\x9f\x55\x79\x9a\x88\x8a\x15\x39\x09\x23\x91\x55\x2c\x4d\x79\x4e\xe2\xb2\x64\x51\x44\x49\xc9\x05\x62\x52\xa6\x28\xde\x52\x02\xd9\x8b\x92\xa4\x79\xb8\x2a\xe2\x28\xa7\x34\xc9\xd3\x34\x8e\xf2\x95\x38\x2b\xc9\x79\x94\x86\x61\x9e\xd0\x84\x54\x05\xa6\x67\x83\x66\x4a\x34\x8a\xb5\x0d\xca\xba\x71\xf6\x3f\x13\x44\xf4\x5f\x0a\xe2\x45\x0a\xff\xa7\x92\xf8\xa8\xb7\x4c\xbd\x2a\x88\xe8\x7f\xa0\x88\x37\x04\x91\xa7\x65\x1c\x55\x19\x8b\xab\x84\x24\x79\x58\x85\x51\x1c\x27\x24\x09\x69\x46\x78\xce\x4b\x24\x59\x95\x89\xac\xe0\x6f\x0a\x22\x4d\x18\xc6\x59\x5c\x91\x82\x56\xac\x8a\x44\x49\xcb\x9c\x25\x34\x0b\x33\x4e\xca\x22\x47\x5e\x31\x92\xa5\x42\xbc\x29\x88\x24\x49\x2a\x9a\x14\x18\x93\x2c\x49\x22\xcc\x28\xe7\x55\x16\x67\x09\xa5\x98\x46\x55\x48\x49\x51\x16\x79\x44\xc9\xdb\x82\x20\x49\x98\x61\x19\x67\x45\x12\x86\x34\x89\x69\x9e\x90\xf0\x8c\x52\x5a\xe4\x09\x3f\x3f\xcb\x68\x91\xac\x4e\xf8\x49\x19\x2e\x82\xe0\x1d\x78\xaa\xbd\x77\xfa\x7d\x87\x68\x7c\xdb\x2a\x59\xf7\x66\xc0\xb2\x41\x17\x75\xe3\x92\x70\x2b\x37\xa8\x7b\x07\xbb\x06\x15\xe8\x0e\xd5\xb4\x2b\x28\xe4\x83\xa5\xa7\xb6\x07\xb0\x01\xcc\xaf\x27\x97\x25\x2c\x62\x62\x87\x48\xd7\x3d\xf6\xf8\x5d\x88\x61\x84\xcc\x1e\x14\x6f\x8c\x56\xba\xb7\x5e\x2d\x1c\xad\x95\xaa\x0e\xbe\x7a\x87\x31\x81\x71\xd3\xb1\xc3\xb4\x55\xbf\x29\xd1\x78\xbd\x79\xc2\xa0\xb1\xc7\x5c\x2b\xeb\x25\x3c\x69\x6f\xe7\x3f\x35\x25\x02\x6b\x5b\xcd\x99\x43\x01\xcc\x81\x75\xcc\xb8\xbe\x0b\xc0\xfb\xdf\x8d\x8e\x4b\x88\x06\xf4\x0f\x06\xd1\x42\xdf\xc1\xe9\xd5\x67\xe0\x07\xde\xa2\x1d\x4b\x1d\x03\x80\xb4\xb0\x63\x72\x58\x90\x7c\xbe\xb8\x45\xe5\x7c\xa9\xe3\xf1\x1d\x93\x43\xb5\x9f\x6e\x96\x10\xfa\x42\x9f\x28\x6f\x3b\xe4\xb2\x92\xfc\x65\xd1\xc1\x4c\xf9\xb1\xb4\x1b\x6c\xd1\x93\x79\xd7\x48\xde\x3c\xc9\x01\x18\xe7\xba\xf7\x5f\x74\x0d\xbd\xc5\xf9\x5e\xd2\xbe\x09\xd3\x85\x22\x40\xaa\xe1\x25\xef\xad\xd3\x9b\x29\x08\x54\xb2\xc5\x00\xe6\x85\x70\x35\xc2\x5c\xb2\x0d\x2e\x61\xe1\x97\xc0\xc5\xd3\xda\xe7\x93\x99\x81\x9f\xe2\xf2\x56\xfa\x45\xc2\x5f\x65\xf0\x8f\x1d\x82\xc1\xaf\xbd\x34\x08\x3b\x0b\xda\x80\xec\xf8\xb4\x0b\xfa\xd5\xcf\x3f\x72\xe6\x7c\xda\x43\x4b\xfe\xe9\xbb\xab\x05\x7e\x5e\x5f\x2c\xa1\x71\xae\x5b\x1e\x1f\xfb\x11\xb4\x8d\xb6\x6e\x59\xa4\x49\x3a\x0f\x73\xd8\x55\x6b\xe6\x6b\x91\xdc\xa7\x5b\x33\x7b\xe5\x1f\x97\x10\x92\xf9\xf7\x83\x71\x2b\x37\xd2\x8d\xc6\x17\xfe\x71\x09\x49\x16\x46\x71\x9e\xbf\x20\xa9\xd3\xc3\xb4\x46\x6a\xa9\x6f\x95\x39\xc3\x94\x65\x03\x61\xe7\x1a\x84\x18\x77\x5b\x06\x65\xab\xf9\x23\x30\x25\xa6\x52\xc0\x19\x59\xd7\x68\x50\x8c\x94\x76\xb8\x77\xf3\xa0\x47\x5a\x53\xe2\x79\xfd\x5a\x60\x83\x4c\x80\x56\xed\xc1\xcb\x65\x26\xfb\xbc\xe0\xcf\x29\x7d\x83\x5e\x23\x13\x2f\xe1\xc3\x74\x42\xbf\xf4\x93\x78\x9e\x7b\xa7\x75\x0b\x1b\xb6\x07\x83\xce\xc8\xf1\xbb\x62\x51\x09\x60\x2f\xcc\xf4\x16\x4d\x00\xde\x70\x3d\xda\x2d\x21\x9a\x7a\xfa\x73\x48\xa9\x1c\x9a\x2d\x6b\x07\xdc\xc3\x28\x00\xe6\x13\xe4\xbd\x31\xc3\x72\xf9\xcc\xa3\x61\x16\x4a\x44\xbf\x7d\x3a\xe4\x6e\x68\xd3\x0c\xe0\xe3\xf9\xfb\x2c\x9a\x2a\x38\x93\x76\x60\xcb\x80\x68\xf5\xe6\x07\xb6\x59\x10\x1a\x94\x76\x60\xfb\xae\xd3\xc6\x81\xdb\x0f\x19\xb1\x4e\xfa\xff\x16\xfb\x2b\xad\xdb\x15\xf7\xd7\xc2\xb9\xf2\x48\x62\x09\xce\xf4\xe8\xb5\xc6\xd4\x01\x04\x96\x7d\x5d\x4f\x57\x92\x97\xc0\x70\x01\xd4\x1a\x7c\x90\x60\x38\x1d\xa5\xd6\x75\x46\x57\xc3\x78\x9e\x5c\x02\x18\xdf\x2e\xa1\x62\xad\xc5\xe0\xdf\x01\x00\x00\xff\xff\x58\x7c\x2d\x36\xa2\x0d\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xf7\xc6\x71\xbd\xc8\xf1\x8d\x9f\x02\x02\x87\x24\x62\x0a\x60\x00\x50\x4b\x7e\x7d\x07\x20\xe5\xd8\x71\xec\xdb\x4e\xa7\x7e\x31\x05\xe0\x7c\x38\xcb\x77\x3e\x00\x07\x70\x82\x15\xe9\x5b\x03\x0c\xd7\xd8\xca\x6e\x85\xc2\x80\x41\x6d\x04\x1a\x20\x35\xe1\x42\x1b\x50\x5c\x3c\x60\xb9\x9b\x50\x14\x46\xf1\xaa\xaf\xf1\x02\xcd\x46\xaa\x87\x39\xa8\x5e\x6b\x4e\x44\xc3\xdb\x76\xe2\xc0\xb8\x40\x30\x0d\x02\x1b\x71\xc5\xb0\x52\x83\x69\x88\x81\xe3\x47\x04\x58\x11\x2e\x8c\xc5\x9f\xec\x97\xcc\x27\x00\x07\x70\x2e\x29\x69\x9d\x0b\x5c\xd4\x40\xa5\x30\x8a\x50\x03\x84\x31\x85\x5a\xa3\x06\x81\xc8\xc0\x48\x28\x11\x34\x1a\xd8\x70\xd3\x00\x8a\x35\xac\x89\xe2\xa4\x6c\x51\xcf\x26\xb0\xb7\xb7\x90\x00\x9c\xcd\x21\x8a\x22\xf7\x8d\xa6\x41\x85\xfd\x6a\x8c\xe0\x77\x36\x87\x3c\xca\x87\xb9\x52\x4a\xa3\x8d\x22\xdd\x25\xa2\xd2\x83\xad\x07\xd3\x43\xde\xc5\x87\x41\x98\xcd\xfc\x99\x3f\x0b\x0e\x0d\xed\x0e\xa3\x3c\xf4\xc3\x43\xde\x55\xfa\xf0\x6a\xb5\xbc\xda\x96\x9b\x87\xfe\xfe\xf3\xe7\x93\xaa\xff\xbe\x2c\xb7\xa7\x8b\x6b\x5c\x5e\x1c\x9f\xcb\xef\xbb\x5d\x92\xe4\xeb\x2b\x51\x7f\x5a\x5f\x7e\xfc\x7a\xfe\xf9\x61\xfa\x17\xa0\xd1\x1e\xf4\x53\x95\x9e\x5e\xa4\xab\x87\x6f\x77\xf8\xf5\xee\xc3\x5d\xf8\xed\xb2\x0f\xd2\x3f\x3b\xf6\x2e\x7a\xf8\x43\x06\xcb\x68\xd5\x90\xe6\xf2\x28\xb9\xc1\x44\x04\x03\xe8\x3e\x55\x8b\x7d\xa6\x86\x00\x6c\xf8\x28\x0c\x37\xbb\x33\x42\x8d\x54\xbb\x39\x4c\xa7\x3f\xcd\x5c\x63\xcd\xb5\x79\x36\x45\x04\x6d\xa4\xba\xc6\x4e\x6a\xfe\x93\x55\x47\x76\x96\x26\xff\x2a\x5b\x5e\x13\xc3\xa5\x70\x73\xae\x78\x1f\x09\x17\xbf\xa4\xd2\x58\xe3\x09\x3c\x65\xcc\xe0\xe0\x01\x5c\xf4\x2b\x54\x9c\xc2\xef\x27\x20\x2b\xc7\x9e\x27\x3c\xf9\x61\x39\x14\x32\x09\x46\xab\xa3\x7d\xb5\xa0\xe5\xda\x58\x4b\x21\x19\xbe\x24\x5a\xa7\xe4\x9a\xbb\x09\xe9\xb0\x9f\x38\xb0\x77\xef\x2f\xab\x1f\x25\xb3\x30\x4c\x66\xa1\xef\xcf\xe2\xf0\x67\x06\x04\xe1\x49\xf4\x41\xca\xbb\x73\xce\xe9\xd5\xa7\xcd\xb2\x59\x1e\x7d\x4e\xb7\x1f\xe8\xa5\x3c\xaf\xd2\xeb\xab\xcf\x7f\x9c\x75\x9b\x2a\x50\x59\xb2\x39\xdf\x86\xf7\xd7\x51\x77\xcc\x82\xe9\xaf\xe0\xf3\x74\x16\x06\xfe\x6b\xf0\x57\xf7\x1f\x17\xf9\xbb\xcb\xf7\x6a\x7d\x7a\x7f\x54\x6c\xd8\x83\xbc\xa5\x8b\xc5\xea\xf8\xfe\x7d\x57\xe0\x6e\x77\x1f\xdf\x9c\xe6\xf5\x99\x8a\x9a\xe5\xc5\x9f\xd3\x31\x47\xa7\x23\xdb\xf7\x59\xb4\x29\xf6\xe0\x7a\xec\xe7\x57\xfa\x21\x1e\x8d\xcf\x89\x4d\x0f\x30\xec\x5a\xb9\x43\x06\x37\x2b\xa2\x0c\x1c\x8f\x34\xd3\x50\x49\xe5\x12\x5a\xf3\x35\x8a\x67\xa9\x7c\x49\x45\x78\x95\x8b\xfe\xb6\xf0\x59\x58\xc4\x49\x16\x60\x16\xe5\x71\x98\x16\x19\x49\xd3\x32\x23\x45\x41\xfc\x82\xb1\x94\x66\x11\x8b\x92\x94\xbd\xc1\x5a\x7f\x5b\xa4\xa9\x4f\xfd\xa8\x60\x51\x10\xc4\x49\x44\x2a\x9f\x25\x39\x4d\xd2\x34\xcd\xc2\x88\x15\x34\xac\x48\xc6\x52\xa4\x6f\xf0\xdb\xdf\x66\x55\x9e\xc4\xac\x22\x45\xee\x07\x21\xcb\x2a\x92\x24\x34\xf7\xa3\xb2\x24\x61\x98\xfa\x25\x65\x88\x71\x99\x20\x7b\xab\x13\xfc\x2d\x2b\xfd\x24\x0f\x16\x45\x14\xe6\x69\x1a\xe7\x49\x12\x85\xf9\x82\x9d\x94\xfe\x69\x98\x04\x41\x1e\xa7\xb1\x5f\x15\x98\x9c\xb8\x9e\x29\x51\x09\xd2\x36\xc8\xeb\xc6\x8c\xa4\x3b\x38\x38\x18\x2b\xf0\x41\xae\x89\x80\xb3\xc5\xd5\xf8\xdb\x83\x3b\xab\x76\x5c\x54\xbd\x22\xb0\x93\x3d\xd4\x56\xa6\x05\xa0\x52\x52\x59\x3a\x2d\x1b\xae\x41\xe1\xb7\xde\x56\x8e\x6b\x10\xd2\x80\xee\xbb\x4e\x2a\x83\x0c\x4a\xa4\xa4\xd7\x68\x2d\x95\xeb\x16\xbb\x44\xf5\x42\x58\xa9\x75\x42\xaa\x0d\x31\xb6\x65\x7a\x3b\x34\x83\xeb\x5e\x0c\xe3\x9e\x37\x8e\xfd\x46\x14\x6d\xf8\x1a\x67\xd3\x7f\x8c\x4e\x01\x6c\x6c\xc7\x19\x09\x4c\xfe\xd3\x59\x10\x68\x9d\x88\x77\x44\x71\xb3\x1b\x36\x72\x28\x0f\x2e\x1e\xac\xe7\xc3\xcf\x2f\xe3\x02\xcf\xa3\x0d\xe1\xe2\xb7\x61\xda\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xba\xf1\x9f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x25\x7d\xd0\xc3\x98\x46\xb5\x46\xaf\xb5\x49\x05\xcf\x5b\x91\xad\xd7\xd9\xa6\x86\x30\xb1\x46\x5a\x90\x4e\x37\xd2\x8c\x83\x6e\x6c\xc5\xc5\xb3\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x25\xb3\x4d\x91\xac\xaa\x97\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb3\xeb\xa5\x00\xad\x99\x0d\x89\xd0\x06\x3d\xcd\xbf\x23\xc4\x7e\x91\x82\xe7\x7d\xd5\x52\xa8\x8e\x7a\x8d\xd4\x46\x03\x69\xdb\x27\x63\x5c\x18\x54\x15\xa1\x68\xc7\xbf\x3c\x2f\xf7\xcb\x64\xfe\xaa\xf2\x47\x36\x7c\x64\xb6\xf7\x04\x0e\x8e\x18\x09\x77\x58\xde\xd8\x71\xa3\xc1\xe5\x44\x41\xa5\xe4\x0a\x7a\x61\x54\xaf\x2d\x25\xa4\xe2\x35\x17\x73\x98\xcd\xa6\xaf\xd6\xd3\x36\xf9\x8b\x5a\x7e\xf1\xbc\x5e\x68\x52\xa1\x87\xdb\x4e\x6a\xfc\x02\x55\x4b\xea\x9f\x08\xfc\xdf\x29\x7b\xf8\x3f\x2a\xfb\xb3\x5e\xfa\x8f\xb5\x3d\xf0\xe3\x59\x90\xc4\xb3\x20\x9f\x25\x2f\x4e\xf7\xbd\xf8\x5e\xea\x94\x13\xbc\xed\xcf\xee\x2f\xfa\xe0\xdd\x76\xad\x77\x47\xcb\x1b\xb5\xd4\xc5\xda\x1c\xa5\xa5\xf9\xb8\x10\xef\xcf\xe4\xf9\xd7\xf2\xe1\xfb\x31\x99\xfe\x02\x3e\x99\x05\x79\x32\x0b\xa3\xec\xd5\x0d\x8e\xdf\xd1\x0d\x5f\x7e\x95\x1f\xee\xde\x57\x47\x24\xce\xc3\xdb\x4b\x43\xf0\x76\x7b\x71\xbe\x61\xf9\xf7\x52\x1c\x05\x37\xd9\x06\x17\xf7\xb7\xdb\xfb\xb7\xd5\xdd\x89\xc6\xab\xda\x1e\xfe\x1f\xc4\xfd\x0d\x6d\xcf\x93\x32\x0a\xab\x8c\x44\x55\xec\xc7\x79\x50\x05\x61\x14\xc5\x7e\x1c\xa4\x99\x4f\x73\x5a\xa2\x9f\x55\x19\xcb\x0a\xfa\xa6\xb6\x27\x31\xc1\x28\x8b\x2a\xbf\x48\x2b\x52\x85\xac\x4c\xcb\x9c\xc4\x69\x16\x64\xd4\x2f\x8b\x1c\x69\x45\xfc\x2c\x61\xec\x4d\x6d\x8f\xe3\xb8\x4a\xe3\x02\x23\x3f\x8b\xe3\x10\xb3\x94\xd2\x2a\x8b\xb2\x38\x4d\x31\x09\xab\x20\xf5\x8b\xb2\xc8\xc3\xd4\x7f\x5b\xdb\xfd\x38\xc8\xb0\x8c\xb2\x22\x0e\x82\x34\x8e\xd2\x3c\xf6\x83\x93\x34\x4d\x8b\x3c\xa6\xa7\x27\x59\x5a\xc4\x8b\x23\x7a\x54\x06\xd3\xc9\xe4\x00\x2c\xd9\x3c\x23\x9d\xae\xd8\xb4\x55\xbc\xee\x95\xc3\xd2\x93\x2e\xec\x86\xfb\xee\x92\xaf\x50\xf6\x06\x36\x0d\x0a\x90\x1d\x8a\xf1\xda\x3b\x36\xb1\x23\xb7\x13\xa6\x09\xec\x87\x47\x93\x39\x4c\x23\x5f\xbb\x9d\xae\x7a\xec\xf1\xa7\x2d\x5c\x09\x89\xde\x09\xda\x28\x29\x64\xaf\x6d\xbf\x50\xd4\x9a\x8b\x7a\xf2\xcd\x1a\x0c\x0e\x0c\x97\x76\xed\xaa\x2d\xfa\x55\x89\xca\x76\x9c\x25\x0c\x2a\x7d\x48\xa5\xd0\xb6\x89\xc7\xee\xdb\xd8\x5b\x53\xe9\x54\x4a\x52\x62\x05\x84\x18\x7b\x68\x28\xd3\x77\x13\xb0\xf6\x77\x83\xe1\x1c\x42\x87\x7e\xa6\x10\x35\xf4\x1d\x1c\x5f\xde\x02\xdd\xd1\x16\xf5\x10\xea\xb0\x81\x3d\x80\x36\x84\xbb\xbb\xbe\xf5\x17\xd7\x28\x8c\x0d\x75\x98\xbe\x23\xdc\x45\xfb\xf1\x66\x0e\x81\x0d\xf4\x91\xf2\xba\x43\xca\x2b\x4e\x9f\x07\x3d\xd9\x53\x7e\x08\xed\x06\x5b\xb4\x64\xde\x34\x9c\x36\x8f\xed\x00\x84\x52\xd9\x0b\x27\x71\xf6\x34\x1c\x95\x49\xda\x24\x8c\x92\xc2\x80\x0f\xb2\x47\x7b\x6d\xe4\x6a\xdc\x04\x2a\xde\xe2\x04\xf6\x6f\x9b\xc5\x00\x73\x41\x56\x38\x87\xa9\x7d\xcf\x4c\x1f\x5f\x30\x4e\x7f\x47\xe0\xc7\x7d\x69\x6b\x0f\xaa\x41\x43\xff\xb6\x41\x77\x4e\x73\x85\xb0\xd1\x20\x15\xf0\x8e\x8e\xcf\x1a\xfb\x8a\xb1\x9f\x94\x18\xeb\xb6\x4b\xc9\xdf\x6d\x76\x25\xc3\xdb\xeb\xf3\x39\x34\xc6\x74\xf3\xc3\x43\x77\x30\xd8\xd3\x64\x5e\x24\x71\xb2\x2f\xa6\x7b\x76\xd5\xc4\xc6\xc2\xa9\x75\xb7\x26\xfa\xd2\x7e\xce\x21\xf0\xf7\x7f\x2f\x16\xb7\x7c\xc5\xcd\xb0\xf8\xdc\x7e\xce\x21\xce\x82\x30\xca\xf3\x67\x24\x35\xd2\x55\x6b\xa0\x96\xf8\x11\x99\x51\x44\x68\xf2\x78\xea\xd8\x18\x18\x1b\x9e\x69\x04\xdc\xc1\x0c\x44\xb0\x31\x14\x30\x8a\xd7\x35\x2a\x64\x03\xa5\x0d\x6e\xcd\xbe\xd0\x03\xad\x53\xdf\xf2\xfa\xb5\x8d\x15\x12\x06\x52\xb4\x3b\xdb\x2e\x7b\xb2\xef\xdf\xaa\x7b\x97\x7e\x40\x5f\x23\x61\xcf\xe1\x83\x64\x44\xbf\xb0\x95\x78\xea\x7b\x27\x65\x0b\x2b\xb2\x05\x85\x46\xf1\xe1\x64\xd1\x28\x18\x90\x67\xcb\xe4\x1a\xd5\x04\xec\xc2\xeb\x61\xdd\x1c\xc2\x31\xa7\xbf\x86\x74\xc7\xfb\x9a\xb4\x0e\x77\x37\x34\x00\xb1\x0e\xd2\x5e\x29\xf7\x4e\x7a\x62\xd1\x10\x0d\x25\xa2\x7d\x48\x19\xa4\xc6\xa5\x69\x0f\x60\xf7\xb3\x7a\x16\x8e\x11\x9c\x70\xed\xd8\xe2\x10\xb5\x5c\xbd\x60\x9b\x06\x26\x9f\xde\x02\xc1\x6c\x9d\x47\xa4\xe3\xf6\x99\xbc\xbd\x94\xb2\x5d\x50\x2b\x0b\xa7\xc2\x22\xb1\x39\x18\xd5\xa3\xed\x35\x22\x76\xc0\xb0\xec\xeb\x7a\x94\x24\xdb\x02\x4e\x00\x6a\x09\x76\x93\x89\x9b\x1d\x5a\xad\xeb\x94\xac\x5c\x79\x1e\x4d\x26\x30\x8c\xce\xa1\x22\xad\xc6\xc9\xbf\x03\x00\x00\xff\xff\x6c\x54\x71\x54\x6d\x10\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 3490, mode: os.FileMode(420), modTime: time.Unix(1543934586, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4205, mode: os.FileMode(420), modTime: time.Unix(1544092466, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1541606744, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + From d4a8c1706c8f35152bece1633b9133852935ffe3 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 6 Dec 2018 14:07:57 +0100 Subject: [PATCH 061/220] remove envs from yml (#540) --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 289afb818..2a9791273 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,6 @@ services: env: matrix: - DEPCACHEDIR=/tmp/depcache IMAGE_NAME=centrifugeio/go-centrifuge PROTOTOOL_VERSION=0.4.0 PROTOTOOL_BIN=~/bin/0.4.0/prototool - global: - - secure: XDK6tU10HRQOLqYBquB69KJ0ZcA/avqWZ3o73ET+RurApvlYqEY1YA1FtPs2+vY9BlvvzN0c7v9RoxIqwYsYl7m/qoZHBcl4gpjCcFJtjPqpudkrigFZmb5voSelqKXdh4UmwQa4hQPq4W002eju82FHXEtdFSThNi1jAPMitLEmFhG22JoKda2M810HbPqrBctye6RD/2ZSsSLMZQgeTDkwvU5FFDzO2qfKQqtYrMqfpvcqTsfqr6vpUyZyaOVsr2AzLtu3qLB9UBSHw98yOoSsTpZ+rg6d2X5PWn8ndOKSyswelHoPCdNjTwPOxRie+P7tEClr90LtdWrtXbQDxp0j6dutP0FQALv38sSioazag0sDePl6yjGvSH9s8UgvnpSIHUZsS+ZxntVEOSNnxzP+wFwP05XEpzd5XL+dn9CjH8PtXOX+lv+KHc8NGHeKdnw/eiwD5eikW13V9u6Fm2ZyAOeLSqXb+m0Hfj0+OirUnisZII1dO2AAWbigop7tk0xn/UPQQaT/TEREdhM9cSXhQOyHB4UoHac7zipbDKtBveJPbaGNe9iRqPaLViPO9XwUAHkOGrNv8gl+WaNzrmiOFgWpVg7KUUxzKu5n2QyuNZb5H27+u4RpUbv6qTQiU0VhSW9F2xcwgHLVoJGSDVwyOM1XuTidX/aTQ/G0pZQ= - - secure: Id6nD7LQ//FySnKgFAae4Gi60JEnpXw1lWARfcJbYOVIH7usbyKm+lHyyCb9tsj5eJmdHovpzd4ZO52arMdDbvzGmnBHbWMXhjJe7oGJNgJ4ifI0GTSCCHOshox5kzhom3OekjOs5QZgcg/DN0Aflt5JkJY+PQy0KGqSo449uvB86QMesrDI2FVZlCL/a81HaSRIB9UhWfgyQrpEY6CqmIQtWY4MTHPnb1YegG04OKrUVdmD0iPbN3diDciiS5xCXi4JyiP+hSbUbnAakEr071CptRaGiJXkCkMK28AUvn5ox6xffDNeA2snDfE36EUUZYLkcs89fUKAp8Quu4i18HTFCtfC8o82mt2nAu+ZNEuU+SJzK4mKUwdSwt/kDMMxdHZ5ss7aoTlreHGDehts12OGBMsp7w/cYqKnnaLf8uHFfcasOD+51SDGyo5jzA5QDM6lrt28Cptb/3NwH+xmFTY85YxE9tnTAKkBd/NRPlB8Q1HNzLWu4QGC4u0wnWeM0IvWhtEFguEb8E9MtcvKHHC5iVyyxJUavJ9s+41Xg4x0KF2Z0fmmsZTu1WYrcFLhWtBnkUGeS70NfQpGZ5UkuL9yJN3SvVApdku9QMbw6Bn/ep05V5JnFSOGlHx5HztyMpkq/CJRcuzq1lxnoUWhXVulhwBrDelvsgO8pBVALJw= checkout: post: From a29a27c062313bb7a67dfcd9815d13536447f73e Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 6 Dec 2018 17:49:11 +0100 Subject: [PATCH 062/220] Generic db implementation (#534) Fixes #503 Note: This is just the implementation. Further PRs should handle integration to Invoice and PO --- documents/invoice/repository.go | 2 +- documents/invoice/repository_test.go | 4 +- documents/invoice/service.go | 4 +- documents/purchaseorder/repository.go | 2 +- documents/purchaseorder/repository_test.go | 4 +- documents/purchaseorder/service.go | 4 +- documents/repository.go | 188 +++++++++++++++++++-- documents/repository_test.go | 110 ++++++++++++ documents/test_bootstrapper.go | 2 +- p2p/handler_test.go | 2 +- 10 files changed, 294 insertions(+), 28 deletions(-) create mode 100644 documents/repository_test.go diff --git a/documents/invoice/repository.go b/documents/invoice/repository.go index 00d997c62..97c0ec9ca 100644 --- a/documents/invoice/repository.go +++ b/documents/invoice/repository.go @@ -11,7 +11,7 @@ type repository struct { } // getRepository returns the implemented documents.legacyRepo for invoices -func getRepository(ldb *leveldb.DB) documents.Repository { +func getRepository(ldb *leveldb.DB) documents.LegacyRepository { return &repository{ documents.LevelDBRepository{ KeyPrefix: "invoice", diff --git a/documents/invoice/repository_test.go b/documents/invoice/repository_test.go index a961a3c62..a71d059b7 100644 --- a/documents/invoice/repository_test.go +++ b/documents/invoice/repository_test.go @@ -53,9 +53,9 @@ func TestRepository_getRepository(t *testing.T) { assert.Equal(t, "invoice", r.(*repository).KeyPrefix) } -var testRepoGlobal documents.Repository +var testRepoGlobal documents.LegacyRepository -func testRepo() documents.Repository { +func testRepo() documents.LegacyRepository { if testRepoGlobal == nil { ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) if err != nil { diff --git a/documents/invoice/service.go b/documents/invoice/service.go index bd6561ad4..dd2f5d481 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -53,7 +53,7 @@ type Service interface { // service implements Service and handles all invoice related persistence and validations // service always returns errors of type `centerrors` with proper error code type service struct { - repo documents.Repository + repo documents.LegacyRepository coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -61,7 +61,7 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Config, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { +func DefaultService(config config.Config, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config.(notification.Config)), anchorRepository: anchorRepository, identityService: identityService} } diff --git a/documents/purchaseorder/repository.go b/documents/purchaseorder/repository.go index 1d01a624a..b05faad69 100644 --- a/documents/purchaseorder/repository.go +++ b/documents/purchaseorder/repository.go @@ -11,7 +11,7 @@ type repository struct { } // getRepository returns the implemented documents.legacyRepo for purchase orders -func getRepository(ldb *leveldb.DB) documents.Repository { +func getRepository(ldb *leveldb.DB) documents.LegacyRepository { return &repository{ documents.LevelDBRepository{ KeyPrefix: "purchaseorder", diff --git a/documents/purchaseorder/repository_test.go b/documents/purchaseorder/repository_test.go index 3cd3e1db2..c4e5043e3 100644 --- a/documents/purchaseorder/repository_test.go +++ b/documents/purchaseorder/repository_test.go @@ -16,9 +16,9 @@ func TestRepository_getRepository(t *testing.T) { assert.Equal(t, "purchaseorder", r.(*repository).KeyPrefix) } -var testRepoGlobal documents.Repository +var testRepoGlobal documents.LegacyRepository -func testRepo() documents.Repository { +func testRepo() documents.LegacyRepository { if testRepoGlobal == nil { ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) if err != nil { diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index a67859d1a..78bff8f85 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -53,7 +53,7 @@ type Service interface { // service implements Service and handles all purchase order related persistence and validations // service always returns errors of type `centerrors` with proper error code type service struct { - repo documents.Repository + repo documents.LegacyRepository coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -61,7 +61,7 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Config, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { +func DefaultService(config config.Config, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } diff --git a/documents/repository.go b/documents/repository.go index a27372b57..d0c73d625 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -1,39 +1,195 @@ package documents -// Loader interface can be implemented by any type that handles document retrieval -type Loader interface { +import ( + "encoding/json" + "fmt" + "reflect" + "sync" + + "github.com/syndtr/goleveldb/leveldb" +) + +// LegacyRepository should be implemented by any type that wants to store a document in key-value storage. +// Deprecated: Use the single collection DB. +type LegacyRepository interface { // GetKey will prepare the the identifier key from ID GetKey(id []byte) (key []byte) // GetByID finds the doc with identifier and marshals it into message LoadByID(id []byte, model Model) error -} -// Checker interface can be implemented by any type that handles if document exists -type Checker interface { // Exists checks for document existence // True if exists else false Exists(id []byte) bool -} -// Creator interface can be implemented by any type that handles document creation -type Creator interface { // Create stores the initial document // If document exist, it errors out Create(id []byte, model Model) error -} -// Updater interface can be implemented by any type that handles document update -type Updater interface { // Update updates the already stored document // errors out when document is missing Update(id []byte, model Model) error } -// Repository should be implemented by any type that wants to store a document in key-value storage +// Repository defines the required methods for a document repository. +// Can be implemented by any type that stores the documents. Ex: levelDB, sql etc... type Repository interface { - Checker - Loader - Creator - Updater + // Exists checks if the id, owned by tenantID, exists in DB + Exists(tenantID, id []byte) bool + + // Get returns the Model associated with ID, owned by tenantID + Get(tenantID, id []byte) (Model, error) + + // Create creates the model if not present in the DB. + // should error out if the document exists. + Create(tenantID, id []byte, model Model) error + + // Update strictly updates the model. + // Will error out when the model doesn't exist in the DB. + Update(tenantID, id []byte, model Model) error + + // Register registers the model so that the DB can return the document without knowing the type + Register(model Model) +} + +// levelDBRepo implements Repository using LevelDB as storage layer +type levelDBRepo struct { + db *leveldb.DB + models map[string]reflect.Type + mu sync.RWMutex // to protect the models +} + +// value is an internal representation of how levelDb stores the model. +type value struct { + Type string `json:"type"` + Data json.RawMessage `json:"data"` +} + +// NewLevelDBRepository returns levelDb implementation of Repository +func NewLevelDBRepository(db *leveldb.DB) Repository { + return &levelDBRepo{ + db: db, + models: make(map[string]reflect.Type), + } +} + +// getKey returns tenantID+id +func getKey(tenantID, id []byte) []byte { + return append(tenantID, id...) +} + +// Exists returns true if the id, owned by tenantID, exists. +func (l *levelDBRepo) Exists(tenantID, id []byte) bool { + key := getKey(tenantID, id) + res, err := l.db.Has(key, nil) + // TODO check this + if err != nil { + return false + } + + return res +} + +// getModel returns a new instance of the type mt. +func (l *levelDBRepo) getModel(mt string) (Model, error) { + tp, ok := l.models[mt] + if !ok { + return nil, fmt.Errorf("type %s not registered", mt) + } + + return reflect.New(tp).Interface().(Model), nil +} + +// Get returns the model associated with ID, owned by tenantID. +func (l *levelDBRepo) Get(tenantID, id []byte) (Model, error) { + key := getKey(tenantID, id) + data, err := l.db.Get(key, nil) + if err != nil { + return nil, fmt.Errorf("document missing: %v", err) + } + + v := new(value) + err = json.Unmarshal(data, v) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal value: %v", err) + } + + l.mu.RLock() + defer l.mu.RUnlock() + nm, err := l.getModel(v.Type) + if err != nil { + return nil, fmt.Errorf("failed to get model type: %v", err) + } + + err = nm.FromJSON([]byte(v.Data)) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal to model: %v", err) + } + + return nm, nil +} + +// getTypeIndirect returns the type of the model without pointers. +func getTypeIndirect(tp reflect.Type) reflect.Type { + if tp.Kind() == reflect.Ptr { + return getTypeIndirect(tp.Elem()) + } + + return tp +} + +// save stores the model. +func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { + data, err := model.JSON() + if err != nil { + return fmt.Errorf("failed to marshall model: %v", err) + } + + tp := getTypeIndirect(model.Type()) + v := value{ + Type: tp.String(), + Data: json.RawMessage(data), + } + + data, err = json.Marshal(v) + if err != nil { + return fmt.Errorf("failed to marshall value: %v", err) + } + + key := getKey(tenantID, id) + err = l.db.Put(key, data, nil) + if err != nil { + return fmt.Errorf("failed to save model to DB: %v", err) + } + + return nil +} + +// Create stores the model to the DB. +// Errors out if the model already exists. +func (l *levelDBRepo) Create(tenantID, id []byte, model Model) error { + if l.Exists(tenantID, id) { + return fmt.Errorf("model already exists") + } + + return l.save(tenantID, id, model) +} + +// Update overwrites the value at tenantID+id. +// Errors out if model doesn't exist +func (l *levelDBRepo) Update(tenantID, id []byte, model Model) error { + if !l.Exists(tenantID, id) { + return fmt.Errorf("model doesn't exist") + } + + return l.save(tenantID, id, model) +} + +// Register registers the model for type less operations. +// Same type names will be overwritten. +func (l *levelDBRepo) Register(model Model) { + l.mu.Lock() + defer l.mu.Unlock() + tp := getTypeIndirect(model.Type()) + l.models[tp.String()] = tp } diff --git a/documents/repository_test.go b/documents/repository_test.go new file mode 100644 index 000000000..b6da2d616 --- /dev/null +++ b/documents/repository_test.go @@ -0,0 +1,110 @@ +// +build unit + +package documents + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/stretchr/testify/assert" + "github.com/syndtr/goleveldb/leveldb" +) + +func getRepository(ctx map[string]interface{}) Repository { + db := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + return NewLevelDBRepository(db) +} + +type doc struct { + Model + SomeString string `json:"some_string"` +} + +func (m *doc) JSON() ([]byte, error) { + return json.Marshal(m) +} + +func (m *doc) FromJSON(data []byte) error { + return json.Unmarshal(data, m) +} + +func (m *doc) Type() reflect.Type { + return reflect.TypeOf(m) +} + +func TestLevelDBRepo_Create_Exists(t *testing.T) { + repo := getRepository(ctx) + d := &doc{SomeString: "Hello, World!"} + tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) + assert.False(t, repo.Exists(tenantID, id), "doc must not be present") + err := repo.Create(tenantID, id, d) + assert.Nil(t, err, "Create: unknown error") + assert.True(t, repo.Exists(tenantID, id), "doc must be present") + + // overwrite + err = repo.Create(tenantID, id, d) + assert.Error(t, err, "Create: must not overwrite existing doc") +} + +func TestLevelDBRepo_Update_Exists(t *testing.T) { + repo := getRepository(ctx) + d := &doc{SomeString: "Hello, World!"} + tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) + assert.False(t, repo.Exists(tenantID, id), "doc must not be present") + err := repo.Update(tenantID, id, d) + assert.Error(t, err, "Update: should error out") + assert.False(t, repo.Exists(tenantID, id), "doc must not be present") + + // overwrite + err = repo.Create(tenantID, id, d) + assert.Nil(t, err, "Create: unknown error") + d.SomeString = "Hello, Repo!" + err = repo.Update(tenantID, id, d) + assert.Nil(t, err, "Update: unknown error") + assert.True(t, repo.Exists(tenantID, id), "doc must be [resent") +} + +func TestLevelDBRepo_Register(t *testing.T) { + repo := getRepository(ctx) + assert.Len(t, repo.(*levelDBRepo).models, 0, "should be empty") + d := &doc{SomeString: "Hello, Repo!"} + repo.Register(d) + assert.Len(t, repo.(*levelDBRepo).models, 1, "should be not empty") + assert.Contains(t, repo.(*levelDBRepo).models, "documents.doc") +} + +func TestLevelDBRepo_Get_Create_Update(t *testing.T) { + repo := getRepository(ctx) + + tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) + m, err := repo.Get(tenantID, id) + assert.Error(t, err, "must return error") + assert.Nil(t, m) + + d := &doc{SomeString: "Hello, Repo!"} + err = repo.Create(tenantID, id, d) + assert.Nil(t, err, "Create: unknown error") + + m, err = repo.Get(tenantID, id) + assert.Error(t, err, "doc is not registered yet") + assert.Nil(t, m) + + repo.Register(&doc{}) + m, err = repo.Get(tenantID, id) + assert.Nil(t, err) + assert.NotNil(t, m) + nd := m.(*doc) + assert.Equal(t, d, nd, "must be equal") + + d.SomeString = "Hello, World!" + err = repo.Update(tenantID, id, d) + assert.Nil(t, err, "Update: unknown error") + + m, err = repo.Get(tenantID, id) + assert.Nil(t, err, "Get: unknown error") + nd = m.(*doc) + assert.Equal(t, d, nd, "must be equal") +} diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 9cff1de4b..400b637c4 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -10,7 +10,7 @@ import ( ) // initialized ONLY for tests -var testLevelDB Repository +var testLevelDB LegacyRepository func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { if _, ok := context[storage.BootstrappedLevelDB]; !ok { diff --git a/p2p/handler_test.go b/p2p/handler_test.go index e02938916..9024754dc 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -163,7 +163,7 @@ func TestP2PService_basicChecks(t *testing.T) { type mockRepo struct { mock.Mock - documents.Repository + documents.LegacyRepository } func (r mockRepo) Update(id []byte, m documents.Model) error { From bffc000cc6c0a7fd068b77b591036f6d1dcf9ea9 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 6 Dec 2018 17:55:56 +0100 Subject: [PATCH 063/220] integration test: added node time out test & improved test framework (#539) * added cancel func to host * added utils func and basic setup for timeout test * formatting * finished nodeTime test * improved existing testcases * removed uncommented code * added testSuite to hostManager * restart alice after shutdown * added own node for timeout * added timeout after re-start * added restart method * increased timeout --- testworld/README.md | 4 + testworld/document_consensus_test.go | 120 ++++++++++++++++----------- testworld/httputils.go | 16 +++- testworld/park.go | 57 +++++++++++-- testworld/park_test.go | 43 +++------- testworld/payloads.go | 32 +++++++ 6 files changed, 179 insertions(+), 93 deletions(-) create mode 100644 testworld/payloads.go diff --git a/testworld/README.md b/testworld/README.md index b94174fce..1124b0ade 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -17,5 +17,9 @@ Here you can create, run and test nodes with various behaviours to observe how t - Plus points if you write a test with a scenario that matches a scene in Westworld with node names matching the characters ;) +### Speed improvements for testing +- set `runMigrations` to `false` after the contracts are deployed once at the local geth node. +- remove `cmd.CreateConfig(...)` in `park.go` after identities are already deployed once at the local geth node. + diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 74774476d..cf7710d2f 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -2,76 +2,96 @@ package testworld -import "testing" +import ( + "net/http" + "testing" +) func TestHost_AddExternalCollaborator(t *testing.T) { - alice := doctorFord.getHost("Alice") - bob := doctorFord.getHost("Bob") - charlie := doctorFord.getHost("Charlie") - eAlice := alice.createHttpExpectation(t) - eBob := bob.createHttpExpectation(t) - eCharlie := charlie.createHttpExpectation(t) - - a, err := alice.id() - if err != nil { - t.Error(err) - } - - b, err := bob.id() - if err != nil { - t.Error(err) - } - c, err := charlie.id() - if err != nil { - t.Error(err) - } + alice := doctorFord.getHostTestSuite(t, "Alice") + bob := doctorFord.getHostTestSuite(t, "Bob") + charlie := doctorFord.getHostTestSuite(t, "Charlie") // Alice shares invoice document with Bob first - res, err := alice.createInvoice(eAlice, map[string]interface{}{ - "data": map[string]interface{}{ - "invoice_number": "12324", - "due_date": "2018-09-26T23:12:37.902198664Z", - "gross_amount": "40", - "currency": "GBP", - "net_amount": "40", - }, - "collaborators": []string{b.String()}, - }) + res, err := alice.host.createInvoice(alice.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) if err != nil { t.Error(err) } - docIdentifier := res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { t.Error("docIdentifier empty") } params := map[string]interface{}{ "document_id": docIdentifier, - "currency": "GBP", + "currency": "USD", } - getInvoiceAndCheck(eAlice, params) - getInvoiceAndCheck(eBob, params) + getInvoiceAndCheck(alice.expect, params) + getInvoiceAndCheck(bob.expect, params) // Bob updates invoice and shares with Charlie as well - res, err = bob.updateInvoice(eBob, docIdentifier, map[string]interface{}{ - "data": map[string]interface{}{ - "invoice_number": "12324", - "due_date": "2018-09-26T23:12:37.902198664Z", - "gross_amount": "40", - "currency": "USD", - "net_amount": "40", - }, - "collaborators": []string{a.String(), c.String()}, - }) + res, err = bob.host.updateInvoice(bob.expect, http.StatusOK, docIdentifier, updatedInvoicePayload([]string{alice.id.String(), charlie.id.String()})) + if err != nil { t.Error(err) } - docIdentifier = res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + docIdentifier = getDocumentIdentifier(t, res) + if docIdentifier == "" { t.Error("docIdentifier empty") } - params["currency"] = "USD" - getInvoiceAndCheck(eAlice, params) - getInvoiceAndCheck(eBob, params) - getInvoiceAndCheck(eCharlie, params) + params["currency"] = "EUR" + getInvoiceAndCheck(alice.expect, params) + getInvoiceAndCheck(bob.expect, params) + getInvoiceAndCheck(charlie.expect, params) +} + +func TestHost_CollaboratorTimeOut(t *testing.T) { + + kenny := doctorFord.getHostTestSuite(t, "Kenny") + bob := doctorFord.getHostTestSuite(t, "Bob") + + // Kenny shares an invoice with Bob + response, err := kenny.host.createInvoice(kenny.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) + + if err != nil { + t.Error(err) + } + + // check if Bob and Kenny received the document + docIdentifier := getDocumentIdentifier(t, response) + paramsV1 := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "USD", + } + getInvoiceAndCheck(kenny.expect, paramsV1) + getInvoiceAndCheck(bob.expect, paramsV1) + + // Kenny gets killed + kenny.host.canc() + + // Bob updates and sends to Alice + updatedPayload := updatedInvoicePayload([]string{kenny.id.String()}) + + // Bob will anchor the document without Alice signature but will receive an error because kenny is dead + response, err = bob.host.updateInvoice(bob.expect, http.StatusInternalServerError, docIdentifier, updatedPayload) + if err != nil { + t.Error(err) + } + + // check if bob saved the updated document + paramsV2 := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "EUR", + } + getInvoiceAndCheck(bob.expect, paramsV2) + + // bring Kenny back to life + doctorFord.restartHost(kenny.name) + + // Kenny should not have latest version + getInvoiceAndCheck(kenny.expect, paramsV1) + } diff --git a/testworld/httputils.go b/testworld/httputils.go index dc8de8dce..390d5e2c6 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -40,20 +40,28 @@ func getInvoiceAndCheck(e *httpexpect.Expect, params map[string]interface{}) *ht return objGet } -func createInvoice(e *httpexpect.Expect, payload map[string]interface{}) *httpexpect.Object { +func createInvoice(e *httpexpect.Expect, status int, payload map[string]interface{}) *httpexpect.Object { obj := e.POST("/invoice"). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). WithJSON(payload). - Expect().Status(http.StatusOK).JSON().Object() + Expect().Status(status).JSON().Object() return obj } -func updateInvoice(e *httpexpect.Expect, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { +func updateInvoice(e *httpexpect.Expect, status int, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { obj := e.PUT("/invoice/"+docIdentifier). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). WithJSON(payload). - Expect().Status(http.StatusOK).JSON().Object() + Expect().Status(status).JSON().Object() return obj } + +func getDocumentIdentifier(t *testing.T, response *httpexpect.Object) string { + docIdentifier := response.Value("header").Path("$.document_id").String().NotEmpty().Raw() + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + return docIdentifier +} diff --git a/testworld/park.go b/testworld/park.go index 328985497..6d623c834 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -31,6 +31,7 @@ var hostConfig = []struct { {"Alice", 8084, 38204}, {"Bob", 8085, 38205}, {"Charlie", 8086, 38206}, + {"Kenny", 8087, 38207}, } // hostManager is the hostManager of the hosts at Testworld (Robert) @@ -54,6 +55,11 @@ type hostManager struct { // canc is the cancel signal for all hosts canc context.CancelFunc + + // TODO: context should be removed from hostManager + // currently needed to restart a node + // parent context + cancCtx context.Context } func newHostManager( @@ -71,8 +77,17 @@ func newHostManager( } } +func (r *hostManager) restartHost(name string) { + r.startHost(name) + time.Sleep(time.Second * 2) +} + +func (r *hostManager) startHost(name string) { + go r.niceHosts[name].start(r.cancCtx) +} + func (r *hostManager) init() error { - cancCtx, canc := context.WithCancel(context.Background()) + r.cancCtx, r.canc = context.WithCancel(context.Background()) r.bernard = r.createHost("Bernard", 8081, 38201, nil) err := r.bernard.init() if err != nil { @@ -80,7 +95,7 @@ func (r *hostManager) init() error { } // start and wait for Bernard since other hosts depend on him - go r.bernard.start(cancCtx) + go r.bernard.start(r.cancCtx) time.Sleep(10 * time.Second) bootnode, err := r.bernard.p2pURL() @@ -91,13 +106,14 @@ func (r *hostManager) init() error { // start hosts for _, h := range hostConfig { r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, []string{bootnode}) - err = r.niceHosts[h.name].init() + + err := r.niceHosts[h.name].init() if err != nil { return err } - go r.niceHosts[h.name].start(cancCtx) + r.startHost(h.name) + } - r.canc = canc // print host centIDs for name, host := range r.niceHosts { i, err := host.id() @@ -133,6 +149,24 @@ func (r *hostManager) createHost(name string, apiPort, p2pPort int64, bootstraps ) } +type hostTestSuite struct { + name string + host *host + id identity.CentID + expect *httpexpect.Expect +} + +func (r *hostManager) getHostTestSuite(t *testing.T, name string) hostTestSuite { + host := r.getHost(name) + expect := host.createHttpExpectation(t) + id, err := host.id() + if err != nil { + t.Error(err) + } + return hostTestSuite{name: name, host: host, id: id, expect: expect} + +} + type host struct { name, dir, ethNodeUrl, accountKeyPath, accountPassword, network, identityFactoryAddr, identityRegistryAddr, anchorRepositoryAddr, paymentObligationAddr string @@ -144,6 +178,7 @@ type host struct { config config.Config identity identity.Identity node *node.Node + canc context.CancelFunc } func newHost( @@ -209,6 +244,10 @@ func (h *host) start(c context.Context) error { feedback := make(chan error) // may be we can pass a context that exists in c here cancCtx, canc := context.WithCancel(context.WithValue(c, bootstrap.NodeObjRegistry, h.bootstrappedCtx)) + + // cancel func of individual node + h.canc = canc + go h.node.Start(cancCtx, feedback) controlC := make(chan os.Signal, 1) signal.Notify(controlC, os.Interrupt) @@ -225,12 +264,12 @@ func (h *host) start(c context.Context) error { } -func (h *host) createInvoice(e *httpexpect.Expect, inv map[string]interface{}) (*httpexpect.Object, error) { - return createInvoice(e, inv), nil +func (h *host) createInvoice(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { + return createInvoice(e, status, inv), nil } -func (h *host) updateInvoice(e *httpexpect.Expect, docIdentifier string, inv map[string]interface{}) (*httpexpect.Object, error) { - return updateInvoice(e, docIdentifier, inv), nil +func (h *host) updateInvoice(e *httpexpect.Expect, status int, docIdentifier string, inv map[string]interface{}) (*httpexpect.Object, error) { + return updateInvoice(e, status, docIdentifier, inv), nil } func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { diff --git a/testworld/park_test.go b/testworld/park_test.go index 476d519e0..14da7f4ef 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -3,50 +3,33 @@ package testworld import ( - "testing" - "fmt" + "net/http" + "testing" ) func TestHost_Happy(t *testing.T) { - alice := doctorFord.getHost("Alice") - bob := doctorFord.getHost("Bob") - charlie := doctorFord.getHost("Charlie") - eAlice := alice.createHttpExpectation(t) - eBob := bob.createHttpExpectation(t) - eCharlie := charlie.createHttpExpectation(t) + alice := doctorFord.getHostTestSuite(t, "Alice") + bob := doctorFord.getHostTestSuite(t, "Bob") + charlie := doctorFord.getHostTestSuite(t, "Charlie") - b, err := bob.id() + // alice shares a document with bob and charlie + res, err := alice.host.createInvoice(alice.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) if err != nil { t.Error(err) } - c, err := charlie.id() - if err != nil { - t.Error(err) - } - res, err := alice.createInvoice(eAlice, map[string]interface{}{ - "data": map[string]interface{}{ - "invoice_number": "12324", - "due_date": "2018-09-26T23:12:37.902198664Z", - "gross_amount": "40", - "currency": "GBP", - "net_amount": "40", - }, - "collaborators": []string{b.String(), c.String()}, - }) - if err != nil { - t.Error(err) - } - docIdentifier := res.Value("header").Path("$.document_id").String().NotEmpty().Raw() + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { t.Error("docIdentifier empty") } params := map[string]interface{}{ "document_id": docIdentifier, - "currency": "GBP", + "currency": "USD", } - getInvoiceAndCheck(eBob, params) - getInvoiceAndCheck(eCharlie, params) + getInvoiceAndCheck(alice.expect, params) + getInvoiceAndCheck(bob.expect, params) + getInvoiceAndCheck(charlie.expect, params) fmt.Println("Host test success") } diff --git a/testworld/payloads.go b/testworld/payloads.go new file mode 100644 index 000000000..8e0a24821 --- /dev/null +++ b/testworld/payloads.go @@ -0,0 +1,32 @@ +// +build testworld + +package testworld + +func defaultInvoicePayload(collaborators []string) map[string]interface{} { + + return map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "USD", + "net_amount": "40", + }, + "collaborators": collaborators, + } + +} + +func updatedInvoicePayload(collaborators []string) map[string]interface{} { + return map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "EUR", + "net_amount": "42", + }, + "collaborators": collaborators, + } + +} From ef42f056c284f18934502ba63c9c570b541d7767 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 6 Dec 2018 17:58:42 +0100 Subject: [PATCH 064/220] Update README.md (#545) --- testworld/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/testworld/README.md b/testworld/README.md index 1124b0ade..5679df724 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -16,10 +16,8 @@ Here you can create, run and test nodes with various behaviours to observe how t - Each test scenario must be defined in a `testworld/_test.go` file and the build tag `// +build testworld` must be included at the top. - Plus points if you write a test with a scenario that matches a scene in Westworld with node names matching the characters ;) - -### Speed improvements for testing +### Dev +#### Speed improvements for local testing - set `runMigrations` to `false` after the contracts are deployed once at the local geth node. - remove `cmd.CreateConfig(...)` in `park.go` after identities are already deployed once at the local geth node. - - From 25becc31e8d4875849965e5f41166c90b813b3c4 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 6 Dec 2018 19:05:04 +0100 Subject: [PATCH 065/220] Added node defaults to default config (#541) --- build/configs/default_config.yaml | 14 ++++++++++++++ resources/data.go | 8 ++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 010aafb8f..e1215fc8a 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -55,8 +55,22 @@ networks: anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" paymentObligation: "0x0417eb37941164368401D666984cED7694ABcBb1" +# Local Storage configuration +storage: + # Path for levelDB file + path: /tmp/centrifuge_data.leveldb + +# Interface where the API and P2P Server listens to +nodeHostname: 0.0.0.0 +# Port where API Server listens to +nodePort: 8082 + # Peer-to-peer configurations p2p: + # Specify External IP where the node can be reached at if behind NAT + #externalIP: w.x.y.z + # Port used for the P2P layer + port: 38202 # Timeout when opening connections to peers connectTimeout: "30s" diff --git a/resources/data.go b/resources/data.go index 8a41a817b..739a5df0a 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xf7\xc6\x71\xbd\xc8\xf1\x8d\x9f\x02\x02\x87\x24\x62\x0a\x60\x00\x50\x4b\x7e\x7d\x07\x20\xe5\xd8\x71\xec\xdb\x4e\xa7\x7e\x31\x05\xe0\x7c\x38\xcb\x77\x3e\x00\x07\x70\x82\x15\xe9\x5b\x03\x0c\xd7\xd8\xca\x6e\x85\xc2\x80\x41\x6d\x04\x1a\x20\x35\xe1\x42\x1b\x50\x5c\x3c\x60\xb9\x9b\x50\x14\x46\xf1\xaa\xaf\xf1\x02\xcd\x46\xaa\x87\x39\xa8\x5e\x6b\x4e\x44\xc3\xdb\x76\xe2\xc0\xb8\x40\x30\x0d\x02\x1b\x71\xc5\xb0\x52\x83\x69\x88\x81\xe3\x47\x04\x58\x11\x2e\x8c\xc5\x9f\xec\x97\xcc\x27\x00\x07\x70\x2e\x29\x69\x9d\x0b\x5c\xd4\x40\xa5\x30\x8a\x50\x03\x84\x31\x85\x5a\xa3\x06\x81\xc8\xc0\x48\x28\x11\x34\x1a\xd8\x70\xd3\x00\x8a\x35\xac\x89\xe2\xa4\x6c\x51\xcf\x26\xb0\xb7\xb7\x90\x00\x9c\xcd\x21\x8a\x22\xf7\x8d\xa6\x41\x85\xfd\x6a\x8c\xe0\x77\x36\x87\x3c\xca\x87\xb9\x52\x4a\xa3\x8d\x22\xdd\x25\xa2\xd2\x83\xad\x07\xd3\x43\xde\xc5\x87\x41\x98\xcd\xfc\x99\x3f\x0b\x0e\x0d\xed\x0e\xa3\x3c\xf4\xc3\x43\xde\x55\xfa\xf0\x6a\xb5\xbc\xda\x96\x9b\x87\xfe\xfe\xf3\xe7\x93\xaa\xff\xbe\x2c\xb7\xa7\x8b\x6b\x5c\x5e\x1c\x9f\xcb\xef\xbb\x5d\x92\xe4\xeb\x2b\x51\x7f\x5a\x5f\x7e\xfc\x7a\xfe\xf9\x61\xfa\x17\xa0\xd1\x1e\xf4\x53\x95\x9e\x5e\xa4\xab\x87\x6f\x77\xf8\xf5\xee\xc3\x5d\xf8\xed\xb2\x0f\xd2\x3f\x3b\xf6\x2e\x7a\xf8\x43\x06\xcb\x68\xd5\x90\xe6\xf2\x28\xb9\xc1\x44\x04\x03\xe8\x3e\x55\x8b\x7d\xa6\x86\x00\x6c\xf8\x28\x0c\x37\xbb\x33\x42\x8d\x54\xbb\x39\x4c\xa7\x3f\xcd\x5c\x63\xcd\xb5\x79\x36\x45\x04\x6d\xa4\xba\xc6\x4e\x6a\xfe\x93\x55\x47\x76\x96\x26\xff\x2a\x5b\x5e\x13\xc3\xa5\x70\x73\xae\x78\x1f\x09\x17\xbf\xa4\xd2\x58\xe3\x09\x3c\x65\xcc\xe0\xe0\x01\x5c\xf4\x2b\x54\x9c\xc2\xef\x27\x20\x2b\xc7\x9e\x27\x3c\xf9\x61\x39\x14\x32\x09\x46\xab\xa3\x7d\xb5\xa0\xe5\xda\x58\x4b\x21\x19\xbe\x24\x5a\xa7\xe4\x9a\xbb\x09\xe9\xb0\x9f\x38\xb0\x77\xef\x2f\xab\x1f\x25\xb3\x30\x4c\x66\xa1\xef\xcf\xe2\xf0\x67\x06\x04\xe1\x49\xf4\x41\xca\xbb\x73\xce\xe9\xd5\xa7\xcd\xb2\x59\x1e\x7d\x4e\xb7\x1f\xe8\xa5\x3c\xaf\xd2\xeb\xab\xcf\x7f\x9c\x75\x9b\x2a\x50\x59\xb2\x39\xdf\x86\xf7\xd7\x51\x77\xcc\x82\xe9\xaf\xe0\xf3\x74\x16\x06\xfe\x6b\xf0\x57\xf7\x1f\x17\xf9\xbb\xcb\xf7\x6a\x7d\x7a\x7f\x54\x6c\xd8\x83\xbc\xa5\x8b\xc5\xea\xf8\xfe\x7d\x57\xe0\x6e\x77\x1f\xdf\x9c\xe6\xf5\x99\x8a\x9a\xe5\xc5\x9f\xd3\x31\x47\xa7\x23\xdb\xf7\x59\xb4\x29\xf6\xe0\x7a\xec\xe7\x57\xfa\x21\x1e\x8d\xcf\x89\x4d\x0f\x30\xec\x5a\xb9\x43\x06\x37\x2b\xa2\x0c\x1c\x8f\x34\xd3\x50\x49\xe5\x12\x5a\xf3\x35\x8a\x67\xa9\x7c\x49\x45\x78\x95\x8b\xfe\xb6\xf0\x59\x58\xc4\x49\x16\x60\x16\xe5\x71\x98\x16\x19\x49\xd3\x32\x23\x45\x41\xfc\x82\xb1\x94\x66\x11\x8b\x92\x94\xbd\xc1\x5a\x7f\x5b\xa4\xa9\x4f\xfd\xa8\x60\x51\x10\xc4\x49\x44\x2a\x9f\x25\x39\x4d\xd2\x34\xcd\xc2\x88\x15\x34\xac\x48\xc6\x52\xa4\x6f\xf0\xdb\xdf\x66\x55\x9e\xc4\xac\x22\x45\xee\x07\x21\xcb\x2a\x92\x24\x34\xf7\xa3\xb2\x24\x61\x98\xfa\x25\x65\x88\x71\x99\x20\x7b\xab\x13\xfc\x2d\x2b\xfd\x24\x0f\x16\x45\x14\xe6\x69\x1a\xe7\x49\x12\x85\xf9\x82\x9d\x94\xfe\x69\x98\x04\x41\x1e\xa7\xb1\x5f\x15\x98\x9c\xb8\x9e\x29\x51\x09\xd2\x36\xc8\xeb\xc6\x8c\xa4\x3b\x38\x38\x18\x2b\xf0\x41\xae\x89\x80\xb3\xc5\xd5\xf8\xdb\x83\x3b\xab\x76\x5c\x54\xbd\x22\xb0\x93\x3d\xd4\x56\xa6\x05\xa0\x52\x52\x59\x3a\x2d\x1b\xae\x41\xe1\xb7\xde\x56\x8e\x6b\x10\xd2\x80\xee\xbb\x4e\x2a\x83\x0c\x4a\xa4\xa4\xd7\x68\x2d\x95\xeb\x16\xbb\x44\xf5\x42\x58\xa9\x75\x42\xaa\x0d\x31\xb6\x65\x7a\x3b\x34\x83\xeb\x5e\x0c\xe3\x9e\x37\x8e\xfd\x46\x14\x6d\xf8\x1a\x67\xd3\x7f\x8c\x4e\x01\x6c\x6c\xc7\x19\x09\x4c\xfe\xd3\x59\x10\x68\x9d\x88\x77\x44\x71\xb3\x1b\x36\x72\x28\x0f\x2e\x1e\xac\xe7\xc3\xcf\x2f\xe3\x02\xcf\xa3\x0d\xe1\xe2\xb7\x61\xda\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xba\xf1\x9f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x25\x7d\xd0\xc3\x98\x46\xb5\x46\xaf\xb5\x49\x05\xcf\x5b\x91\xad\xd7\xd9\xa6\x86\x30\xb1\x46\x5a\x90\x4e\x37\xd2\x8c\x83\x6e\x6c\xc5\xc5\xb3\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x25\xb3\x4d\x91\xac\xaa\x97\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb3\xeb\xa5\x00\xad\x99\x0d\x89\xd0\x06\x3d\xcd\xbf\x23\xc4\x7e\x91\x82\xe7\x7d\xd5\x52\xa8\x8e\x7a\x8d\xd4\x46\x03\x69\xdb\x27\x63\x5c\x18\x54\x15\xa1\x68\xc7\xbf\x3c\x2f\xf7\xcb\x64\xfe\xaa\xf2\x47\x36\x7c\x64\xb6\xf7\x04\x0e\x8e\x18\x09\x77\x58\xde\xd8\x71\xa3\xc1\xe5\x44\x41\xa5\xe4\x0a\x7a\x61\x54\xaf\x2d\x25\xa4\xe2\x35\x17\x73\x98\xcd\xa6\xaf\xd6\xd3\x36\xf9\x8b\x5a\x7e\xf1\xbc\x5e\x68\x52\xa1\x87\xdb\x4e\x6a\xfc\x02\x55\x4b\xea\x9f\x08\xfc\xdf\x29\x7b\xf8\x3f\x2a\xfb\xb3\x5e\xfa\x8f\xb5\x3d\xf0\xe3\x59\x90\xc4\xb3\x20\x9f\x25\x2f\x4e\xf7\xbd\xf8\x5e\xea\x94\x13\xbc\xed\xcf\xee\x2f\xfa\xe0\xdd\x76\xad\x77\x47\xcb\x1b\xb5\xd4\xc5\xda\x1c\xa5\xa5\xf9\xb8\x10\xef\xcf\xe4\xf9\xd7\xf2\xe1\xfb\x31\x99\xfe\x02\x3e\x99\x05\x79\x32\x0b\xa3\xec\xd5\x0d\x8e\xdf\xd1\x0d\x5f\x7e\x95\x1f\xee\xde\x57\x47\x24\xce\xc3\xdb\x4b\x43\xf0\x76\x7b\x71\xbe\x61\xf9\xf7\x52\x1c\x05\x37\xd9\x06\x17\xf7\xb7\xdb\xfb\xb7\xd5\xdd\x89\xc6\xab\xda\x1e\xfe\x1f\xc4\xfd\x0d\x6d\xcf\x93\x32\x0a\xab\x8c\x44\x55\xec\xc7\x79\x50\x05\x61\x14\xc5\x7e\x1c\xa4\x99\x4f\x73\x5a\xa2\x9f\x55\x19\xcb\x0a\xfa\xa6\xb6\x27\x31\xc1\x28\x8b\x2a\xbf\x48\x2b\x52\x85\xac\x4c\xcb\x9c\xc4\x69\x16\x64\xd4\x2f\x8b\x1c\x69\x45\xfc\x2c\x61\xec\x4d\x6d\x8f\xe3\xb8\x4a\xe3\x02\x23\x3f\x8b\xe3\x10\xb3\x94\xd2\x2a\x8b\xb2\x38\x4d\x31\x09\xab\x20\xf5\x8b\xb2\xc8\xc3\xd4\x7f\x5b\xdb\xfd\x38\xc8\xb0\x8c\xb2\x22\x0e\x82\x34\x8e\xd2\x3c\xf6\x83\x93\x34\x4d\x8b\x3c\xa6\xa7\x27\x59\x5a\xc4\x8b\x23\x7a\x54\x06\xd3\xc9\xe4\x00\x2c\xd9\x3c\x23\x9d\xae\xd8\xb4\x55\xbc\xee\x95\xc3\xd2\x93\x2e\xec\x86\xfb\xee\x92\xaf\x50\xf6\x06\x36\x0d\x0a\x90\x1d\x8a\xf1\xda\x3b\x36\xb1\x23\xb7\x13\xa6\x09\xec\x87\x47\x93\x39\x4c\x23\x5f\xbb\x9d\xae\x7a\xec\xf1\xa7\x2d\x5c\x09\x89\xde\x09\xda\x28\x29\x64\xaf\x6d\xbf\x50\xd4\x9a\x8b\x7a\xf2\xcd\x1a\x0c\x0e\x0c\x97\x76\xed\xaa\x2d\xfa\x55\x89\xca\x76\x9c\x25\x0c\x2a\x7d\x48\xa5\xd0\xb6\x89\xc7\xee\xdb\xd8\x5b\x53\xe9\x54\x4a\x52\x62\x05\x84\x18\x7b\x68\x28\xd3\x77\x13\xb0\xf6\x77\x83\xe1\x1c\x42\x87\x7e\xa6\x10\x35\xf4\x1d\x1c\x5f\xde\x02\xdd\xd1\x16\xf5\x10\xea\xb0\x81\x3d\x80\x36\x84\xbb\xbb\xbe\xf5\x17\xd7\x28\x8c\x0d\x75\x98\xbe\x23\xdc\x45\xfb\xf1\x66\x0e\x81\x0d\xf4\x91\xf2\xba\x43\xca\x2b\x4e\x9f\x07\x3d\xd9\x53\x7e\x08\xed\x06\x5b\xb4\x64\xde\x34\x9c\x36\x8f\xed\x00\x84\x52\xd9\x0b\x27\x71\xf6\x34\x1c\x95\x49\xda\x24\x8c\x92\xc2\x80\x0f\xb2\x47\x7b\x6d\xe4\x6a\xdc\x04\x2a\xde\xe2\x04\xf6\x6f\x9b\xc5\x00\x73\x41\x56\x38\x87\xa9\x7d\xcf\x4c\x1f\x5f\x30\x4e\x7f\x47\xe0\xc7\x7d\x69\x6b\x0f\xaa\x41\x43\xff\xb6\x41\x77\x4e\x73\x85\xb0\xd1\x20\x15\xf0\x8e\x8e\xcf\x1a\xfb\x8a\xb1\x9f\x94\x18\xeb\xb6\x4b\xc9\xdf\x6d\x76\x25\xc3\xdb\xeb\xf3\x39\x34\xc6\x74\xf3\xc3\x43\x77\x30\xd8\xd3\x64\x5e\x24\x71\xb2\x2f\xa6\x7b\x76\xd5\xc4\xc6\xc2\xa9\x75\xb7\x26\xfa\xd2\x7e\xce\x21\xf0\xf7\x7f\x2f\x16\xb7\x7c\xc5\xcd\xb0\xf8\xdc\x7e\xce\x21\xce\x82\x30\xca\xf3\x67\x24\x35\xd2\x55\x6b\xa0\x96\xf8\x11\x99\x51\x44\x68\xf2\x78\xea\xd8\x18\x18\x1b\x9e\x69\x04\xdc\xc1\x0c\x44\xb0\x31\x14\x30\x8a\xd7\x35\x2a\x64\x03\xa5\x0d\x6e\xcd\xbe\xd0\x03\xad\x53\xdf\xf2\xfa\xb5\x8d\x15\x12\x06\x52\xb4\x3b\xdb\x2e\x7b\xb2\xef\xdf\xaa\x7b\x97\x7e\x40\x5f\x23\x61\xcf\xe1\x83\x64\x44\xbf\xb0\x95\x78\xea\x7b\x27\x65\x0b\x2b\xb2\x05\x85\x46\xf1\xe1\x64\xd1\x28\x18\x90\x67\xcb\xe4\x1a\xd5\x04\xec\xc2\xeb\x61\xdd\x1c\xc2\x31\xa7\xbf\x86\x74\xc7\xfb\x9a\xb4\x0e\x77\x37\x34\x00\xb1\x0e\xd2\x5e\x29\xf7\x4e\x7a\x62\xd1\x10\x0d\x25\xa2\x7d\x48\x19\xa4\xc6\xa5\x69\x0f\x60\xf7\xb3\x7a\x16\x8e\x11\x9c\x70\xed\xd8\xe2\x10\xb5\x5c\xbd\x60\x9b\x06\x26\x9f\xde\x02\xc1\x6c\x9d\x47\xa4\xe3\xf6\x99\xbc\xbd\x94\xb2\x5d\x50\x2b\x0b\xa7\xc2\x22\xb1\x39\x18\xd5\xa3\xed\x35\x22\x76\xc0\xb0\xec\xeb\x7a\x94\x24\xdb\x02\x4e\x00\x6a\x09\x76\x93\x89\x9b\x1d\x5a\xad\xeb\x94\xac\x5c\x79\x1e\x4d\x26\x30\x8c\xce\xa1\x22\xad\xc6\xc9\xbf\x03\x00\x00\xff\xff\x6c\x54\x71\x54\x6d\x10\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x5b\x6f\xdb\x3a\xd6\x7d\xf7\xaf\xd8\x70\x5e\xbe\x0f\x18\x39\xba\x5f\x0c\x1c\x0c\xec\x5c\xda\x9e\xa6\x19\x27\x71\x4e\x4e\xf3\x32\xa5\xc8\x2d\x8b\x8d\x4c\xaa\x24\xe5\x4b\x7f\xfd\x80\x94\x9c\x26\x4d\x93\x33\x83\xc1\xf4\xa5\x32\xc9\xbd\xb9\x2f\x6b\x2d\x92\x39\x82\x53\xac\x48\xd7\x18\x60\xb8\xc1\x46\xb6\x6b\x14\x06\x0c\x6a\x23\xd0\x00\x59\x11\x2e\xb4\x01\xc5\xc5\x03\x96\xfb\x11\x45\x61\x14\xaf\xba\x15\x5e\xa2\xd9\x4a\xf5\x30\x05\xd5\x69\xcd\x89\xa8\x79\xd3\x8c\x9c\x33\x2e\x10\x4c\x8d\xc0\x06\xbf\xa2\x5f\xa9\xc1\xd4\xc4\xc0\xc9\xa3\x07\x58\x13\x2e\x8c\xf5\x3f\x3a\x2c\x99\x8e\x00\x8e\xe0\x42\x52\xd2\xb8\x10\xb8\x58\x01\x95\xc2\x28\x42\x0d\x10\xc6\x14\x6a\x8d\x1a\x04\x22\x03\x23\xa1\x44\xd0\x68\x60\xcb\x4d\x0d\x28\x36\xb0\x21\x8a\x93\xb2\x41\x3d\x19\xc1\xc1\xde\xba\x04\xe0\x6c\x0a\x51\x14\xb9\x6f\x34\x35\x2a\xec\xd6\x43\x06\x1f\xd8\x14\xf2\x28\xef\xe7\x4a\x29\x8d\x36\x8a\xb4\x0b\x44\xa5\x7b\x5b\x0f\xc6\xc7\xbc\x8d\x8f\x83\x30\x9b\xf8\x13\x7f\x12\x1c\x1b\xda\x1e\x47\x79\xe8\x87\xc7\xbc\xad\xf4\xf1\xd5\x7a\x79\xb5\x2b\xb7\x0f\xdd\xfd\xe7\xcf\xa7\x55\xf7\x7d\x59\xee\xce\x66\xd7\xb8\xbc\x3c\xb9\x90\xdf\xf7\xfb\x24\xc9\x37\x57\x62\xf5\xc7\x66\xf1\xe9\xeb\xc5\xe7\x87\xf1\x5f\x38\x8d\x0e\x4e\xff\xa8\xd2\xb3\xcb\x74\xfd\xf0\xed\x0e\xbf\xde\x7d\xbc\x0b\xbf\x2d\xba\x20\xfd\xb3\x65\xef\xa2\x87\xdf\x65\xb0\x8c\xd6\x35\xa9\x17\xf3\xe4\x06\x13\x11\xf4\x4e\x0f\xa5\x9a\x1d\x2a\xd5\x27\x60\xd3\x47\x61\xb8\xd9\x9f\x13\x6a\xa4\xda\x4f\x61\x3c\xfe\x69\xe6\x1a\x57\x5c\x9b\x67\x53\x44\xd0\x5a\xaa\x6b\x6c\xa5\xe6\x3f\x59\xb5\x64\x6f\x61\xf2\x8f\xb2\xe1\x2b\x62\xb8\x14\x6e\xce\x35\xef\x13\xe1\xe2\x97\x50\x1a\x7a\x3c\x82\xa7\x88\xe9\x03\x3c\x82\xcb\x6e\x8d\x8a\x53\xf8\x70\x0a\xb2\x72\xe8\x79\x82\x93\x1f\x96\x7d\x23\x93\x60\xb0\x9a\x1f\xba\x05\x0d\xd7\xc6\x5a\x0a\xc9\xf0\x25\xd0\x5a\x25\x37\xdc\x4d\x48\xe7\xfb\x49\x00\x87\xf0\xfe\xb2\xfb\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x46\x40\x10\x9e\x46\x1f\xa5\xbc\xbb\xe0\x9c\x5e\xfd\xb1\x5d\xd6\xcb\xf9\xe7\x74\xf7\x91\x2e\xe4\x45\x95\x5e\x5f\x7d\xfe\xfd\xbc\xdd\x56\x81\xca\x92\xed\xc5\x2e\xbc\xbf\x8e\xda\x13\x16\x8c\x7f\xe5\x3e\x4f\x27\x61\xe0\xbf\xe6\xfe\xea\xfe\xd3\x2c\x7f\xb7\x78\xaf\x36\x67\xf7\xf3\x62\xcb\x1e\xe4\x2d\x9d\xcd\xd6\x27\xf7\xef\xdb\x02\xf7\xfb\xfb\xf8\xe6\x2c\x5f\x9d\xab\xa8\x5e\x5e\xfe\x39\x1e\x6a\x74\x36\xa0\xfd\x50\x45\x5b\x62\x0f\xae\x07\x3e\xbf\xc2\x87\x78\x30\xbe\x20\xb6\x3c\xc0\xb0\x6d\xe4\x1e\x19\xdc\xac\x89\x32\x70\x32\xc0\x4c\x43\x25\x95\x2b\xe8\x8a\x6f\x50\x3c\x2b\xe5\x4b\x28\xc2\xab\x58\xf4\x77\x85\xcf\xc2\x22\x4e\xb2\x00\xb3\x28\x8f\xc3\xb4\xc8\x48\x9a\x96\x19\x29\x0a\xe2\x17\x8c\xa5\x34\x8b\x58\x94\xa4\xec\x0d\xd4\xfa\xbb\x22\x4d\x7d\xea\x47\x05\x8b\x82\x20\x4e\x22\x52\xf9\x2c\xc9\x69\x92\xa6\x69\x16\x46\xac\xa0\x61\x45\x32\x96\x22\x7d\x03\xdf\xfe\x2e\xab\xf2\x24\x66\x15\x29\x72\x3f\x08\x59\x56\x91\x24\xa1\xb9\x1f\x95\x25\x09\xc3\xd4\x2f\x29\x43\x8c\xcb\x04\xd9\x5b\x4c\xf0\x77\xac\xf4\x93\x3c\x98\x15\x51\x98\xa7\x69\x9c\x27\x49\x14\xe6\x33\x76\x5a\xfa\x67\x61\x12\x04\x79\x9c\xc6\x7e\x55\x60\x72\xea\x38\x53\xa2\x12\xa4\xa9\x91\xaf\x6a\x33\x80\xee\xe8\xe8\x68\xe8\xc0\x47\xb9\x21\x02\xce\x67\x57\xc3\x6f\x0f\xee\xac\xda\x71\x51\x75\x8a\xc0\x5e\x76\xb0\xb2\x32\x2d\x00\x95\x92\xca\xc2\x69\x59\x73\x0d\x0a\xbf\x75\xb6\x73\x5c\x83\x90\x06\x74\xd7\xb6\x52\x19\x64\x50\x22\x25\x9d\x46\x6b\xa9\x1c\x5b\xec\x12\xd5\x09\x61\xa5\xd6\x09\xa9\x36\xc4\x58\xca\x74\x76\x68\x02\xd7\x9d\xe8\xc7\x3d\x6f\x18\xfb\x8d\x28\x5a\xf3\x0d\x4e\xc6\x7f\x1b\x82\x02\xd8\x5a\xc6\x19\x09\x4c\xfe\xdd\x59\x10\x68\x9c\x88\xb7\x44\x71\xb3\xef\x37\x72\x5e\x1e\x5c\x3e\xb8\x9a\xf6\x3f\xbf\x0c\x0b\x3c\x8f\xd6\x84\x8b\xdf\xfa\x69\xcf\xb3\xd1\xfe\x16\xf9\x91\x1f\x83\xe7\x6d\x89\x6a\x87\xff\xbc\x92\x28\xc5\x51\x41\x92\xe6\xbe\xef\xfb\xe0\x79\x42\x7a\x44\x50\x8e\xc2\x78\x65\x23\xe9\x83\xee\xc7\x34\xaa\x0d\x7a\x8d\x2d\x2a\x78\xde\x9a\xec\xbc\xd6\x92\x1a\xc2\xc4\x1a\x69\x41\x5a\x5d\x4b\x33\x0c\xba\xb1\x35\x17\xcf\x7e\xda\x98\x09\x35\x7c\x83\xe0\x79\x16\xcc\xb6\x44\xb2\xaa\x5e\x56\x02\x3c\x8f\x95\x1e\x95\xeb\xd6\xae\x97\x02\xb4\x66\x36\x25\x42\x6b\xf4\x34\xff\x8e\x10\xfb\x45\x0a\x9e\xf7\x55\x4b\xa1\x5a\xea\xd5\x52\x1b\x0d\xa4\x69\x9e\x8c\x71\x61\x50\x55\x84\xa2\x1d\xff\xf2\xbc\xdd\x2f\x8b\xf9\xab\xce\xcf\x6d\xfa\xc8\x2c\xf7\x04\xf6\x81\x18\x09\x77\x58\xde\xd8\x71\xa3\xc1\xd5\x44\x41\xa5\xe4\x1a\x3a\x61\x54\xa7\x2d\x24\xa4\xe2\x2b\x2e\xa6\x30\x99\x8c\x5f\xed\xa7\x25\xf9\x8b\x5e\x7e\xf1\xbc\x4e\x68\x52\xa1\x87\xbb\x56\x6a\xfc\x02\x55\x43\x56\x3f\x01\xf8\x3f\x53\xf6\xf0\xbf\x54\xf6\x67\x5c\xfa\xb7\xb5\x3d\xf0\xe3\x49\x90\xc4\x93\x20\x9f\x24\x2f\x4e\xf7\x83\xf8\x2e\x74\xca\x09\xde\x76\xe7\xf7\x97\x5d\xf0\x6e\xb7\xd1\xfb\xf9\xf2\x46\x2d\x75\xb1\x31\xf3\xb4\x34\x9f\x66\xe2\xfd\xb9\xbc\xf8\x5a\x3e\x7c\x3f\x21\xe3\x5f\xb8\x4f\x26\x41\x9e\x4c\xc2\x28\x7b\x75\x83\x93\x77\x74\xcb\x97\x5f\xe5\xc7\xbb\xf7\xd5\x9c\xc4\x79\x78\xbb\x30\x04\x6f\x77\x97\x17\x5b\x96\x7f\x2f\xc5\x3c\xb8\xc9\xb6\x38\xbb\xbf\xdd\xdd\xbf\xad\xee\x4e\x34\x5e\xd5\xf6\xf0\x7f\x20\xee\x6f\x68\x7b\x9e\x94\x51\x58\x65\x24\xaa\x62\x3f\xce\x83\x2a\x08\xa3\x28\xf6\xe3\x20\xcd\x7c\x9a\xd3\x12\xfd\xac\xca\x58\x56\xd0\x37\xb5\x3d\x89\x09\x46\x59\x54\xf9\x45\x5a\x91\x2a\x64\x65\x5a\xe6\x24\x4e\xb3\x20\xa3\x7e\x59\xe4\x48\x2b\xe2\x67\x09\x63\x6f\x6a\x7b\x1c\xc7\x55\x1a\x17\x18\xf9\x59\x1c\x87\x98\xa5\x94\x56\x59\x94\xc5\x69\x8a\x49\x58\x05\xa9\x5f\x94\x45\x1e\xa6\xfe\xdb\xda\xee\xc7\x41\x86\x65\x94\x15\x71\x10\xa4\x71\x94\xe6\xb1\x1f\x9c\xa6\x69\x5a\xe4\x31\x3d\x3b\xcd\xd2\x22\x9e\xcd\xe9\xbc\x0c\xc6\xa3\xd1\xe1\x2a\x7b\x63\xa4\x22\x2b\xb4\x75\xab\xf8\xaa\x53\xce\xd9\x48\xf7\xa3\xfd\x9d\x77\x41\x4c\xed\x2a\xde\xd8\xab\xd3\xe9\x1c\x2a\xde\xe0\xc8\xc6\x60\xea\x29\x1c\x9b\x75\x7b\xfc\xe3\xee\xfd\x4f\x46\x0c\x99\xb8\x95\xac\xb4\xdb\x7c\x78\xd4\x8e\xad\xed\xb7\x6b\xdb\x6c\xf1\x01\x88\x60\xb0\x08\x17\x70\xd3\x13\xdf\x72\x09\x85\x25\xcb\xc8\xd2\xe9\xbd\xd4\x46\x90\x35\x4e\xc1\x77\x77\x50\x7f\x74\x04\x0b\xa9\xcc\xe0\xc4\x3a\xf8\xb5\xa1\x5d\x34\x85\xdc\xcf\x43\xbb\xb9\x25\x94\x67\xa4\xd3\xce\xe7\x29\xea\x51\x1b\xb6\x7d\x7e\x37\x2d\x52\x5e\xed\xe1\x6c\x67\x1c\x45\xe1\xc3\xe2\x49\xac\x4e\x53\x28\x11\xf6\x46\xaf\xd0\xca\x26\x03\x62\x80\x57\x50\x62\xcd\x05\x83\xcb\xd9\xd2\xba\xc1\xc1\xfa\xc3\x62\x0a\xdb\xc9\x6e\xb2\x9f\x7c\xef\xab\x67\xa3\xee\x34\xb2\x47\xd0\xda\xac\x1b\xb2\x47\x65\x6b\xe8\xc2\x75\x8c\x73\xab\x97\x7c\x8d\xb2\x73\x69\x0a\x90\x2d\x8a\xe1\x99\x31\x88\xa6\x13\x13\x77\x10\x8c\xe0\x30\x3c\x98\x4c\x61\x1c\xf9\xda\x75\xf6\xaa\xc3\xee\xa7\x8e\xf6\x94\x21\x7a\x2f\x68\xad\xa4\x90\x9d\xb6\xfa\x44\x51\x6b\x2e\x56\xa3\x6f\xd6\xa0\x2f\x46\xff\x48\xd2\x7d\xea\xdd\xba\x44\x65\x15\xce\x12\x14\x95\x3e\xa6\x52\x68\x2b\x9a\x83\xda\x6d\xed\x2d\xb5\x74\xa7\x82\xa4\xc4\xf4\x95\xd1\x86\x28\xd3\xb5\x23\xb0\xf6\x77\xbd\xe1\x14\xfa\xf4\xce\x15\xa2\x86\xae\x85\x93\xc5\x2d\xd0\x3d\x6d\x50\xf7\xa9\xf6\x1b\xd8\x03\x7f\x4b\xb8\x7b\x5b\xd9\x78\x71\x83\xc2\xd8\x54\xfb\xe9\x3b\xc2\x5d\xb6\x9f\x6e\xa6\x10\xd8\x44\x1f\x25\x46\xbb\x16\x72\xfa\x13\x8c\x0f\x12\x33\xf4\x19\x1b\xb4\xe2\xb1\xad\x39\xad\x1f\xe5\x07\x08\xa5\xb2\x13\xee\x48\xb1\xb7\x8f\xe1\x24\x90\xb6\x08\x83\x84\x33\xe0\xfd\x31\x43\x3b\x6d\xe4\x7a\xd8\xe4\x40\x83\xe1\x2d\x39\xeb\xdd\x5c\x3a\xd0\x8e\xed\xfb\x71\xfc\xf8\x62\x74\xe7\xdd\xe0\xf8\x71\x5f\xda\xd8\x8b\x41\x8f\xaf\xff\xdb\xa2\xbb\x17\x71\x85\xb0\xd5\x20\x15\xf0\x96\x0e\xcf\x48\xfb\x6a\xb4\x9f\x94\x18\x1b\xb6\x2b\xc9\xff\xdb\xea\x4a\x86\xb7\xd7\x17\x53\xa8\x8d\x69\xa7\xc7\xc7\xee\x20\xb6\xa7\xf7\xb4\x48\xe2\xe4\xd0\x4c\xf7\xcc\x5d\x11\x9b\x0b\xa7\x36\xdc\x15\xd1\x0b\xfb\x39\x85\xc0\x3f\xfc\x7b\xb1\xb8\xe1\x6b\x6e\xfa\xc5\x17\xf6\x73\x0a\x71\x16\x84\x51\x9e\x3f\x03\xa9\x91\xae\x5b\x3d\xb4\xc4\x8f\xcc\x8c\x22\x42\x93\xc7\x53\xde\xe6\xc0\x58\xff\x2c\x26\xe0\x2e\x42\x8e\xfd\x7d\x2a\x60\x14\x5f\xad\x50\x21\xeb\x21\x6d\x70\x67\x0e\x8d\xee\x61\x9d\xfa\x16\xd7\xaf\x6d\xac\x90\x30\x90\xa2\xd9\x5b\xba\x1c\xc0\x7e\xf8\xdb\xc0\x21\xa4\x1f\xae\xaf\x91\xb0\xe7\xee\x83\x64\xf0\x7e\x69\x3b\xf1\x34\xf6\x56\xca\x06\xd6\x64\x07\x0a\x8d\xe2\xfd\x49\xae\x51\x30\x20\xcf\x96\xc9\x8d\xa3\xf2\x9a\xec\xae\xfb\x75\x53\x08\x87\x9a\xfe\xda\xa5\xbb\x4e\x6d\x48\xe3\xfc\xee\x7b\x02\x10\x1b\x20\xed\x94\x72\xef\xd2\x27\x16\x35\xd1\x50\x22\xda\x87\xab\x41\x6a\x5c\x99\x0e\x0e\xec\x7e\xf6\xfc\x08\x87\x0c\x4e\xb9\x76\x68\x71\x1e\xb5\x5c\xbf\x40\x9b\x06\x26\x9f\xde\xba\xc1\xec\x5c\x44\xa4\xe5\x23\x00\xb3\x5b\x48\xd9\xcc\xa8\x95\x85\x33\x61\x3d\xb1\x29\x18\xd5\xa1\xe5\x1a\x11\x7b\x60\x58\x76\xab\xd5\x20\x49\x96\x02\x4e\x00\x56\x12\xec\x26\x23\x37\xdb\x53\xad\x6d\x95\xac\x5c\x7b\x1e\x4d\xac\xd8\xd9\xd1\x29\x54\xa4\xd1\x38\xfa\x57\x00\x00\x00\xff\xff\x54\xdb\x3a\xcf\xdd\x11\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4205, mode: os.FileMode(420), modTime: time.Unix(1544092466, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4573, mode: os.FileMode(420), modTime: time.Unix(1544105977, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540471826, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - From c619a37d1c2f3b3c1332df1c2805f368889d0eeb Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 7 Dec 2018 15:07:59 +0100 Subject: [PATCH 066/220] Testworld: detect when host is live instead of waiting arbitrarily (#546) * Minor adjustments * Detect when host is live instead of waiting arbitrarily --- testworld/README.md | 4 +- testworld/document_consensus_test.go | 39 +++++----- testworld/httputils.go | 20 +++--- testworld/park.go | 102 ++++++++++++++++++++------- testworld/park_test.go | 8 +-- testworld/start_test.go | 5 +- 6 files changed, 116 insertions(+), 62 deletions(-) diff --git a/testworld/README.md b/testworld/README.md index 5679df724..a00ee5d84 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -18,6 +18,6 @@ Here you can create, run and test nodes with various behaviours to observe how t ### Dev #### Speed improvements for local testing -- set `runMigrations` to `false` after the contracts are deployed once at the local geth node. -- remove `cmd.CreateConfig(...)` in `park.go` after identities are already deployed once at the local geth node. +- On `start_test.go` set `runMigrations` to `false` after the contracts are deployed once at the local geth node. +- On `start_test.go` set `createHostConfigs` to `false` after configs have been generated in `peerconfigs` dir, note that if you add new hosts using `hostConfig` you would need this to be set to `true` again to generate the config for the new host. diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index cf7710d2f..726dfaf1a 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -8,53 +8,50 @@ import ( ) func TestHost_AddExternalCollaborator(t *testing.T) { - alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") // Alice shares invoice document with Bob first - res, err := alice.host.createInvoice(alice.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) + res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) if err != nil { t.Error(err) } docIdentifier := getDocumentIdentifier(t, res) - if docIdentifier == "" { t.Error("docIdentifier empty") } + params := map[string]interface{}{ "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(alice.expect, params) - getInvoiceAndCheck(bob.expect, params) + getInvoiceAndCheck(alice.httpExpect, params) + getInvoiceAndCheck(bob.httpExpect, params) // Bob updates invoice and shares with Charlie as well - res, err = bob.host.updateInvoice(bob.expect, http.StatusOK, docIdentifier, updatedInvoicePayload([]string{alice.id.String(), charlie.id.String()})) - + res, err = bob.host.updateInvoice(bob.httpExpect, http.StatusOK, docIdentifier, updatedInvoicePayload([]string{alice.id.String(), charlie.id.String()})) if err != nil { t.Error(err) } - docIdentifier = getDocumentIdentifier(t, res) + docIdentifier = getDocumentIdentifier(t, res) if docIdentifier == "" { t.Error("docIdentifier empty") } params["currency"] = "EUR" - getInvoiceAndCheck(alice.expect, params) - getInvoiceAndCheck(bob.expect, params) - getInvoiceAndCheck(charlie.expect, params) + getInvoiceAndCheck(alice.httpExpect, params) + getInvoiceAndCheck(bob.httpExpect, params) + getInvoiceAndCheck(charlie.httpExpect, params) } func TestHost_CollaboratorTimeOut(t *testing.T) { - kenny := doctorFord.getHostTestSuite(t, "Kenny") bob := doctorFord.getHostTestSuite(t, "Bob") // Kenny shares an invoice with Bob - response, err := kenny.host.createInvoice(kenny.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) + response, err := kenny.host.createInvoice(kenny.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) if err != nil { t.Error(err) @@ -66,17 +63,17 @@ func TestHost_CollaboratorTimeOut(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(kenny.expect, paramsV1) - getInvoiceAndCheck(bob.expect, paramsV1) + getInvoiceAndCheck(kenny.httpExpect, paramsV1) + getInvoiceAndCheck(bob.httpExpect, paramsV1) // Kenny gets killed - kenny.host.canc() + kenny.host.kill() // Bob updates and sends to Alice updatedPayload := updatedInvoicePayload([]string{kenny.id.String()}) // Bob will anchor the document without Alice signature but will receive an error because kenny is dead - response, err = bob.host.updateInvoice(bob.expect, http.StatusInternalServerError, docIdentifier, updatedPayload) + response, err = bob.host.updateInvoice(bob.httpExpect, http.StatusInternalServerError, docIdentifier, updatedPayload) if err != nil { t.Error(err) } @@ -86,12 +83,12 @@ func TestHost_CollaboratorTimeOut(t *testing.T) { "document_id": docIdentifier, "currency": "EUR", } - getInvoiceAndCheck(bob.expect, paramsV2) + getInvoiceAndCheck(bob.httpExpect, paramsV2) // bring Kenny back to life - doctorFord.restartHost(kenny.name) + doctorFord.reLive(t, kenny.name) - // Kenny should not have latest version - getInvoiceAndCheck(kenny.expect, paramsV1) + // Kenny should NOT have latest version + getInvoiceAndCheck(kenny.httpExpect, paramsV1) } diff --git a/testworld/httputils.go b/testworld/httputils.go index 390d5e2c6..66ca2841b 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -4,21 +4,14 @@ import ( "crypto/tls" "net/http" "testing" - "time" "github.com/gavv/httpexpect" ) -func createInsecureClient(t *testing.T, baseURL string) *httpexpect.Expect { - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } +func createInsecureClientWithExpect(t *testing.T, baseURL string) *httpexpect.Expect { config := httpexpect.Config{ - BaseURL: baseURL, - Client: &http.Client{ - Transport: transport, - Timeout: time.Second * 600, - }, + BaseURL: baseURL, + Client: createInsecureClient(), Reporter: httpexpect.NewAssertReporter(t), Printers: []httpexpect.Printer{ httpexpect.NewCompactPrinter(t), @@ -65,3 +58,10 @@ func getDocumentIdentifier(t *testing.T, response *httpexpect.Object) string { } return docIdentifier } + +func createInsecureClient() *http.Client { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return &http.Client{Transport: tr} +} diff --git a/testworld/park.go b/testworld/park.go index 6d623c834..6769bc0fd 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -12,6 +12,8 @@ import ( "time" + "net/http" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/config" @@ -34,6 +36,14 @@ var hostConfig = []struct { {"Kenny", 8087, 38207}, } +// hostTestSuite encapsulates test utilities on top of each host +type hostTestSuite struct { + name string + host *host + id identity.CentID + httpExpect *httpexpect.Expect +} + // hostManager is the hostManager of the hosts at Testworld (Robert) type hostManager struct { @@ -77,26 +87,35 @@ func newHostManager( } } -func (r *hostManager) restartHost(name string) { +func (r *hostManager) reLive(t *testing.T, name string) { r.startHost(name) - time.Sleep(time.Second * 2) + // wait for the host to be live, here its 11 seconds allowed but the host should come alive before that and this will return faster + ok, err := r.getHost(name).isLive(11 * time.Second) + if ok { + return + } else { + t.Error(err) + } } func (r *hostManager) startHost(name string) { - go r.niceHosts[name].start(r.cancCtx) + go r.niceHosts[name].live(r.cancCtx) } -func (r *hostManager) init() error { +func (r *hostManager) init(createConfig bool) error { r.cancCtx, r.canc = context.WithCancel(context.Background()) - r.bernard = r.createHost("Bernard", 8081, 38201, nil) + r.bernard = r.createHost("Bernard", 8081, 38201, createConfig, nil) err := r.bernard.init() if err != nil { return err } // start and wait for Bernard since other hosts depend on him - go r.bernard.start(r.cancCtx) - time.Sleep(10 * time.Second) + go r.bernard.live(r.cancCtx) + _, err = r.bernard.isLive(10 * time.Second) + if err != nil { + return fmt.Errorf("bernard couldn't be made alive %v", err) + } bootnode, err := r.bernard.p2pURL() if err != nil { @@ -105,7 +124,7 @@ func (r *hostManager) init() error { // start hosts for _, h := range hostConfig { - r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, []string{bootnode}) + r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, createConfig, []string{bootnode}) err := r.niceHosts[h.name].init() if err != nil { @@ -136,7 +155,7 @@ func (r *hostManager) stop() { r.canc() } -func (r *hostManager) createHost(name string, apiPort, p2pPort int64, bootstraps []string) *host { +func (r *hostManager) createHost(name string, apiPort, p2pPort int64, createConfig bool, bootstraps []string) *host { return newHost( name, r.ethNodeUrl, @@ -145,17 +164,11 @@ func (r *hostManager) createHost(name string, apiPort, p2pPort int64, bootstraps r.network, apiPort, p2pPort, bootstraps, r.txPoolAccess, + createConfig, r.contractAddresses, ) } -type hostTestSuite struct { - name string - host *host - id identity.CentID - expect *httpexpect.Expect -} - func (r *hostManager) getHostTestSuite(t *testing.T, name string) hostTestSuite { host := r.getHost(name) expect := host.createHttpExpectation(t) @@ -163,7 +176,7 @@ func (r *hostManager) getHostTestSuite(t *testing.T, name string) hostTestSuite if err != nil { t.Error(err) } - return hostTestSuite{name: name, host: host, id: id, expect: expect} + return hostTestSuite{name: name, host: host, id: id, httpExpect: expect} } @@ -179,13 +192,14 @@ type host struct { identity identity.Identity node *node.Node canc context.CancelFunc + createConfig bool } func newHost( name, ethNodeUrl, accountKeyPath, accountPassword, network string, apiPort, p2pPort int64, bootstraps []string, - txPoolAccess bool, + txPoolAccess, createConfig bool, smartContractAddrs *config.SmartContractAddresses, ) *host { return &host{ @@ -200,20 +214,24 @@ func newHost( txPoolAccess: txPoolAccess, smartContractAddrs: smartContractAddrs, dir: "peerconfigs/" + name, + createConfig: createConfig, } } func (h *host) init() error { - err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.smartContractAddrs) - if err != nil { - return err + if h.createConfig { + err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.smartContractAddrs) + if err != nil { + return err + } } + m := ctx.MainBootstrapper{} m.PopulateBaseBootstrappers() h.bootstrappedCtx = map[string]interface{}{ config.BootstrappedConfigFile: h.dir + "/config.yaml", } - err = m.Bootstrap(h.bootstrappedCtx) + err := m.Bootstrap(h.bootstrappedCtx) if err != nil { return err } @@ -234,7 +252,7 @@ func (h *host) init() error { return nil } -func (h *host) start(c context.Context) error { +func (h *host) live(c context.Context) error { srvs, err := node.GetServers(h.bootstrappedCtx) if err != nil { return fmt.Errorf("failed to load servers: %v", err) @@ -264,6 +282,42 @@ func (h *host) start(c context.Context) error { } +func (h *host) kill() { + h.canc() +} + +func (h *host) isLive(softTimeOut time.Duration) (bool, error) { + sig := make(chan error) + c := createInsecureClient() + go func(sig chan<- error) { + var fErr error + // wait upto 10 seconds(hard timeout) for the host to be live + for i := 0; i < 10; i++ { + res, err := c.Get(fmt.Sprintf("https://localhost:%d/ping", h.config.GetServerPort())) + fErr = err + if err != nil { + time.Sleep(time.Second) + continue + } + if res.StatusCode == http.StatusOK { + sig <- nil + return + } + } + sig <- fErr + }(sig) + t := time.After(softTimeOut) + select { + case <-t: + return false, fmt.Errorf("host failed to live even after %f seconds", softTimeOut.Seconds()) + case err := <-sig: + if err != nil { + return false, err + } + return true, nil + } +} + func (h *host) createInvoice(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { return createInvoice(e, status, inv), nil } @@ -273,7 +327,7 @@ func (h *host) updateInvoice(e *httpexpect.Expect, status int, docIdentifier str } func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { - return createInsecureClient(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) + return createInsecureClientWithExpect(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) } func (h *host) id() (identity.CentID, error) { diff --git a/testworld/park_test.go b/testworld/park_test.go index 14da7f4ef..fb08632e1 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -14,7 +14,7 @@ func TestHost_Happy(t *testing.T) { charlie := doctorFord.getHostTestSuite(t, "Charlie") // alice shares a document with bob and charlie - res, err := alice.host.createInvoice(alice.expect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) + res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) if err != nil { t.Error(err) } @@ -28,8 +28,8 @@ func TestHost_Happy(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(alice.expect, params) - getInvoiceAndCheck(bob.expect, params) - getInvoiceAndCheck(charlie.expect, params) + getInvoiceAndCheck(alice.httpExpect, params) + getInvoiceAndCheck(bob.httpExpect, params) + getInvoiceAndCheck(charlie.httpExpect, params) fmt.Println("Host test success") } diff --git a/testworld/start_test.go b/testworld/start_test.go index a1316e8bb..1f1b918b8 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -17,6 +17,9 @@ var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 var configFile = "configs/local.json" var runPOAGeth = !isRunningOnCI +// make this true this when running for the first time in local env +var createHostConfigs = isRunningOnCI + // make this false if you want to make the tests run faster locally, but revert before committing to repo var runMigrations = !isRunningOnCI @@ -40,7 +43,7 @@ func TestMain(m *testing.M) { contractAddresses = getSmartContractAddresses() } doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, c.TxPoolAccess, contractAddresses) - err = doctorFord.init() + err = doctorFord.init(createHostConfigs) if err != nil { panic(err) } From 1e612f5746155bb2addb40f4d5f3bdc4e96353f9 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 7 Dec 2018 17:46:38 +0100 Subject: [PATCH 067/220] move to original geth (#547) --- Gopkg.lock | 9 ++++----- Gopkg.toml | 5 ++--- coredocument/coredocument.go | 15 ++++++++------- documents/handler.go | 2 +- documents/handler_test.go | 7 ++++--- documents/invoice/model.go | 3 ++- documents/invoice/model_test.go | 2 +- documents/invoice/service_test.go | 4 ++-- documents/purchaseorder/model.go | 3 ++- documents/purchaseorder/model_test.go | 2 +- documents/purchaseorder/service_test.go | 4 ++-- nft/ethereum_payment_obligation_test.go | 20 ++++++++++---------- 12 files changed, 39 insertions(+), 37 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index d21eaa10d..16b8bb44f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -86,14 +86,14 @@ revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" [[projects]] - digest = "1:d065eb5f32b539d2935f0ec4f2f160b78c924306b923ce5eac6e7dfe46d07794" + digest = "1:f84321c62605dab82f35a0795dfe30981199e28ea8a0652e5e7ba9af66575fef" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "8957bc48e1bd690a835c630fa6fdfd141c41f5dd" + revision = "d0df6e2ed059de47375ef8281529a500cd920261" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" @@ -120,7 +120,7 @@ version = "v1.7" [[projects]] - digest = "1:6aada383585d097e8ef3d06b74956eb1f22f49acb94ca0cb0672c1e767171a23" + digest = "1:54f69b2b6585c979160e3b00194fcdf343abf0f439a9ae5a7d40dd223c7f7364" name = "github.com/ethereum/go-ethereum" packages = [ ".", @@ -149,8 +149,7 @@ "trie", ] pruneopts = "T" - revision = "27e633ca943ee9f49614b9ea074667227402b571" - source = "github.com/centrifuge/go-ethereum" + revision = "d2328b604a2d4ecdccc47d8f9133593161cbd40a" [[projects]] digest = "1:af43bdaaf86655a2343f113e9b293bbc16b12099eaeb223982bbe4d4c22ba14d" diff --git a/Gopkg.toml b/Gopkg.toml index e99796376..51f388f56 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -40,7 +40,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/centrifuge/precise-proofs" - revision = "8957bc48e1bd690a835c630fa6fdfd141c41f5dd" + revision = "d0df6e2ed059de47375ef8281529a500cd920261" [[constraint]] name = "github.com/centrifuge/gocelery" @@ -52,8 +52,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/ethereum/go-ethereum" - source = "github.com/centrifuge/go-ethereum" - revision = "27e633ca943ee9f49614b9ea074667227402b571" + revision = "d2328b604a2d4ecdccc47d8f9133593161cbd40a" [[override]] name = "github.com/satori/go.uuid" diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index 0a5fedded..7a9bc5786 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -80,27 +80,28 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do tree = &t // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: "signing_root"}) + err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: proofs.NewProperty("signing_root")}) if err != nil { return nil, err } // For every signature we create a LeafNode + sigProperty := proofs.NewProperty("signatures") sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ - Property: "signatures.length", + Property: sigProperty.LengthProp(), Salt: make([]byte, 32), Value: fmt.Sprintf("%d", len(document.Signatures)), } - sigLengthNode.HashNode(h) + sigLengthNode.HashNode(h, false) sigLeafList[0] = sigLengthNode for i, sig := range document.Signatures { payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) leaf := proofs.LeafNode{ Hash: payload[:], Hashed: true, - Property: fmt.Sprintf("signatures[%d]", i), + Property: sigProperty.ElemProp(proofs.FieldNum(i)), } - leaf.HashNode(h) + leaf.HashNode(h, false) sigLeafList[i+1] = leaf } err = tree.AddLeaves(sigLeafList) @@ -129,11 +130,11 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs } // Adding document type as it is an excluded field in the tree documentTypeNode := proofs.LeafNode{ - Property: "document_type", + Property: proofs.NewProperty("document_type"), Salt: make([]byte, 32), Value: document.EmbeddedData.TypeUrl, } - documentTypeNode.HashNode(h) + documentTypeNode.HashNode(h, false) err = tree.AddLeaf(documentTypeNode) if err != nil { return nil, err diff --git a/documents/handler.go b/documents/handler.go index 1de7f848b..ec011a31e 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -93,7 +93,7 @@ func ConvertProofsToClientFormat(proofs []*proofspb.Proof) []*documentpb.Proof { // ConvertProofToClientFormat converts a proof in precise proof format in to a client protobuf proof func ConvertProofToClientFormat(proof *proofspb.Proof) *documentpb.Proof { return &documentpb.Proof{ - Property: proof.Property, + Property: proof.GetReadableName(), Value: proof.Value, Salt: hexutil.Encode(proof.Salt), Hash: hexutil.Encode(proof.Hash), diff --git a/documents/handler_test.go b/documents/handler_test.go index 0e0cb457d..1c346cbca 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" @@ -154,7 +155,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { State: "state", FieldProofs: []*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "val1", Salt: []byte{1, 2, 3}, Hash: []byte{1, 2, 4}, @@ -212,7 +213,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { func TestConvertProofsToClientFormat(t *testing.T) { clientFormat := documents.ConvertProofsToClientFormat([]*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "val1", Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), @@ -223,7 +224,7 @@ func TestConvertProofsToClientFormat(t *testing.T) { }, }, { - Property: "prop2", + Property: proofs.ReadableName("prop2"), Value: "val2", Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 46b61d912..ae82423f4 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -373,7 +373,8 @@ func (i *Invoice) calculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prefix}) + prop := proofs.NewProperty(prefix) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: &prop}) invoiceData := i.createP2PProtobuf() err = t.AddLeavesFromDocument(invoiceData, i.getInvoiceSalts(invoiceData)) if err != nil { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 493f16ee5..b3a80f603 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -306,7 +306,7 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { assert.Nil(t, err, "tree should be generated without error") _, leaf := tree.GetLeafByProperty("invoice.invoice_number") assert.NotNil(t, leaf) - assert.Equal(t, "invoice.invoice_number", leaf.Property) + assert.Equal(t, "invoice.invoice_number", leaf.Property.ReadableName()) } func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, error) { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 318d5f587..17f1e002f 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -318,7 +318,7 @@ func TestService_CreateProofs(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") } func TestService_CreateProofsValidationFails(t *testing.T) { @@ -364,7 +364,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "invoice.invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 8e32d5092..01fce2aa7 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -349,7 +349,8 @@ func (p *PurchaseOrder) calculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prefix}) + prop := proofs.NewProperty(prefix) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: &prop}) poData := p.createP2PProtobuf() err = t.AddLeavesFromDocument(poData, p.getPurchaseOrderSalts(poData)) if err != nil { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 1204415fd..1460e0faf 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -270,7 +270,7 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { assert.Nil(t, err, "tree should be generated without error") _, leaf := tree.GetLeafByProperty("po.po_number") assert.NotNil(t, leaf) - assert.Equal(t, "po.po_number", leaf.Property) + assert.Equal(t, "po.po_number", leaf.Property.ReadableName()) } func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, *coredocumentpb.CoreDocument, error) { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index f0e1d5bed..61d26e147 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -390,7 +390,7 @@ func TestService_CreateProofs(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "po.po_number") } func TestService_CreateProofsValidationFails(t *testing.T) { @@ -472,7 +472,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetProperty(), "po.po_number") + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "po.po_number") } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 47162f23a..3989033d6 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,18 +7,18 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -41,13 +41,13 @@ func TestCreateProofData(t *testing.T) { "happypath", []*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "value1", Salt: salt, SortedHashes: sortedHashes, }, { - Property: "prop2", + Property: proofs.ReadableName("prop2"), Value: "value2", Salt: salt, SortedHashes: sortedHashes, @@ -64,13 +64,13 @@ func TestCreateProofData(t *testing.T) { "invalid hashes", []*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "value1", Salt: salt, SortedHashes: [][]byte{utils.RandomSlice(33), utils.RandomSlice(31)}, }, { - Property: "prop2", + Property: proofs.ReadableName("prop2"), Value: "value2", Salt: salt, SortedHashes: [][]byte{utils.RandomSlice(33), utils.RandomSlice(31)}, @@ -87,13 +87,13 @@ func TestCreateProofData(t *testing.T) { "invalid salts", []*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "value1", Salt: utils.RandomSlice(33), SortedHashes: sortedHashes, }, { - Property: "prop2", + Property: proofs.ReadableName("prop2"), Value: "value2", Salt: utils.RandomSlice(32), SortedHashes: sortedHashes, @@ -205,7 +205,7 @@ func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProo State: "state", FieldProofs: []*proofspb.Proof{ { - Property: "prop1", + Property: proofs.ReadableName("prop1"), Value: "val1", Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), @@ -216,7 +216,7 @@ func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProo }, }, { - Property: "prop2", + Property: proofs.ReadableName("prop2"), Value: "val2", Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), From 01e98b660d2ac2bfc2e293787ba638bea59fd9d5 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 7 Dec 2018 19:10:08 +0100 Subject: [PATCH 068/220] Fix p2p timeouts and make Testworld parallel and faster (#548) * Fix timeouts and make Testworld faster * Fix test * Make tests parallel * Remove unnecessary iteration in test scripts * Test script update * Make tests parrallel and work * Make tests parrallel and work --- build/scripts/tests/run_testworld.sh | 22 +++++++++++----------- cmd/centrifuge/create_config.go | 1 + cmd/common.go | 20 +++++++++++--------- config/configuration.go | 4 ++++ config/configuration_test.go | 19 ++++++++++--------- coredocument/processor.go | 7 ++++++- p2p/client.go | 3 ++- testworld/document_consensus_test.go | 2 ++ testworld/park.go | 25 +++++++++++++++++-------- testworld/park_test.go | 1 + testworld/peerconfigs/README.md | 1 + 11 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 testworld/peerconfigs/README.md diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index 5420e36e3..dbbdf04e2 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -3,17 +3,17 @@ echo "Running Testworld" status=$? -for d in $(go list -tags=testworld ./... | grep -v vendor); do - output="go test -race -coverprofile=profile.out -covermode=atomic -tags=testworld $d 2>&1" - eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done - if [ ${PIPESTATUS[0]} -ne 0 ]; then - status=1 - fi - if [ -f profile.out ]; then - cat profile.out >> coverage.txt - rm profile.out - fi -done +output="go test -race -parallel 4 -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" +eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done +if [ ${PIPESTATUS[0]} -ne 0 ]; then + status=1 +fi + +if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out +fi + exit $status diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index a96969957..1868c5041 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -39,6 +39,7 @@ func init() { p2pPort, bootstraps, txPoolAccess, + "", nil) if err != nil { log.Info(targetDataDir, diff --git a/cmd/common.go b/cmd/common.go index 4553d2fa0..77def704f 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -59,18 +59,20 @@ func CreateConfig( apiPort, p2pPort int64, bootstraps []string, txPoolAccess bool, + p2pConnectionTimeout string, smartContractAddrs *config.SmartContractAddresses) error { data := map[string]interface{}{ - "targetDataDir": targetDataDir, - "accountKeyPath": accountKeyPath, - "accountPassword": accountPassword, - "network": network, - "ethNodeURL": ethNodeURL, - "bootstraps": bootstraps, - "apiPort": apiPort, - "p2pPort": p2pPort, - "txpoolaccess": txPoolAccess, + "targetDataDir": targetDataDir, + "accountKeyPath": accountKeyPath, + "accountPassword": accountPassword, + "network": network, + "ethNodeURL": ethNodeURL, + "bootstraps": bootstraps, + "apiPort": apiPort, + "p2pPort": p2pPort, + "p2pConnectTimeout": p2pConnectionTimeout, + "txpoolaccess": txPoolAccess, } if smartContractAddrs != nil { data["smartContractAddresses"] = smartContractAddrs diff --git a/config/configuration.go b/config/configuration.go index 007c03da6..35851384d 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -356,6 +356,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { bootstraps := args["bootstraps"].([]string) apiPort := args["apiPort"].(int64) p2pPort := args["p2pPort"].(int64) + p2pConnectTimeout := args["p2pConnectTimeout"].(string) txPoolAccess := args["txpoolaccess"].(bool) if targetDataDir == "" { @@ -386,6 +387,9 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("nodeHostname", "0.0.0.0") v.Set("nodePort", apiPort) v.Set("p2p.port", p2pPort) + if p2pConnectTimeout != "" { + v.Set("p2p.connectTimeout", p2pConnectTimeout) + } v.Set("ethereum.nodeURL", ethNodeURL) v.Set("ethereum.txPoolAccessEnabled", txPoolAccess) v.Set("ethereum.accounts.main.key", string(bfile)) diff --git a/config/configuration_test.go b/config/configuration_test.go index 939603873..dc3967a0c 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -22,15 +22,16 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { assert.Nil(t, err, "err should be nil") data := map[string]interface{}{ - "targetDataDir": targetDir, - "accountKeyPath": accountKeyPath, - "accountPassword": "pwrd", - "network": "russianhill", - "ethNodeURL": "http://127.0.0.1:9545", - "bootstraps": []string{"/ip4/127.0.0.1/bootstrap1", "/ip4/127.0.0.1/bootstrap2"}, - "apiPort": int64(8082), - "p2pPort": int64(38202), - "txpoolaccess": false, + "targetDataDir": targetDir, + "accountKeyPath": accountKeyPath, + "accountPassword": "pwrd", + "network": "russianhill", + "ethNodeURL": "http://127.0.0.1:9545", + "bootstraps": []string{"/ip4/127.0.0.1/bootstrap1", "/ip4/127.0.0.1/bootstrap2"}, + "apiPort": int64(8082), + "p2pPort": int64(38202), + "txpoolaccess": false, + "p2pConnectTimeout": "", } v, err := CreateConfigFile(data) diff --git a/coredocument/processor.go b/coredocument/processor.go index 1ba218133..8b99a3219 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -3,6 +3,9 @@ package coredocument import ( "fmt" + "context" + "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" @@ -22,6 +25,7 @@ var log = logging.Logger("coredocument") type Config interface { GetNetworkID() uint32 GetIdentityID() ([]byte, error) + GetP2PConnectionTimeout() time.Duration } // Processor identifies an implementation, which can do a bunch of things with a CoreDocument. @@ -93,7 +97,8 @@ func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredoc NetworkIdentifier: dp.config.GetNetworkID(), } - resp, err := client.SendAnchoredDocument(ctx.Context(), &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) + c, _ := context.WithTimeout(ctx.Context(), dp.config.GetP2PConnectionTimeout()) + resp, err := client.SendAnchoredDocument(c, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) if err != nil || !resp.Accepted { return centerrors.Wrap(err, "failed to send document to the node") } diff --git a/p2p/client.go b/p2p/client.go index a41e42204..7733513e4 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -151,7 +151,8 @@ func (s *p2pServer) GetSignaturesForDocument(ctx *header.ContextHeader, identity // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - go s.getSignatureAsync(ctx.Context(), identityService, *doc, client, collaboratorID, in) + c, _ := context.WithTimeout(ctx.Context(), s.config.GetP2PConnectionTimeout()) + go s.getSignatureAsync(c, identityService, *doc, client, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 726dfaf1a..4147a912c 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -8,6 +8,7 @@ import ( ) func TestHost_AddExternalCollaborator(t *testing.T) { + t.Parallel() alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") @@ -47,6 +48,7 @@ func TestHost_AddExternalCollaborator(t *testing.T) { } func TestHost_CollaboratorTimeOut(t *testing.T) { + t.Parallel() kenny := doctorFord.getHostTestSuite(t, "Kenny") bob := doctorFord.getHostTestSuite(t, "Bob") diff --git a/testworld/park.go b/testworld/park.go index 6769bc0fd..67a11f3de 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -36,6 +36,8 @@ var hostConfig = []struct { {"Kenny", 8087, 38207}, } +const defaultP2PTimeout = "2s" + // hostTestSuite encapsulates test utilities on top of each host type hostTestSuite struct { name string @@ -104,7 +106,7 @@ func (r *hostManager) startHost(name string) { func (r *hostManager) init(createConfig bool) error { r.cancCtx, r.canc = context.WithCancel(context.Background()) - r.bernard = r.createHost("Bernard", 8081, 38201, createConfig, nil) + r.bernard = r.createHost("Bernard", defaultP2PTimeout, 8081, 38201, createConfig, nil) err := r.bernard.init() if err != nil { return err @@ -124,7 +126,7 @@ func (r *hostManager) init(createConfig bool) error { // start hosts for _, h := range hostConfig { - r.niceHosts[h.name] = r.createHost(h.name, h.apiPort, h.p2pPort, createConfig, []string{bootnode}) + r.niceHosts[h.name] = r.createHost(h.name, defaultP2PTimeout, h.apiPort, h.p2pPort, createConfig, []string{bootnode}) err := r.niceHosts[h.name].init() if err != nil { @@ -133,8 +135,12 @@ func (r *hostManager) init(createConfig bool) error { r.startHost(h.name) } - // print host centIDs + // make sure hosts are alive and print host centIDs for name, host := range r.niceHosts { + _, err = host.isLive(10 * time.Second) + if err != nil { + return fmt.Errorf("%s couldn't be made alive %v", host.name, err) + } i, err := host.id() if err != nil { return err @@ -155,13 +161,14 @@ func (r *hostManager) stop() { r.canc() } -func (r *hostManager) createHost(name string, apiPort, p2pPort int64, createConfig bool, bootstraps []string) *host { +func (r *hostManager) createHost(name, p2pTimeout string, apiPort, p2pPort int64, createConfig bool, bootstraps []string) *host { return newHost( name, r.ethNodeUrl, r.accountKeyPath, r.accountPassword, r.network, + p2pTimeout, apiPort, p2pPort, bootstraps, r.txPoolAccess, createConfig, @@ -182,7 +189,7 @@ func (r *hostManager) getHostTestSuite(t *testing.T, name string) hostTestSuite type host struct { name, dir, ethNodeUrl, accountKeyPath, accountPassword, network, - identityFactoryAddr, identityRegistryAddr, anchorRepositoryAddr, paymentObligationAddr string + identityFactoryAddr, identityRegistryAddr, anchorRepositoryAddr, paymentObligationAddr, p2pTimeout string apiPort, p2pPort int64 bootstrapNodes []string bootstrappedCtx map[string]interface{} @@ -196,7 +203,7 @@ type host struct { } func newHost( - name, ethNodeUrl, accountKeyPath, accountPassword, network string, + name, ethNodeUrl, accountKeyPath, accountPassword, network, p2pTimeout string, apiPort, p2pPort int64, bootstraps []string, txPoolAccess, createConfig bool, @@ -210,6 +217,7 @@ func newHost( network: network, apiPort: apiPort, p2pPort: p2pPort, + p2pTimeout: p2pTimeout, bootstrapNodes: bootstraps, txPoolAccess: txPoolAccess, smartContractAddrs: smartContractAddrs, @@ -220,7 +228,7 @@ func newHost( func (h *host) init() error { if h.createConfig { - err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.smartContractAddrs) + err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) if err != nil { return err } @@ -263,7 +271,7 @@ func (h *host) live(c context.Context) error { // may be we can pass a context that exists in c here cancCtx, canc := context.WithCancel(context.WithValue(c, bootstrap.NodeObjRegistry, h.bootstrappedCtx)) - // cancel func of individual node + // cancel func of individual host h.canc = canc go h.node.Start(cancCtx, feedback) @@ -286,6 +294,7 @@ func (h *host) kill() { h.canc() } +// isLive waits for host to come alive until the given soft timeout has passed, or the hard timeout of 10s is passed func (h *host) isLive(softTimeOut time.Duration) (bool, error) { sig := make(chan error) c := createInsecureClient() diff --git a/testworld/park_test.go b/testworld/park_test.go index fb08632e1..fab470377 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -9,6 +9,7 @@ import ( ) func TestHost_Happy(t *testing.T) { + t.Parallel() alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") diff --git a/testworld/peerconfigs/README.md b/testworld/peerconfigs/README.md new file mode 100644 index 000000000..ecbcd1263 --- /dev/null +++ b/testworld/peerconfigs/README.md @@ -0,0 +1 @@ +## FILES IN THIS DIRECTORY ARE GENERATED AUTOMATICALLY. THE GENERATED FILES ARE GIT IGNORED. DON'T PUT ANYTHING HERE THAT NEEDS TO BE COMMITED TO THE REPO. \ No newline at end of file From 341447a5e69102415b2a50f85bb8514261358b78 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 10 Dec 2018 10:01:28 +0100 Subject: [PATCH 069/220] Fix for migrate bash script (#549) --- build/scripts/migrate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/scripts/migrate.sh b/build/scripts/migrate.sh index e232aeed7..d93abeb28 100755 --- a/build/scripts/migrate.sh +++ b/build/scripts/migrate.sh @@ -4,8 +4,8 @@ PARENT_DIR=$1 if [ -z ${PARENT_DIR} ]; then - echo "PARENT DIR $1" - PARENT_DIR = `pwd` + PARENT_DIR=`pwd` + echo "PARENT DIR ${PARENT_DIR}" fi # Even if other `env_vars.sh` might hold this variable From d150af3fd60589dc30a50059f07ebeb011f011ce Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 10 Dec 2018 11:12:50 +0100 Subject: [PATCH 070/220] Errors/internal (#543) Fixes #537 Note: This only adds internal errors. We need to add client and peerError later --- errors/errors.go | 143 ++++++++++++++++++++++++++++++++++++++++++ errors/errors_test.go | 113 +++++++++++++++++++++++++++++++++ utils/events.go | 6 +- 3 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 errors/errors.go create mode 100644 errors/errors_test.go diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 000000000..877155958 --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,143 @@ +package errors + +import ( + "fmt" + "strings" +) + +// ErrUnknown is an unknown error type +const ErrUnknown = Error("unknown error") + +// Error is a string that implements error +// this will have interesting side effects of having constant errors +type Error string + +// Error returns error message +func (e Error) Error() string { + return string(e) +} + +// New returns a new error with message passed. +// if args are passed, we will format the message with args +// Example: +// New("some error") returns error with exact string passed +// New("some error: %v", "some context") returns error with message "some error: some context" +func New(format string, args ...interface{}) error { + return Error(fmt.Sprintf(format, args...)) +} + +// listError holds a list of errors +type listError struct { + errs []error +} + +// Error formats the underlying errs into string +func (l *listError) Error() string { + if len(l.errs) == 0 { + return "" + } + + var errs []string + for _, err := range l.errs { + errs = append(errs, err.Error()) + } + + res := strings.Join(errs, "; ") + return "[" + res + "]" +} + +// append appends the err to the list of errs +func getErrs(err error) []error { + if err == nil { + return nil + } + + if errl, ok := err.(*listError); ok { + return errl.errs + } + + return []error{err} +} + +// AppendError returns a new listError +// if errn == nil, return err +// if err is of type listError and if errn is of type listerror, +// append errn errors to err and return err +func AppendError(err, errn error) error { + var errs []error + + for _, e := range []error{err, errn} { + if serrs := getErrs(e); len(serrs) > 0 { + errs = append(errs, serrs...) + } + } + + if len(errs) < 1 { + return nil + } + + return &listError{errs} +} + +// Len returns the total number of errors +// if err is listError, return len(listError.errs) +// if err == nil, return 0 +// else return 1 +func Len(err error) int { + if err == nil { + return 0 + } + + if lerr, ok := err.(*listError); ok { + return len(lerr.errs) + } + + return 1 +} + +// typeError holds a type of error and an context error +type typeError struct { + terr error + ctxErr error +} + +// Error returns the error in string +func (t *typeError) Error() string { + return fmt.Sprintf("%v: %v", t.terr, t.ctxErr) +} + +// NewTypeError returns a new error of type typeError +func NewTypeError(terr, err error) error { + if terr == nil { + terr = ErrUnknown + } + + return &typeError{terr: terr, ctxErr: err} +} + +// TypeError can be implemented by any type error +type TypeError interface { + IsOfType(terr error) bool +} + +// IsOfType returns if the err t is of type terr +func (t *typeError) IsOfType(terr error) bool { + if t.terr.Error() == terr.Error() { + return true + } + + if cterr, ok := t.ctxErr.(TypeError); ok { + return cterr.IsOfType(terr) + } + + return t.ctxErr.Error() == terr.Error() +} + +// IsOfType returns if the err is of type terr +func IsOfType(terr, err error) bool { + if errt, ok := err.(TypeError); ok { + return errt.IsOfType(terr) + } + + return err.Error() == terr.Error() +} diff --git a/errors/errors_test.go b/errors/errors_test.go new file mode 100644 index 000000000..a565709c5 --- /dev/null +++ b/errors/errors_test.go @@ -0,0 +1,113 @@ +// +build unit + +package errors + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNew(t *testing.T) { + tests := []struct { + msg string + args []interface{} + result string + }{ + // empty message + {}, + + //// simple message + { + msg: "some error", + result: "some error", + }, + + // format error + { + msg: "some error: %v: %v", + args: []interface{}{"error1", "error2"}, + result: "some error: error1: error2", + }, + } + + for _, c := range tests { + err := New(c.msg, c.args...) + assert.Equal(t, c.result, err.Error(), "must match") + } +} + +func checkListError(t *testing.T, lerr error, len int, result string) { + assert.NotNil(t, lerr) + _, ok := lerr.(*listError) + assert.True(t, ok) + assert.Equal(t, len, Len(lerr)) + assert.Equal(t, result, lerr.Error()) +} + +func TestAppendError(t *testing.T) { + // both nil + assert.Nil(t, AppendError(nil, nil)) + + // errn nil, and err not nil but simple error + serr := errors.New("some error") + lerr := AppendError(serr, nil) + checkListError(t, lerr, 1, "[some error]") + + // errn nil, and err not nil and a list error + lerr = AppendError(lerr, nil) + checkListError(t, lerr, 1, "[some error]") + + // err nil and errn not nil and simple error + lerr = AppendError(nil, serr) + checkListError(t, lerr, 1, "[some error]") + + // err nil and errn not nil and list error + lerr = AppendError(nil, lerr) + checkListError(t, lerr, 1, "[some error]") + + // both simple errors + lerr = AppendError(serr, serr) + checkListError(t, lerr, 2, "[some error; some error]") + + // err simple and errn list + lerr = AppendError(serr, lerr) + checkListError(t, lerr, 3, "[some error; some error; some error]") + + // err list error and errn simple error + lerr = AppendError(lerr, serr) + checkListError(t, lerr, 4, "[some error; some error; some error; some error]") + + // both list errors + lerr = AppendError(AppendError(serr, nil), AppendError(serr, nil)) + checkListError(t, lerr, 2, "[some error; some error]") +} + +func TestIsOfType(t *testing.T) { + // single type error + const errBadErr = Error("bad error") + serr := New("some error") + terr := NewTypeError(ErrUnknown, serr) + assert.True(t, IsOfType(ErrUnknown, terr)) + assert.False(t, IsOfType(errBadErr, terr)) + assert.Equal(t, "unknown error: some error", terr.Error()) + + // recursive error + terr = NewTypeError(errBadErr, terr) + assert.True(t, IsOfType(ErrUnknown, terr)) + assert.True(t, IsOfType(errBadErr, terr)) + assert.Equal(t, "bad error: unknown error: some error", terr.Error()) + + // simple error + assert.False(t, IsOfType(ErrUnknown, serr)) + assert.False(t, IsOfType(errBadErr, serr)) + assert.True(t, IsOfType(serr, serr)) + + // list error + lerr := AppendError(serr, nil) + assert.False(t, IsOfType(ErrUnknown, lerr)) + assert.False(t, IsOfType(errBadErr, lerr)) + terr = NewTypeError(errBadErr, lerr) + assert.True(t, IsOfType(errBadErr, terr)) +} diff --git a/utils/events.go b/utils/events.go index 299b771b6..f3ff9309b 100644 --- a/utils/events.go +++ b/utils/events.go @@ -1,9 +1,11 @@ package utils -import "fmt" +import ( + "github.com/centrifuge/go-centrifuge/errors" +) // ErrEventNotFound when event is not found and need to retry -var ErrEventNotFound = fmt.Errorf("event not found") +const ErrEventNotFound = errors.Error("event not found") // EventIterator contains functions that make events listening more easier type EventIterator interface { From 59d231b5edc219d5382269fef2fd699aa65cb098 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 10 Dec 2018 14:29:46 +0100 Subject: [PATCH 071/220] Tenant config model (#544) * Node and Tenant config models * Node and Tenant config models * Test update * Fix mistake * Review comments --- config/configuration.go | 8 +- config/model.go | 96 +++++++++++++++++++ config/model_test.go | 198 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 config/model.go create mode 100644 config/model_test.go diff --git a/config/configuration.go b/config/configuration.go index 35851384d..73cc2243d 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -33,7 +33,6 @@ type Config interface { GetP2PPort() int GetP2PExternalIP() string GetP2PConnectionTimeout() time.Duration - GetReceiveEventNotificationEndpoint() string GetServerPort() int GetServerAddress() string GetNumWorkers() int @@ -45,8 +44,6 @@ type Config interface { GetEthereumMaxRetries() int GetEthereumGasPrice() *big.Int GetEthereumGasLimit() uint64 - GetEthereumDefaultAccountName() string - GetEthereumAccount(accountName string) (account *AccountConfig, err error) GetTxPoolAccessEnabled() bool GetNetworkString() string GetNetworkKey(k string) string @@ -54,6 +51,11 @@ type Config interface { GetContractAddress(address string) common.Address GetBootstrapPeers() []string GetNetworkID() uint32 + + // CentID specific configs (eg: for multi tenancy) + GetEthereumAccount(accountName string) (account *AccountConfig, err error) + GetEthereumDefaultAccountName() string + GetReceiveEventNotificationEndpoint() string GetIdentityID() ([]byte, error) GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) diff --git a/config/model.go b/config/model.go new file mode 100644 index 000000000..0d1039fd3 --- /dev/null +++ b/config/model.go @@ -0,0 +1,96 @@ +package config + +import ( + "math/big" + "time" +) + +// KeyPair represents a key pair config +type KeyPair struct { + Pub, Priv string +} + +// NewKeyPair creates a KeyPair +func NewKeyPair(pub, priv string) KeyPair { + return KeyPair{Pub: pub, Priv: priv} +} + +// NodeConfig exposes configs specific to the node +type NodeConfig struct { + StoragePath string + P2PPort int + P2PExternalIP string + P2PConnectionTimeout time.Duration + ServerPort int + ServerAddress string + NumWorkers int + WorkerWaitTimeMS int + EthereumNodeURL string + EthereumContextReadWaitTimeout time.Duration + EthereumContextWaitTimeout time.Duration + EthereumIntervalRetry time.Duration + EthereumMaxRetries int + EthereumGasPrice *big.Int + EthereumGasLimit uint64 + TxPoolAccessEnabled bool + NetworkString string + BootstrapPeers []string + NetworkID uint32 + + // TODO what to do about contract addresses? +} + +// NewNodeConfig creates a new NodeConfig instance with configs +func NewNodeConfig(config Config) *NodeConfig { + return &NodeConfig{ + StoragePath: config.GetStoragePath(), + P2PPort: config.GetP2PPort(), + P2PExternalIP: config.GetP2PExternalIP(), + P2PConnectionTimeout: config.GetP2PConnectionTimeout(), + ServerPort: config.GetServerPort(), + ServerAddress: config.GetServerAddress(), + NumWorkers: config.GetNumWorkers(), + WorkerWaitTimeMS: config.GetWorkerWaitTimeMS(), + EthereumNodeURL: config.GetEthereumNodeURL(), + EthereumContextReadWaitTimeout: config.GetEthereumContextReadWaitTimeout(), + EthereumContextWaitTimeout: config.GetEthereumContextWaitTimeout(), + EthereumIntervalRetry: config.GetEthereumIntervalRetry(), + EthereumMaxRetries: config.GetEthereumMaxRetries(), + EthereumGasPrice: config.GetEthereumGasPrice(), + EthereumGasLimit: config.GetEthereumGasLimit(), + TxPoolAccessEnabled: config.GetTxPoolAccessEnabled(), + NetworkString: config.GetNetworkString(), + BootstrapPeers: config.GetBootstrapPeers(), + NetworkID: config.GetNetworkID(), + } +} + +// TenantConfig exposes configs specific to a tenant in the node +type TenantConfig struct { + EthereumAccount *AccountConfig + EthereumDefaultAccountName string + ReceiveEventNotificationEndpoint string + IdentityID []byte + SigningKeyPair KeyPair + EthAuthKeyPair KeyPair +} + +// NewTenantConfig creates a new TenantConfig instance with configs +func NewTenantConfig(ethAccountName string, config Config) (*TenantConfig, error) { + id, err := config.GetIdentityID() + if err != nil { + return nil, err + } + acc, err := config.GetEthereumAccount(ethAccountName) + if err != nil { + return nil, err + } + return &TenantConfig{ + EthereumAccount: acc, + EthereumDefaultAccountName: config.GetEthereumDefaultAccountName(), + IdentityID: id, + ReceiveEventNotificationEndpoint: config.GetReceiveEventNotificationEndpoint(), + SigningKeyPair: NewKeyPair(config.GetSigningKeyPair()), + EthAuthKeyPair: NewKeyPair(config.GetEthAuthKeyPair()), + }, nil +} diff --git a/config/model_test.go b/config/model_test.go new file mode 100644 index 000000000..065e50e4d --- /dev/null +++ b/config/model_test.go @@ -0,0 +1,198 @@ +package config + +import ( + "testing" + + "math/big" + "time" + + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" +) + +type MockConfig struct { + mock.Mock +} + +func (m *MockConfig) GetStoragePath() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetP2PPort() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetP2PExternalIP() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetP2PConnectionTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetReceiveEventNotificationEndpoint() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetServerPort() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetServerAddress() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetNumWorkers() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetWorkerWaitTimeMS() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetEthereumNodeURL() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetEthereumContextReadWaitTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumContextWaitTimeout() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumIntervalRetry() time.Duration { + args := m.Called() + return args.Get(0).(time.Duration) +} + +func (m *MockConfig) GetEthereumMaxRetries() int { + args := m.Called() + return args.Get(0).(int) +} + +func (m *MockConfig) GetEthereumGasPrice() *big.Int { + args := m.Called() + return args.Get(0).(*big.Int) +} + +func (m *MockConfig) GetEthereumGasLimit() uint64 { + args := m.Called() + return args.Get(0).(uint64) +} + +func (m *MockConfig) GetEthereumDefaultAccountName() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { + args := m.Called(accountName) + return args.Get(0).(*AccountConfig), args.Error(1) +} + +func (m *MockConfig) GetTxPoolAccessEnabled() bool { + args := m.Called() + return args.Get(0).(bool) +} + +func (m *MockConfig) GetNetworkString() string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetNetworkKey(k string) string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetContractAddressString(address string) string { + args := m.Called() + return args.Get(0).(string) +} + +func (m *MockConfig) GetContractAddress(address string) common.Address { + args := m.Called() + return args.Get(0).(common.Address) +} + +func (m *MockConfig) GetBootstrapPeers() []string { + args := m.Called() + return args.Get(0).([]string) +} + +func (m *MockConfig) GetNetworkID() uint32 { + args := m.Called() + return args.Get(0).(uint32) +} + +func (m *MockConfig) GetIdentityID() ([]byte, error) { + args := m.Called() + return args.Get(0).([]byte), args.Error(1) +} + +func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} + +func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} + +func TestNewNodeConfig(t *testing.T) { + c := &MockConfig{} + c.On("GetStoragePath").Return("dummyStorage").Once() + c.On("GetP2PPort").Return(30000).Once() + c.On("GetP2PExternalIP").Return("ip").Once() + c.On("GetP2PConnectionTimeout").Return(time.Second).Once() + + c.On("GetServerPort").Return(8080).Once() + c.On("GetServerAddress").Return("dummyServer").Once() + c.On("GetNumWorkers").Return(2).Once() + c.On("GetWorkerWaitTimeMS").Return(1).Once() + c.On("GetEthereumNodeURL").Return("dummyNode").Once() + + c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumIntervalRetry").Return(time.Second).Once() + c.On("GetEthereumMaxRetries").Return(1).Once() + c.On("GetEthereumGasPrice").Return(big.NewInt(1)).Once() + + c.On("GetEthereumGasLimit").Return(uint64(100)).Once() + c.On("GetTxPoolAccessEnabled").Return(true).Once() + c.On("GetNetworkString").Return("somehill").Once() + c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() + + c.On("GetNetworkID").Return(uint32(1)).Once() + NewNodeConfig(c) + + c.AssertExpectations(t) +} + +func TestNewTenantConfig(t *testing.T) { + c := &MockConfig{} + c.On("GetEthereumAccount", "name").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetSigningKeyPair").Return("pub", "priv").Once() + c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + NewTenantConfig("name", c) + c.AssertExpectations(t) +} From da7b7406655942451fa742954505b0f23d499944 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 10 Dec 2018 19:37:50 +0100 Subject: [PATCH 072/220] use config interface (#552) We seem to using config structure when we have an interface. This PR should take care of using interfaces everywhere --- api/bootstrapper_test.go | 4 +- api/server_test.go | 4 +- api/service.go | 4 +- cmd/common.go | 4 +- config/configuration.go | 109 ++++++++++-------- config/model.go | 4 +- config/model_test.go | 63 +++++----- coredocument/coredocument_test.go | 10 +- documents/invoice/bootstrapper.go | 2 +- documents/invoice/handler.go | 4 +- documents/invoice/model.go | 49 ++++---- documents/invoice/model_test.go | 9 +- documents/invoice/service.go | 4 +- documents/invoice/service_test.go | 6 +- documents/purchaseorder/bootstrapper.go | 2 +- documents/purchaseorder/handler.go | 4 +- documents/purchaseorder/model_test.go | 4 +- documents/purchaseorder/service.go | 2 +- documents/purchaseorder/service_test.go | 3 +- documents/test/anchor_test.go | 4 +- ethereum/geth_client_integration_test.go | 4 +- ethereum/geth_client_test.go | 4 +- header/context.go | 2 +- healthcheck/handler_test.go | 4 +- .../ethereum_identity_integration_test.go | 4 +- identity/identity_test.go | 4 +- keytools/ed25519/ed25519_test.go | 4 +- keytools/secp256k1/secp256k1_test.go | 4 +- nft/payment_obligation_integration_test.go | 4 +- p2p/bootstrapper.go | 2 +- p2p/bootstrapper_test.go | 4 +- p2p/handler.go | 4 +- p2p/handler_integration_test.go | 4 +- p2p/handler_test.go | 4 +- queue/bootstrapper.go | 2 +- storage/bootstrapper.go | 2 +- storage/test_bootstrapper.go | 2 +- testingutils/config/config.go | 1 + testingutils/identity/identity.go | 2 +- testingutils/utils.go | 2 +- testworld/park.go | 4 +- 41 files changed, 183 insertions(+), 179 deletions(-) diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index b9873e422..ec244e842 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/stretchr/testify/assert" ) @@ -21,8 +22,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { assert.Error(t, err) // config - c := &config.Configuration{} - m[config.BootstrappedConfig] = c + m[config.BootstrappedConfig] = new(testingconfig.MockConfig) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/api/server_test.go b/api/server_test.go index eead1078f..b4ab8e46b 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -28,7 +28,7 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration var registry *documents.ServiceRegistry func TestMain(m *testing.M) { @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) flag.Parse() result := m.Run() diff --git a/api/service.go b/api/service.go index a1fbdf930..92e307f4b 100644 --- a/api/service.go +++ b/api/service.go @@ -46,7 +46,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // invoice - invCfg := cfg.(config.Config) + invCfg := cfg.(config.Configuration) handler, err := invoice.GRPCHandler(invCfg, registry) if err != nil { return err @@ -58,7 +58,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // purchase orders - poCfg := cfg.(config.Config) + poCfg := cfg.(config.Configuration) srv, err := purchaseorder.GRPCHandler(poCfg, registry) if err != nil { return fmt.Errorf("failed to get purchase order handler: %v", err) diff --git a/cmd/common.go b/cmd/common.go index 77def704f..0c49800cc 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -29,7 +29,7 @@ func createIdentity(idService identity.Service) (identity.CentID, error) { return centID, nil } -func generateKeys(config config.Config) { +func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetSigningKeyPair() ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") @@ -83,7 +83,7 @@ func CreateConfig( } log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) ctx, canc, _ := CommandBootstrap(v.ConfigFileUsed()) - cfg := ctx[config.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(config.Configuration) generateKeys(cfg) idService := ctx[identity.BootstrappedIDService].(identity.Service) diff --git a/config/configuration.go b/config/configuration.go index 73cc2243d..a07da71cd 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -27,8 +27,18 @@ import ( var log = logging.Logger("config") -// Config defines the methods that a config type should implement. -type Config interface { +// Configuration defines the methods that a config type should implement. +type Configuration interface { + // generic methods + IsSet(key string) bool + Set(key string, value interface{}) + SetDefault(key string, value interface{}) + Get(key string) interface{} + GetString(key string) string + GetBool(key string) bool + GetInt(key string) int + GetDuration(key string) time.Duration + GetStoragePath() string GetP2PPort() int GetP2PExternalIP() string @@ -59,10 +69,13 @@ type Config interface { GetIdentityID() ([]byte, error) GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) + + // debug specific methods + IsPProfEnabled() bool } -// Configuration holds the configuration details for the node. -type Configuration struct { +// configuration holds the configuration details for the node. +type configuration struct { mu sync.RWMutex configFile string v *viper.Viper @@ -76,144 +89,144 @@ type AccountConfig struct { } // IsSet check if the key is set in the config. -func (c *Configuration) IsSet(key string) bool { +func (c *configuration) IsSet(key string) bool { c.mu.RLock() defer c.mu.RUnlock() return c.v.IsSet(key) } // Set update the key and the value it holds in the configuration. -func (c *Configuration) Set(key string, value interface{}) { +func (c *configuration) Set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.v.Set(key, value) } // SetDefault sets the default value for the given key. -func (c *Configuration) SetDefault(key string, value interface{}) { +func (c *configuration) SetDefault(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.v.SetDefault(key, value) } // Get returns associated value for the key. -func (c *Configuration) Get(key string) interface{} { +func (c *configuration) Get(key string) interface{} { return c.get(key) } // GetString returns value string associated with key. -func (c *Configuration) GetString(key string) string { +func (c *configuration) GetString(key string) string { return cast.ToString(c.get(key)) } // GetInt returns value int associated with key. -func (c *Configuration) GetInt(key string) int { +func (c *configuration) GetInt(key string) int { return cast.ToInt(c.get(key)) } // GetBool returns value bool associated with key. -func (c *Configuration) GetBool(key string) bool { +func (c *configuration) GetBool(key string) bool { return cast.ToBool(c.get(key)) } // GetDuration returns value duration associated with key. -func (c *Configuration) GetDuration(key string) time.Duration { +func (c *configuration) GetDuration(key string) time.Duration { return cast.ToDuration(c.get(key)) } -func (c *Configuration) get(key string) interface{} { +func (c *configuration) get(key string) interface{} { c.mu.RLock() defer c.mu.RUnlock() return c.v.Get(key) } // GetStoragePath returns the data storage backend. -func (c *Configuration) GetStoragePath() string { +func (c *configuration) GetStoragePath() string { return c.GetString("storage.Path") } // GetP2PPort returns P2P Port. -func (c *Configuration) GetP2PPort() int { +func (c *configuration) GetP2PPort() int { return c.GetInt("p2p.port") } // GetP2PExternalIP returns P2P External IP. -func (c *Configuration) GetP2PExternalIP() string { +func (c *configuration) GetP2PExternalIP() string { return c.GetString("p2p.externalIP") } // GetP2PConnectionTimeout returns P2P Connect Timeout. -func (c *Configuration) GetP2PConnectionTimeout() time.Duration { +func (c *configuration) GetP2PConnectionTimeout() time.Duration { return c.GetDuration("p2p.connectTimeout") } // GetReceiveEventNotificationEndpoint returns the webhook endpoint defined in the config. -func (c *Configuration) GetReceiveEventNotificationEndpoint() string { +func (c *configuration) GetReceiveEventNotificationEndpoint() string { return c.GetString("notifications.endpoint") } // GetServerPort returns the defined server port in the config. -func (c *Configuration) GetServerPort() int { +func (c *configuration) GetServerPort() int { return c.GetInt("nodePort") } // GetServerAddress returns the defined server address of form host:port in the config. -func (c *Configuration) GetServerAddress() string { +func (c *configuration) GetServerAddress() string { return fmt.Sprintf("%s:%s", c.GetString("nodeHostname"), c.GetString("nodePort")) } // GetNumWorkers returns number of queue workers defined in the config. -func (c *Configuration) GetNumWorkers() int { +func (c *configuration) GetNumWorkers() int { return c.GetInt("queue.numWorkers") } // GetWorkerWaitTimeMS returns the queue worker sleep time between cycles. -func (c *Configuration) GetWorkerWaitTimeMS() int { +func (c *configuration) GetWorkerWaitTimeMS() int { return c.GetInt("queue.workerWaitTimeMS") } // GetEthereumNodeURL returns the URL of the Ethereum Node. -func (c *Configuration) GetEthereumNodeURL() string { +func (c *configuration) GetEthereumNodeURL() string { return c.GetString("ethereum.nodeURL") } // GetEthereumContextReadWaitTimeout returns the read duration to pass for context.Deadline. -func (c *Configuration) GetEthereumContextReadWaitTimeout() time.Duration { +func (c *configuration) GetEthereumContextReadWaitTimeout() time.Duration { return c.GetDuration("ethereum.contextReadWaitTimeout") } // GetEthereumContextWaitTimeout returns the commit duration to pass for context.Deadline. -func (c *Configuration) GetEthereumContextWaitTimeout() time.Duration { +func (c *configuration) GetEthereumContextWaitTimeout() time.Duration { return c.GetDuration("ethereum.contextWaitTimeout") } // GetEthereumIntervalRetry returns duration to wait between retries. -func (c *Configuration) GetEthereumIntervalRetry() time.Duration { +func (c *configuration) GetEthereumIntervalRetry() time.Duration { return c.GetDuration("ethereum.intervalRetry") } // GetEthereumMaxRetries returns the max acceptable retries. -func (c *Configuration) GetEthereumMaxRetries() int { +func (c *configuration) GetEthereumMaxRetries() int { return c.GetInt("ethereum.maxRetries") } // GetEthereumGasPrice returns the gas price to use for a ethereum transaction. -func (c *Configuration) GetEthereumGasPrice() *big.Int { +func (c *configuration) GetEthereumGasPrice() *big.Int { return big.NewInt(cast.ToInt64(c.get("ethereum.gasPrice"))) } // GetEthereumGasLimit returns the gas limit to use for a ethereum transaction. -func (c *Configuration) GetEthereumGasLimit() uint64 { +func (c *configuration) GetEthereumGasLimit() uint64 { return cast.ToUint64(c.get("ethereum.gasLimit")) } // GetEthereumDefaultAccountName returns the default account to use for the transaction. -func (c *Configuration) GetEthereumDefaultAccountName() string { +func (c *configuration) GetEthereumDefaultAccountName() string { return c.GetString("ethereum.defaultAccountName") } // GetEthereumAccount returns the account details associated with the account name. -func (c *Configuration) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { +func (c *configuration) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { k := fmt.Sprintf("ethereum.accounts.%s", accountName) if !c.IsSet(k) { @@ -232,42 +245,42 @@ func (c *Configuration) GetEthereumAccount(accountName string) (account *Account // GetTxPoolAccessEnabled returns if the node can check the txpool for nonce increment. // Note:Important flag for concurrency handling. Disable if Ethereum client doesn't support txpool API (INFURA). -func (c *Configuration) GetTxPoolAccessEnabled() bool { +func (c *configuration) GetTxPoolAccessEnabled() bool { return c.GetBool("ethereum.txPoolAccessEnabled") } // GetNetworkString returns defined network the node is connected to. -func (c *Configuration) GetNetworkString() string { +func (c *configuration) GetNetworkString() string { return c.GetString("centrifugeNetwork") } // GetNetworkKey returns the specific key(k) value defined in the default network. -func (c *Configuration) GetNetworkKey(k string) string { +func (c *configuration) GetNetworkKey(k string) string { return fmt.Sprintf("networks.%s.%s", c.GetNetworkString(), k) } // GetContractAddressString returns the deployed contract address for a given contract. -func (c *Configuration) GetContractAddressString(contract string) (address string) { +func (c *configuration) GetContractAddressString(contract string) (address string) { return c.GetString(c.GetNetworkKey(fmt.Sprintf("contractAddresses.%s", contract))) } // GetContractAddress returns the deployed contract address for a given contract. -func (c *Configuration) GetContractAddress(contract string) (address common.Address) { +func (c *configuration) GetContractAddress(contract string) (address common.Address) { return common.HexToAddress(c.GetContractAddressString(contract)) } // GetBootstrapPeers returns the list of configured bootstrap nodes for the given network. -func (c *Configuration) GetBootstrapPeers() []string { +func (c *configuration) GetBootstrapPeers() []string { return cast.ToStringSlice(c.get(c.GetNetworkKey("bootstrapPeers"))) } // GetNetworkID returns the numerical network id. -func (c *Configuration) GetNetworkID() uint32 { +func (c *configuration) GetNetworkID() uint32 { return uint32(c.GetInt(c.GetNetworkKey("id"))) } // GetIdentityID returns the self centID in bytes. -func (c *Configuration) GetIdentityID() ([]byte, error) { +func (c *configuration) GetIdentityID() ([]byte, error) { id, err := hexutil.Decode(c.GetString("identityId")) if err != nil { return nil, centerrors.Wrap(err, "can't read identityId from config") @@ -276,28 +289,28 @@ func (c *Configuration) GetIdentityID() ([]byte, error) { } // GetSigningKeyPair returns the signing key pair. -func (c *Configuration) GetSigningKeyPair() (pub, priv string) { +func (c *configuration) GetSigningKeyPair() (pub, priv string) { return c.GetString("keys.signing.publicKey"), c.GetString("keys.signing.privateKey") } // GetEthAuthKeyPair returns ethereum key pair. -func (c *Configuration) GetEthAuthKeyPair() (pub, priv string) { +func (c *configuration) GetEthAuthKeyPair() (pub, priv string) { return c.GetString("keys.ethauth.publicKey"), c.GetString("keys.ethauth.privateKey") } // IsPProfEnabled returns true if the pprof is enabled -func (c *Configuration) IsPProfEnabled() bool { +func (c *configuration) IsPProfEnabled() bool { return c.GetBool("debug.pprof") } // LoadConfiguration loads the configuration from the given file. -func LoadConfiguration(configFile string) *Configuration { - cfg := &Configuration{configFile: configFile, mu: sync.RWMutex{}} - cfg.InitializeViper() +func LoadConfiguration(configFile string) Configuration { + cfg := &configuration{configFile: configFile, mu: sync.RWMutex{}} + cfg.initializeViper() return cfg } -func (c *Configuration) readConfigFile(path string) error { +func (c *configuration) readConfigFile(path string) error { c.mu.Lock() defer c.mu.Unlock() file, err := os.Open(path) @@ -308,9 +321,9 @@ func (c *Configuration) readConfigFile(path string) error { return err } -// InitializeViper loads viper if not loaded already. +// initializeViper loads viper if not loaded already. // This method should not have any effects if Viper is already initialized. -func (c *Configuration) InitializeViper() { +func (c *configuration) initializeViper() { if c.v != nil { return } diff --git a/config/model.go b/config/model.go index 0d1039fd3..2d62b936f 100644 --- a/config/model.go +++ b/config/model.go @@ -41,7 +41,7 @@ type NodeConfig struct { } // NewNodeConfig creates a new NodeConfig instance with configs -func NewNodeConfig(config Config) *NodeConfig { +func NewNodeConfig(config Configuration) *NodeConfig { return &NodeConfig{ StoragePath: config.GetStoragePath(), P2PPort: config.GetP2PPort(), @@ -76,7 +76,7 @@ type TenantConfig struct { } // NewTenantConfig creates a new TenantConfig instance with configs -func NewTenantConfig(ethAccountName string, config Config) (*TenantConfig, error) { +func NewTenantConfig(ethAccountName string, config Configuration) (*TenantConfig, error) { id, err := config.GetIdentityID() if err != nil { return nil, err diff --git a/config/model_test.go b/config/model_test.go index 065e50e4d..ee38b08c8 100644 --- a/config/model_test.go +++ b/config/model_test.go @@ -11,152 +11,153 @@ import ( "github.com/stretchr/testify/mock" ) -type MockConfig struct { +type mockConfig struct { + Configuration mock.Mock } -func (m *MockConfig) GetStoragePath() string { +func (m *mockConfig) GetStoragePath() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetP2PPort() int { +func (m *mockConfig) GetP2PPort() int { args := m.Called() return args.Get(0).(int) } -func (m *MockConfig) GetP2PExternalIP() string { +func (m *mockConfig) GetP2PExternalIP() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetP2PConnectionTimeout() time.Duration { +func (m *mockConfig) GetP2PConnectionTimeout() time.Duration { args := m.Called() return args.Get(0).(time.Duration) } -func (m *MockConfig) GetReceiveEventNotificationEndpoint() string { +func (m *mockConfig) GetReceiveEventNotificationEndpoint() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetServerPort() int { +func (m *mockConfig) GetServerPort() int { args := m.Called() return args.Get(0).(int) } -func (m *MockConfig) GetServerAddress() string { +func (m *mockConfig) GetServerAddress() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetNumWorkers() int { +func (m *mockConfig) GetNumWorkers() int { args := m.Called() return args.Get(0).(int) } -func (m *MockConfig) GetWorkerWaitTimeMS() int { +func (m *mockConfig) GetWorkerWaitTimeMS() int { args := m.Called() return args.Get(0).(int) } -func (m *MockConfig) GetEthereumNodeURL() string { +func (m *mockConfig) GetEthereumNodeURL() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetEthereumContextReadWaitTimeout() time.Duration { +func (m *mockConfig) GetEthereumContextReadWaitTimeout() time.Duration { args := m.Called() return args.Get(0).(time.Duration) } -func (m *MockConfig) GetEthereumContextWaitTimeout() time.Duration { +func (m *mockConfig) GetEthereumContextWaitTimeout() time.Duration { args := m.Called() return args.Get(0).(time.Duration) } -func (m *MockConfig) GetEthereumIntervalRetry() time.Duration { +func (m *mockConfig) GetEthereumIntervalRetry() time.Duration { args := m.Called() return args.Get(0).(time.Duration) } -func (m *MockConfig) GetEthereumMaxRetries() int { +func (m *mockConfig) GetEthereumMaxRetries() int { args := m.Called() return args.Get(0).(int) } -func (m *MockConfig) GetEthereumGasPrice() *big.Int { +func (m *mockConfig) GetEthereumGasPrice() *big.Int { args := m.Called() return args.Get(0).(*big.Int) } -func (m *MockConfig) GetEthereumGasLimit() uint64 { +func (m *mockConfig) GetEthereumGasLimit() uint64 { args := m.Called() return args.Get(0).(uint64) } -func (m *MockConfig) GetEthereumDefaultAccountName() string { +func (m *mockConfig) GetEthereumDefaultAccountName() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { +func (m *mockConfig) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { args := m.Called(accountName) return args.Get(0).(*AccountConfig), args.Error(1) } -func (m *MockConfig) GetTxPoolAccessEnabled() bool { +func (m *mockConfig) GetTxPoolAccessEnabled() bool { args := m.Called() return args.Get(0).(bool) } -func (m *MockConfig) GetNetworkString() string { +func (m *mockConfig) GetNetworkString() string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetNetworkKey(k string) string { +func (m *mockConfig) GetNetworkKey(k string) string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetContractAddressString(address string) string { +func (m *mockConfig) GetContractAddressString(address string) string { args := m.Called() return args.Get(0).(string) } -func (m *MockConfig) GetContractAddress(address string) common.Address { +func (m *mockConfig) GetContractAddress(address string) common.Address { args := m.Called() return args.Get(0).(common.Address) } -func (m *MockConfig) GetBootstrapPeers() []string { +func (m *mockConfig) GetBootstrapPeers() []string { args := m.Called() return args.Get(0).([]string) } -func (m *MockConfig) GetNetworkID() uint32 { +func (m *mockConfig) GetNetworkID() uint32 { args := m.Called() return args.Get(0).(uint32) } -func (m *MockConfig) GetIdentityID() ([]byte, error) { +func (m *mockConfig) GetIdentityID() ([]byte, error) { args := m.Called() return args.Get(0).([]byte), args.Error(1) } -func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { +func (m *mockConfig) GetSigningKeyPair() (pub, priv string) { args := m.Called() return args.Get(0).(string), args.Get(1).(string) } -func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { +func (m *mockConfig) GetEthAuthKeyPair() (pub, priv string) { args := m.Called() return args.Get(0).(string), args.Get(1).(string) } func TestNewNodeConfig(t *testing.T) { - c := &MockConfig{} + c := &mockConfig{} c.On("GetStoragePath").Return("dummyStorage").Once() c.On("GetP2PPort").Return(30000).Once() c.On("GetP2PExternalIP").Return("ip").Once() @@ -186,7 +187,7 @@ func TestNewNodeConfig(t *testing.T) { } func TestNewTenantConfig(t *testing.T) { - c := &MockConfig{} + c := &mockConfig{} c.On("GetEthereumAccount", "name").Return(&AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 015d2fee1..27496227f 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -3,13 +3,11 @@ package coredocument import ( + "context" "crypto/sha256" - "testing" - "flag" "os" - - "context" + "testing" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -33,14 +31,14 @@ var ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) flag.Parse() cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 22d9874c0..209a43289 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -24,7 +24,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(config.Configuration) ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) if !ok { diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 9c6b9f65c..3043c52e6 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -22,11 +22,11 @@ var apiLog = logging.Logger("invoice-api") // anchoring, sending, finding stored invoice document type grpcHandler struct { service Service - config config.Config + config config.Configuration } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { +func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) if err != nil { return nil, err diff --git a/documents/invoice/model.go b/documents/invoice/model.go index ae82423f4..ed42d9b4e 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -26,38 +26,29 @@ const prefix string = "invoice" // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { - // invoice number or reference number - InvoiceNumber string - // name of the sender company - SenderName string - // street and address details of the sender company - SenderStreet string - SenderCity string - SenderZipcode string - // country ISO code of the sender of this invoice - SenderCountry string - // name of the recipient company - RecipientName string + InvoiceNumber string // invoice number or reference number + SenderName string // name of the sender company + SenderStreet string // street and address details of the sender company + SenderCity string + SenderZipcode string // country ISO code of the sender of this invoice + SenderCountry string + RecipientName string // name of the recipient company RecipientStreet string RecipientCity string RecipientZipcode string - // country ISO code of the receipient of this invoice - RecipientCountry string - // ISO currency code - Currency string - // invoice amount including tax - GrossAmount int64 - // invoice amount excluding tax - NetAmount int64 - TaxAmount int64 - TaxRate int64 - Recipient *identity.CentID - Sender *identity.CentID - Payee *identity.CentID - Comment string - DueDate *timestamp.Timestamp - DateCreated *timestamp.Timestamp - ExtraData []byte + RecipientCountry string // country ISO code of the receipient of this invoice + Currency string // country ISO code of the receipient of this invoice + GrossAmount int64 // invoice amount including tax + NetAmount int64 // invoice amount excluding tax + TaxAmount int64 + TaxRate int64 + Recipient *identity.CentID + Sender *identity.CentID + Payee *identity.CentID + Comment string + DueDate *timestamp.Timestamp + DateCreated *timestamp.Timestamp + ExtraData []byte InvoiceSalts *invoicepb.InvoiceDataSalts CoreDocument *coredocumentpb.CoreDocument diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index b3a80f603..7593aebd4 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -3,13 +3,12 @@ package invoice import ( + "context" "encoding/json" + "os" "reflect" "testing" - "context" - "os" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" @@ -34,7 +33,7 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -54,7 +53,7 @@ func TestMain(m *testing.M) { &queue.Starter{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index dd2f5d481..162d20924 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -61,8 +61,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Config, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config.(notification.Config)), anchorRepository: anchorRepository, identityService: identityService} +func DefaultService(config config.Configuration, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } // CreateProofs creates proofs for the latest version document given the fields diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 17f1e002f..50a500389 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -12,13 +12,13 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -45,14 +45,14 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(&config.Configuration{}, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) + srv := DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(&config.Configuration{}, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) + return idService, DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) } func createMockDocument() (*Invoice, error) { diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 989328236..a128993ce 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -23,7 +23,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { if _, ok := ctx[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(*config.Configuration) + cfg := ctx[config.BootstrappedConfig].(config.Configuration) ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) if !ok { diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index d50e81b5c..7db80a36b 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -21,11 +21,11 @@ var apiLog = logging.Logger("purchaseorder-api") // anchoring, sending, finding stored purchase order document type grpcHandler struct { service Service - config config.Config + config config.Configuration } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { +func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { return nil, fmt.Errorf("failed to fetch purchase order service") diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 1460e0faf..54f082551 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -33,7 +33,7 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 78bff8f85..487b60b7c 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -61,7 +61,7 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Config, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { +func DefaultService(config config.Configuration, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 61d26e147..ba33648a7 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -44,7 +45,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(nil, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return idService, DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func TestService_Update(t *testing.T) { diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index 6973e20aa..753e50144 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -20,14 +20,14 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index b806bad7a..8fb70caad 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/assert" ) -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index f6799dfb1..21206aa4f 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -23,7 +23,7 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ @@ -31,7 +31,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) cfg.Set("ethereum.txPoolAccessEnabled", false) cfg.Set("ethereum.intervalRetry", time.Millisecond*100) result := m.Run() diff --git a/header/context.go b/header/context.go index b8967b80a..937cda15b 100644 --- a/header/context.go +++ b/header/context.go @@ -15,7 +15,7 @@ type ContextHeader struct { } // NewContextHeader creates new instance of the request headers. -func NewContextHeader(context context.Context, config config.Config) (*ContextHeader, error) { +func NewContextHeader(context context.Context, config config.Configuration) (*ContextHeader, error) { idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) if err != nil { return nil, fmt.Errorf("failed to get id config: %v", err) diff --git a/healthcheck/handler_test.go b/healthcheck/handler_test.go index 86f15c10b..fae97a9b0 100644 --- a/healthcheck/handler_test.go +++ b/healthcheck/handler_test.go @@ -15,14 +15,14 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 7f1240688..1014bd146 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -17,14 +17,14 @@ import ( ) var identityService identity.Service -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) ctx := cc.TestFunctionalEthereumBootstrap() - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/identity/identity_test.go b/identity/identity_test.go index 4bdb652fa..4fbf74b53 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -18,14 +18,14 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/keytools/ed25519/ed25519_test.go b/keytools/ed25519/ed25519_test.go index 6245d8cf5..851b5ea19 100644 --- a/keytools/ed25519/ed25519_test.go +++ b/keytools/ed25519/ed25519_test.go @@ -12,14 +12,14 @@ import ( ) var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() os.Exit(result) } diff --git a/keytools/secp256k1/secp256k1_test.go b/keytools/secp256k1/secp256k1_test.go index bab265b97..9b34b8502 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/keytools/secp256k1/secp256k1_test.go @@ -17,7 +17,7 @@ import ( const MaxMsgLen = 32 var ctx = map[string]interface{}{} -var cfg *config.Configuration +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ @@ -25,7 +25,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) result := m.Run() os.Exit(result) } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 43381da8e..71fe4ac0f 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -25,7 +25,7 @@ import ( ) var registry *documents.ServiceRegistry -var cfg *config.Configuration +var cfg config.Configuration var idService identity.Service var payOb nft.PaymentObligation @@ -34,7 +34,7 @@ func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) idService = ctx[identity.BootstrappedIDService].(identity.Service) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) prevSignPubkey := cfg.Get("keys.signing.publicKey") prevSignPrivkey := cfg.Get("keys.signing.privateKey") diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 14db0e294..d5527d300 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -18,7 +18,7 @@ type Bootstrapper struct{} // Bootstrap initiates p2p server and client into context func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[config.BootstrappedConfig].(*config.Configuration) + cfg, ok := ctx[config.BootstrappedConfig].(config.Configuration) if !ok { return fmt.Errorf("config not initialised") } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index c70a162a5..7dfd4b829 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/stretchr/testify/assert" ) @@ -21,8 +22,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { assert.Error(t, err) // config - c := &config.Configuration{} - m[config.BootstrappedConfig] = c + m[config.BootstrappedConfig] = new(testingconfig.MockConfig) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/handler.go b/p2p/handler.go index c18031693..f2261e20c 100644 --- a/p2p/handler.go +++ b/p2p/handler.go @@ -41,11 +41,11 @@ func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb. // handler implements the grpc interface type handler struct { registry *documents.ServiceRegistry - config config.Config + config config.Configuration } // GRPCHandler returns an implementation of P2PServiceServer -func GRPCHandler(config config.Config, registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { +func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { return handler{registry: registry, config: config} } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 3ff71a0ef..d9b0ab58f 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -32,7 +32,7 @@ import ( var ( handler p2ppb.P2PServiceServer anchorRepo anchors.AnchorRepository - cfg *config.Configuration + cfg config.Configuration idService identity.Service ) @@ -42,7 +42,7 @@ func TestMain(m *testing.M) { registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 9024754dc..1a0f0e4f1 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -31,7 +31,7 @@ var ( grpcHandler p2ppb.P2PServiceServer registry *documents.ServiceRegistry coreDoc = testingcoredocument.GenerateCoreDocument() - cfg *config.Configuration + cfg config.Configuration testClient *p2pServer ) @@ -44,7 +44,7 @@ func TestMain(m *testing.M) { } ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(*config.Configuration) + cfg = ctx[config.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index ee1021218..cb497eeb5 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -17,7 +17,7 @@ func (b *Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[config.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(config.Configuration) srv := &Server{config: cfg, taskTypes: []TaskType{}} context[bootstrap.BootstrappedQueueServer] = srv b.context = context diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index 82ee57aae..3a8d29ca2 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -18,7 +18,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[config.BootstrappedConfig]; !ok { return errors.New("config not initialised") } - cfg := context[config.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(config.Configuration) levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index 7058a88cc..c85b95847 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -16,7 +16,7 @@ var db *leveldb.DB func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { rs := GetRandomTestStoragePath() - cfg := context[config.BootstrappedConfig].(*config.Configuration) + cfg := context[config.BootstrappedConfig].(config.Configuration) cfg.SetDefault("storage.Path", rs) log.Info("Set storage.Path to:", cfg.GetStoragePath()) db, err = NewLevelDBStorage(cfg.GetStoragePath()) diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 1ddb55ea7..c6f69f1bf 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -10,6 +10,7 @@ import ( ) type MockConfig struct { + config.Configuration mock.Mock } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 42b5a9d26..a33d29c38 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -8,7 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -func CreateIdentityWithKeys(cfg config.Config, idService identity.Service) identity.CentID { +func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service) identity.CentID { idConfig, _ := identity.GetIdentityConfig(cfg) // only create identity if it doesn't exist id, err := idService.LookupIdentityForID(idConfig.ID) diff --git a/testingutils/utils.go b/testingutils/utils.go index d7a293906..3a3e291a5 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -6,7 +6,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) -func MockConfigOption(cfg *config.Configuration, key string, value interface{}) func() { +func MockConfigOption(cfg config.Configuration, key string, value interface{}) func() { mockedValue := cfg.Get(key) cfg.Set(key, value) return func() { diff --git a/testworld/park.go b/testworld/park.go index 67a11f3de..6c40d3cb0 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -195,7 +195,7 @@ type host struct { bootstrappedCtx map[string]interface{} txPoolAccess bool smartContractAddrs *config.SmartContractAddresses - config config.Config + config config.Configuration identity identity.Identity node *node.Node canc context.CancelFunc @@ -243,7 +243,7 @@ func (h *host) init() error { if err != nil { return err } - h.config = h.bootstrappedCtx[config.BootstrappedConfig].(config.Config) + h.config = h.bootstrappedCtx[config.BootstrappedConfig].(config.Configuration) idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) idBytes, err := h.config.GetIdentityID() if err != nil { From d2d0a305e9ff6407df28240eb8c874baf54f2139 Mon Sep 17 00:00:00 2001 From: Lucas Vogelsang Date: Tue, 11 Dec 2018 11:47:03 -0500 Subject: [PATCH 073/220] Spaces --- testworld/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testworld/README.md b/testworld/README.md index a00ee5d84..ed3c1e17a 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -2,13 +2,13 @@ `"CHAOS TAKES CONTROL. WELCOME TO THE NEW WORLD. WELCOME TO TESTWORLD"` -Testworld(loosely analogous to [Westworld](https://medium.com/@naveen101/westworld-an-introduction-cc7d29bfbe84) ;) is a simulation and test environment for centrifuge p2p network. +Testworld (loosely analogous to [Westworld](https://medium.com/@naveen101/westworld-an-introduction-cc7d29bfbe84) ;) is a simulation and test environment for centrifuge p2p network. Here you can create, run and test nodes with various behaviours to observe how they would behave and debug any problems encountered. ### Tutorial -- All hosts(p2p nodes) in the Testworld are created and maintained during simulation by drFord(`park.go#hostManager`). He also ensures that the hosts and tests are properly cleaned up after each simulation run. -- Bernard(`hostManager.bernard`) is a special host that serves as the libp2p bootnode for the test network. +- All hosts (p2p nodes) in the Testworld are created and maintained during simulation by drFord(`park.go#hostManager`). He also ensures that the hosts and tests are properly cleaned up after each simulation run. +- Bernard (`hostManager.bernard`) is a special host that serves as the libp2p bootnode for the test network. - `hostConfig` serves as the starting point for you to define new hosts. Please check whether an existing host can be reused for your scenario before adding new ones. - At the start of the each test run a test config is loaded for the required Ethereum network(eg: Rinkeby or local). The host configs are defined based on this. - The test initialisation also ensures that geth is running in the background and required smart contracts are migrated for the network. From 230edda14ebb5acb1f4fa781fed72ef921d1bcb9 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 11 Dec 2018 17:59:22 +0100 Subject: [PATCH 074/220] added integration tests for NFT (#555) * added NFT successful test case to integration tests * added error tests for NFT --- testworld/httputils.go | 11 +++++ testworld/nft_test.go | 102 +++++++++++++++++++++++++++++++++++++++++ testworld/park.go | 4 ++ testworld/payloads.go | 16 +++++++ 4 files changed, 133 insertions(+) create mode 100644 testworld/nft_test.go diff --git a/testworld/httputils.go b/testworld/httputils.go index 66ca2841b..01da7f820 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -59,6 +59,17 @@ func getDocumentIdentifier(t *testing.T, response *httpexpect.Object) string { return docIdentifier } +func mintNFT(e *httpexpect.Expect, httpStatus int, payload map[string]interface{}) *httpexpect.Object { + resp := e.POST("/token/mint"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + WithJSON(payload). + Expect().Status(httpStatus) + + httpObj := resp.JSON().Object() + return httpObj +} + func createInsecureClient() *http.Client { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, diff --git a/testworld/nft_test.go b/testworld/nft_test.go new file mode 100644 index 000000000..e8aaa4316 --- /dev/null +++ b/testworld/nft_test.go @@ -0,0 +1,102 @@ +// +build testworld + +package testworld + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +const tokenIdLength = 77 + +func TestPaymentObligationMint_successful(t *testing.T) { + + alice := doctorFord.getHostTestSuite(t, "Alice") + bob := doctorFord.getHostTestSuite(t, "Bob") + + // Alice shares invoice document with Bob + res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultNFTPayload([]string{bob.id.String()})) + if err != nil { + t.Error(err) + } + + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + + params := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "USD", + } + getInvoiceAndCheck(alice.httpExpect, params) + getInvoiceAndCheck(bob.httpExpect, params) + + // mint an NFT + test := struct { + httpStatus int + payload map[string]interface{} + }{ + http.StatusOK, + map[string]interface{}{ + + "identifier": docIdentifier, + "registryAddress": doctorFord.contractAddresses.PaymentObligationAddr, + "depositAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", // dummy address + "proofFields": []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, + }, + } + + response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + assert.Nil(t, err, "mintNFT should be successful") + assert.True(t, len(response.Value("token_id").String().Raw()) >= tokenIdLength, "successful tokenId should have length 77") + +} + +func TestPaymentObligationMint_errors(t *testing.T) { + alice := doctorFord.getHostTestSuite(t, "Alice") + + tests := []struct { + errorMsg string + httpStatus int + payload map[string]interface{} + }{ + { + "RegistryAddress is not a valid Ethereum address", + http.StatusInternalServerError, + map[string]interface{}{ + + "registryAddress": "0x123", + }, + }, + { + "DepositAddress is not a valid Ethereum address", + http.StatusInternalServerError, + map[string]interface{}{ + + "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address + "depositAddress": "abc", + }, + }, + { + "no service exists for provided documentID", + http.StatusInternalServerError, + map[string]interface{}{ + + "identifier": "0x12121212", + "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address + "depositAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address + }, + }, + } + + for _, test := range tests { + response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + assert.Nil(t, err, "it should be possible to call the API endpoint") + response.Value("message").String().Contains(test.errorMsg) + + } + +} diff --git a/testworld/park.go b/testworld/park.go index 6c40d3cb0..d001b4309 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -331,6 +331,10 @@ func (h *host) createInvoice(e *httpexpect.Expect, status int, inv map[string]in return createInvoice(e, status, inv), nil } +func (h *host) mintNFT(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { + return mintNFT(e, status, inv), nil +} + func (h *host) updateInvoice(e *httpexpect.Expect, status int, docIdentifier string, inv map[string]interface{}) (*httpexpect.Object, error) { return updateInvoice(e, status, docIdentifier, inv), nil } diff --git a/testworld/payloads.go b/testworld/payloads.go index 8e0a24821..a79d27580 100644 --- a/testworld/payloads.go +++ b/testworld/payloads.go @@ -17,6 +17,22 @@ func defaultInvoicePayload(collaborators []string) map[string]interface{} { } +func defaultNFTPayload(collaborators []string) map[string]interface{} { + + return map[string]interface{}{ + "data": map[string]interface{}{ + "invoice_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "USD", + "net_amount": "40", + "document_type": "invoice", + }, + "collaborators": collaborators, + } + +} + func updatedInvoicePayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ From 1d99d70f1a3a8f73d5f15c18539aeb0d217b6e7f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 11 Dec 2018 19:35:56 +0100 Subject: [PATCH 075/220] Migrate documents package to use new errors (#553) * Migrate documents package to use new errors * typeerror -> typederror * Fix failing tests * Fix fmt errors * Fix error name * Fix error name --- centerrors/error.go | 11 +- coredocument/processor.go | 5 +- coredocument/validator.go | 27 +++-- coredocument/validator_test.go | 24 ++-- documents/anchor.go | 17 +-- documents/error.go | 139 +++++++--------------- documents/error_test.go | 82 ------------- documents/handler.go | 4 +- documents/invoice/handler.go | 28 +++-- documents/invoice/model.go | 10 +- documents/invoice/service.go | 80 ++++++------- documents/invoice/service_test.go | 25 ++-- documents/invoice/validator.go | 3 +- documents/invoice/validator_test.go | 8 +- documents/leveldb.go | 28 +++++ documents/purchaseorder/handler.go | 28 +++-- documents/purchaseorder/service.go | 82 ++++++------- documents/purchaseorder/service_test.go | 27 +++-- documents/purchaseorder/validator.go | 7 +- documents/purchaseorder/validator_test.go | 8 +- documents/repository.go | 22 ---- documents/validator.go | 7 +- documents/validator_test.go | 38 +++--- errors/errors.go | 50 ++++---- errors/errors_test.go | 8 +- p2p/handler_test.go | 5 +- p2p/validator.go | 8 +- 27 files changed, 343 insertions(+), 438 deletions(-) delete mode 100644 documents/error_test.go diff --git a/centerrors/error.go b/centerrors/error.go index 8ccb07cc9..91c6d8a56 100644 --- a/centerrors/error.go +++ b/centerrors/error.go @@ -11,18 +11,23 @@ import ( const ( // RequiredField error when required field is empty + // Deprecated: in favour of error types in each package RequiredField = "Required field" // NilDocument error when document passed is Nil + // Deprecated: in favour of error types in each package NilDocument = "Nil document" // IdentifierReUsed error when same identifier is re-used + // Deprecated: in favour of error types in each package IdentifierReUsed = "Identifier re-used" // NilDocumentData error when document data is Nil + // Deprecated: in favour of error types in each package NilDocumentData = "Nil document data" // RequirePositiveNumber error when amount or any such is zero or negative + // Deprecated: in favour of error types in each package RequirePositiveNumber = "Require positive number" ) @@ -45,7 +50,7 @@ func New(code code.Code, message string) error { } // NewWithErrors constructs a new error with code, error message, and errors -func NewWithErrors(c code.Code, message string, errors map[string]string) error { +func NewWithErrors(c code.Code, message string, errs map[string]string) error { if c == code.Ok { return nil } @@ -53,7 +58,7 @@ func NewWithErrors(c code.Code, message string, errors map[string]string) error return &errpb{ Code: int32(c), Message: message, - Errors: errors, + Errors: errs, } } @@ -106,12 +111,14 @@ func (p2pErr *P2PError) Errors() map[string]string { } // NilError returns error with Type added to message +// Deprecated: in favour of functions in `github.com/centrifuge/go-centrifuge/errors` func NilError(param interface{}) error { return errors.Errorf("NIL %v provided", reflect.TypeOf(param)) } // Wrap appends msg to errpb.Message if it is of type *errpb // else appends the msg to error through fmt.Errorf +// Deprecated: this is intended for use within p2p or api handlers only, For services and internal errors use the Error type defined in `github.com/centrifuge/go-centrifuge/errors` func Wrap(err error, msg string) error { if err == nil { return fmt.Errorf(msg) diff --git a/coredocument/processor.go b/coredocument/processor.go index 8b99a3219..ffd74b77a 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -11,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" @@ -259,13 +260,13 @@ func (dp defaultProcessor) SendDocument(ctx *header.ContextHeader, model documen for _, c := range extCollaborators { cID, erri := identity.ToCentID(c) if erri != nil { - err = documents.AppendError(err, erri) + err = errors.AppendError(err, erri) continue } erri = dp.Send(ctx, cd, cID) if erri != nil { - err = documents.AppendError(err, erri) + err = errors.AppendError(err, erri) } } diff --git a/coredocument/validator.go b/coredocument/validator.go index 0d6e76214..b16830edb 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" @@ -61,17 +62,17 @@ func UpdateVersionValidator() documents.Validator { for _, c := range checks { if !utils.CheckMultiple32BytesFilled(c.a, c.b) { - err = documents.AppendError(err, documents.NewError(c.name, "missing identifiers")) + err = errors.AppendError(err, documents.NewError(c.name, "missing identifiers")) continue } if !utils.IsSameByteSlice(c.a, c.b) { - err = documents.AppendError(err, documents.NewError(c.name, "mismatched")) + err = errors.AppendError(err, documents.NewError(c.name, "mismatched")) } } if utils.IsEmptyByteSlice(newCD.NextVersion) { - err = documents.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) } return err @@ -105,19 +106,19 @@ func baseValidator() documents.Validator { } if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { - err = documents.AppendError(err, documents.NewError("cd_identifier", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_identifier", centerrors.RequiredField)) } if utils.IsEmptyByteSlice(cd.CurrentVersion) { - err = documents.AppendError(err, documents.NewError("cd_current_version", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_current_version", centerrors.RequiredField)) } if utils.IsEmptyByteSlice(cd.NextVersion) { - err = documents.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) } if utils.IsEmptyByteSlice(cd.DataRoot) { - err = documents.AppendError(err, documents.NewError("cd_data_root", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_data_root", centerrors.RequiredField)) } // double check the identifiers @@ -126,7 +127,7 @@ func baseValidator() documents.Validator { // Problem (re-using an old identifier for NextVersion): CurrentVersion or DocumentIdentifier same as NextVersion if isSameBytes(cd.NextVersion, cd.DocumentIdentifier) || isSameBytes(cd.NextVersion, cd.CurrentVersion) { - err = documents.AppendError(err, documents.NewError("cd_overall", centerrors.IdentifierReUsed)) + err = errors.AppendError(err, documents.NewError("cd_overall", centerrors.IdentifierReUsed)) } // lets not do verbose check like earlier since these will be @@ -138,7 +139,7 @@ func baseValidator() documents.Validator { salts.NextVersion, salts.DocumentIdentifier, salts.PreviousRoot) { - err = documents.AppendError(err, documents.NewError("cd_salts", centerrors.RequiredField)) + err = errors.AppendError(err, documents.NewError("cd_salts", centerrors.RequiredField)) } return err @@ -215,15 +216,15 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) documents.Valida s := signatures.Sign(centIDBytes, priv, pub, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { - err = documents.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) + err = errors.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) } if !utils.IsSameByteSlice(s.PublicKey, sh.PublicKey) { - err = documents.AppendError(err, documents.NewError("cd_public_key", "public key mismatch")) + err = errors.AppendError(err, documents.NewError("cd_public_key", "public key mismatch")) } if !utils.IsSameByteSlice(s.Signature, sh.Signature) { - err = documents.AppendError(err, documents.NewError("cd_signature", "signature mismatch")) + err = errors.AppendError(err, documents.NewError("cd_signature", "signature mismatch")) } return err @@ -247,7 +248,7 @@ func signaturesValidator(idService identity.Service) documents.Validator { for _, sig := range cd.Signatures { if erri := idService.ValidateSignature(sig, cd.SigningRoot); erri != nil { - err = documents.AppendError( + err = errors.AppendError( err, documents.NewError( fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 975ede063..6dc80d751 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -6,14 +6,12 @@ import ( "fmt" "testing" - "errors" - "context" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -60,7 +58,7 @@ func TestUpdateVersionValidator(t *testing.T) { old.AssertExpectations(t) new.AssertExpectations(t) assert.Error(t, err) - assert.Len(t, documents.ConvertToMap(err), 4) + assert.Equal(t, 5, errors.Len(err)) // success newCD, err = PrepareNewVersion(*oldCD, nil) @@ -113,7 +111,7 @@ func TestValidator_baseValidator(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Once() err = bv.Validate(nil, model) assert.Error(t, err) - assert.Contains(t, err.Error(), "cd_salts : Required field") + assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[1].Error()) // success model = mockModel{} @@ -244,7 +242,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) - assert.Len(t, documents.ConvertToMap(err), 3) + assert.Equal(t, 3, errors.Len(err)) // success cd.SigningRoot = utils.RandomSlice(32) @@ -403,7 +401,7 @@ func TestValidate_baseValidator(t *testing.T) { NextVersion: id4, DataRoot: id5, }, - key: "cd_salts", + key: "[cd_salts : Required field]", }, // salts missing previous root @@ -421,7 +419,7 @@ func TestValidate_baseValidator(t *testing.T) { DataRoot: id4, }, }, - key: "cd_salts", + key: "[cd_salts : Required field]", }, // missing identifiers in core document @@ -439,7 +437,7 @@ func TestValidate_baseValidator(t *testing.T) { PreviousRoot: id5, }, }, - key: "cd_data_root", + key: "[cd_data_root : Required field]", }, // missing identifiers in core document and salts @@ -456,7 +454,7 @@ func TestValidate_baseValidator(t *testing.T) { DataRoot: id4, }, }, - key: "cd_data_root", + key: "[cd_data_root : Required field; cd_salts : Required field]", }, // repeated identifiers @@ -475,7 +473,7 @@ func TestValidate_baseValidator(t *testing.T) { PreviousRoot: id5, }, }, - key: "cd_overall", + key: "[cd_overall : Identifier re-used]", }, // repeated identifiers @@ -494,7 +492,7 @@ func TestValidate_baseValidator(t *testing.T) { PreviousRoot: id5, }, }, - key: "cd_overall", + key: "[cd_overall : Identifier re-used]", }, // All okay @@ -529,7 +527,7 @@ func TestValidate_baseValidator(t *testing.T) { continue } - assert.Contains(t, err.Error(), c.key) + assert.Equal(t, c.key, err.Error()) } } diff --git a/documents/anchor.go b/documents/anchor.go index 0a70867fd..8c1646382 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -3,6 +3,7 @@ package documents import ( "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" ) @@ -31,7 +32,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor id := cd.CurrentVersion err = proc.PrepareForSignatureRequests(ctx, model) if err != nil { - return nil, fmt.Errorf("failed to prepare document for signatures: %v", err) + return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to prepare document for signatures: %v", err)) } err = updater(id, model) @@ -41,17 +42,17 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.RequestSignatures(ctx, model) if err != nil { - return nil, fmt.Errorf("failed to collect signatures: %v", err) + return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to collect signatures: %v", err)) } err = updater(id, model) if err != nil { - return nil, err + return nil, errors.NewTypedError(ErrDocumentAnchoring, err) } err = proc.PrepareForAnchoring(model) if err != nil { - return nil, fmt.Errorf("failed to prepare for anchoring: %v", err) + return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to prepare for anchoring: %v", err)) } err = updater(id, model) @@ -61,22 +62,22 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.AnchorDocument(ctx, model) if err != nil { - return nil, fmt.Errorf("failed to anchor document: %v", err) + return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to anchor document: %v", err)) } err = updater(id, model) if err != nil { - return nil, err + return nil, errors.NewTypedError(ErrDocumentAnchoring, err) } err = proc.SendDocument(ctx, model) if err != nil { - return nil, fmt.Errorf("failed to send anchored document: %v", err) + return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to send anchored document: %v", err)) } err = updater(id, model) if err != nil { - return nil, err + return nil, errors.NewTypedError(ErrDocumentAnchoring, err) } return model, nil diff --git a/documents/error.go b/documents/error.go index 35a7e2822..6e95df30a 100644 --- a/documents/error.go +++ b/documents/error.go @@ -1,122 +1,71 @@ package documents import ( - "bytes" "fmt" - "github.com/hashicorp/go-multierror" + "github.com/centrifuge/go-centrifuge/errors" ) -// Error wraps an error with specific key -type Error struct { - key string - err error -} +const ( -// Error returns the underlying error message -func (e Error) Error() string { - return e.err.Error() -} + // ErrDocumentIdentifier must be used for errors caused by document identifier problems + ErrDocumentIdentifier = errors.Error("document identifier error") -// NewError creates a new error from a key and a msg. -func NewError(key, msg string) error { - err := fmt.Errorf(msg) - return Error{key: key, err: err} -} + // ErrDocumentInvalidType must be used when a provided document type is not valid to be processed by the service + ErrDocumentInvalidType = errors.Error("document is of invalid type") -// AppendError function is used to create a list of errors. -// First argument can be nil, a multierror.Error, or any other error -func AppendError(dstErr, srcErr error) error { - _, ok := dstErr.(*multierror.Error) - result := multierror.Append(dstErr, srcErr) - - // if dstErr is not a multierror.Error newly created multierror.Error result needs formatting - if !ok { - return format(result) - } - return result -} + // ErrDocumentNil must be used when the provided document through a function is nil + ErrDocumentNil = errors.Error("no(nil) document provided") -func format(err *multierror.Error) error { - err.ErrorFormat = func(errorList []error) string { - var buffer bytes.Buffer - for i, err := range errorList { - if errt, ok := err.(Error); ok { - buffer.WriteString(fmt.Sprintf("%s : %s\n", errt.key, errt.err.Error())) - continue - } + // ErrDocumentInvalid must only be used when the reason for invalidity is impossible to determine or the invalidity is caused by validation errors + ErrDocumentInvalid = errors.Error("document is invalid") - buffer.WriteString(fmt.Sprintf("Error %v : %s\n", i+1, err.Error())) - } + // ErrDocumentNotFound must be used to indicate that the document for provided id is not found in the system + ErrDocumentNotFound = errors.Error("document not found in the system database") - buffer.WriteString(fmt.Sprintf("Total Errors: %v\n", len(errorList))) - return buffer.String() - } + // ErrDocumentVersionNotFound must be used to indicate that the specified version of the document for provided id is not found in the system + ErrDocumentVersionNotFound = errors.Error("specified version of the document not found in the system database") - return err -} + // ErrDocumentPersistence must be used when creating or updating a document in the system database failed + ErrDocumentPersistence = errors.Error("error encountered when storing document in the system database") -// Errors returns an array of errors -func Errors(err error) []error { - if err == nil { - return nil - } + // ErrDocumentPackingCoreDocument must be used when packing of core document for the given document failed + ErrDocumentPackingCoreDocument = errors.Error("core document packing failed") - if multiErr, ok := err.(*multierror.Error); ok { - return multiErr.Errors - } + // ErrDocumentUnPackingCoreDocument must be used when unpacking of core document for the given document failed + ErrDocumentUnPackingCoreDocument = errors.Error("core document unpacking failed") - return []error{err} -} + // ErrDocumentPrepareCoreDocument must be used when preparing a new core document fails for the given document + ErrDocumentPrepareCoreDocument = errors.Error("core document preparation failed") -// LenError returns the amount of embedded errors. -func LenError(err error) int { + // ErrDocumentSigning must be used when document signing related functionality fails + ErrDocumentSigning = errors.Error("document signing failed") - if err == nil { - return 0 - } + // ErrDocumentAnchoring must be used when document anchoring fails + ErrDocumentAnchoring = errors.Error("document anchoring failed") - if multiErr, ok := err.(*multierror.Error); ok { + // ErrDocumentCollaborator must be used when there is an error in processing collaborators + ErrDocumentCollaborator = errors.Error("document collaborator issue") - return multiErr.Len() - } - return 1 + // ErrDocumentProof must be used when document proof creation fails + ErrDocumentProof = errors.Error("document proof error") +) +// Error wraps an error with specific key +// Deprecated: in favour of Error type in `github.com/centrifuge/go-centrifuge/errors` +type Error struct { + key string + err error } -func addToMap(errorMap map[string]string, key, msg string) map[string]string { - if errorMap[key] != "" { - errorMap[key] = fmt.Sprintf("%s\n%s", errorMap[key], msg) - - } else { - errorMap[key] = msg - - } - return errorMap +// Error returns the underlying error message +func (e Error) Error() string { + return fmt.Sprintf("%s : %s", e.key, e.err) } -// ConvertToMap converts errors into a map. -func ConvertToMap(err error) map[string]string { - - errorMap := make(map[string]string) - var key string - var standardErrorCounter int - - errors := Errors(err) - - for _, err := range errors { - if err, ok := err.(Error); ok { - key = err.key - - } else { - standardErrorCounter++ - key = fmt.Sprintf("error_%v", standardErrorCounter) - - } - - addToMap(errorMap, key, err.Error()) - - } - return errorMap - +// NewError creates a new error from a key and a msg. +// Deprecated: in favour of Error type in `github.com/centrifuge/go-centrifuge/errors` +func NewError(key, msg string) error { + err := fmt.Errorf(msg) + return Error{key: key, err: err} } diff --git a/documents/error_test.go b/documents/error_test.go deleted file mode 100644 index 7f0d4393a..000000000 --- a/documents/error_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// +build unit - -package documents - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNewError(t *testing.T) { - - err := NewError("test_error", "error msg") - assert.Error(t, err, "New should return an error") -} - -func TestAppendError(t *testing.T) { - - err := fmt.Errorf("test error") - - err = AppendError(nil, err) - assert.Equal(t, 1, LenError(err), "err should only include one error") - - err = AppendError(err, fmt.Errorf("second error")) - assert.Equal(t, 2, LenError(err), "err should include two errors") - assert.Equal(t, 2, len(Errors(err)), "returned error array should include two errors") - - err = AppendError(fmt.Errorf("err 1"), fmt.Errorf("err 2")) - assert.Equal(t, 2, LenError(err), "err should include two errors") - - err = AppendError(err, NewError("test", "error")) - assert.Len(t, Errors(err), 3) - assert.Contains(t, err.Error(), "test : error") -} - -func TestLenError(t *testing.T) { - - err := fmt.Errorf("test error") - - assert.Equal(t, 0, LenError(nil), "nil should return len 0") - assert.Equal(t, 1, LenError(err), "normal error should have length 1") - -} - -func TestErrors(t *testing.T) { - - err := AppendError(fmt.Errorf("err 1"), fmt.Errorf("err 2")) - errArray := Errors(err) - assert.Equal(t, 2, len(errArray), "array should contain two errors") - - errArray = Errors(fmt.Errorf("err 1")) - assert.Equal(t, 1, len(errArray), "array should contain one errors") - - errArray = Errors(nil) - assert.Equal(t, 0, len(errArray), "array should be nil") - -} - -func TestConvertToMap(t *testing.T) { - - err := NewError("test1", "error msg") - - err = AppendError(err, NewError("test2", "error msg2")) - - errMap := ConvertToMap(err) - assert.Equal(t, 2, len(errMap), "map should have two entries") - - err = AppendError(err, fmt.Errorf("standard error")) - err = AppendError(err, fmt.Errorf("standard error2")) - errMap = ConvertToMap(err) - assert.Equal(t, 4, len(errMap), "map should have 4 entries") - - assert.NotEqual(t, "", errMap["error_1"], "first standard error should have id 'error_1'") - assert.Equal(t, "", errMap["error_3"], "no standard error with id 'error_3'") - - errMap = ConvertToMap(nil) - assert.Equal(t, 0, len(errMap), "map should be empty") - - fmt.Print(errMap) - -} diff --git a/documents/handler.go b/documents/handler.go index ec011a31e..3d7519122 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -29,7 +29,7 @@ func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProo service, err := h.registry.LocateService(createDocumentProofEnvelope.Type) if err != nil { - return &documentpb.DocumentProof{}, err + return &documentpb.DocumentProof{}, centerrors.Wrap(err, "could not locate service for document type") } identifier, err := hexutil.Decode(createDocumentProofEnvelope.Identifier) @@ -50,7 +50,7 @@ func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDo service, err := h.registry.LocateService(createDocumentProofForVersionEnvelope.Type) if err != nil { - return &documentpb.DocumentProof{}, err + return &documentpb.DocumentProof{}, centerrors.Wrap(err, "could not locate service for document type") } identifier, err := hexutil.Decode(createDocumentProofForVersionEnvelope.Identifier) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 3043c52e6..0cf9a091e 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -50,17 +50,23 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr doc, err := h.service.DeriveFromCreatePayload(req, ctxHeader) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive create payload") } // validate and persist doc, err = h.service.Create(ctxHeader, doc) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not create document") + } + + resp, err := h.service.DeriveInvoiceResponse(doc) + if err != nil { + apiLog.Error(err) + return nil, centerrors.Wrap(err, "could not derive response") } - return h.service.DeriveInvoiceResponse(doc) + return resp, nil } // Update handles the document update and anchoring @@ -75,16 +81,22 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi doc, err := h.service.DeriveFromUpdatePayload(payload, ctxHeader) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive update payload") } doc, err = h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not update document") + } + + resp, err := h.service.DeriveInvoiceResponse(doc) + if err != nil { + apiLog.Error(err) + return nil, centerrors.Wrap(err, "could not derive response") } - return h.service.DeriveInvoiceResponse(doc) + return resp, nil } // GetVersion returns the requested version of the document @@ -111,7 +123,7 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti resp, err := h.service.DeriveInvoiceResponse(model) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive response") } return resp, nil @@ -135,7 +147,7 @@ func (h *grpcHandler) Get(ctx context.Context, getRequest *clientinvoicepb.GetRe resp, err := h.service.DeriveInvoiceResponse(model) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive response") } return resp, nil diff --git a/documents/invoice/model.go b/documents/invoice/model.go index ed42d9b4e..01ac5f429 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -9,8 +9,8 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -202,7 +202,7 @@ func (i *Invoice) initInvoiceFromData(data *clientinvoicepb.InvoiceData) error { if data.ExtraData != "" { ed, err := hexutil.Decode(data.ExtraData) if err != nil { - return centerrors.Wrap(err, "failed to decode extra data") + return errors.NewTypedError(err, fmt.Errorf("failed to decode extra data")) } i.ExtraData = ed @@ -275,7 +275,7 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { invoiceData := i.createP2PProtobuf() serializedInvoice, err := proto.Marshal(invoiceData) if err != nil { - return nil, centerrors.Wrap(err, "couldn't serialise InvoiceData") + return nil, errors.NewTypedError(err, fmt.Errorf("couldn't serialise InvoiceData")) } invoiceAny := any.Any{ @@ -287,7 +287,7 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { serializedSalts, err := proto.Marshal(invoiceSalt) if err != nil { - return nil, centerrors.Wrap(err, "couldn't serialise InvoiceSalts") + return nil, errors.NewTypedError(err, fmt.Errorf("couldn't serialise InvoiceSalts")) } invoiceSaltsAny := any.Any{ @@ -305,7 +305,7 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { // UnpackCoreDocument unpacks the core document into Invoice func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error { if coreDoc == nil { - return centerrors.NilError(coreDoc) + return errors.New("core document provided is nil %v", coreDoc) } if coreDoc.EmbeddedData == nil || diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 162d20924..2ab543d54 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -9,11 +9,10 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" @@ -51,7 +50,7 @@ type Service interface { } // service implements Service and handles all invoice related persistence and validations -// service always returns errors of type `centerrors` with proper error code +// service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { repo documents.LegacyRepository coreDocProcessor coredocument.Processor @@ -89,15 +88,15 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str func (s service) invoiceProof(model documents.Model, fields []string) (*documents.DocumentProof, error) { inv, ok := model.(*Invoice) if !ok { - return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") + return nil, documents.ErrDocumentInvalidType } if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, inv); err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } coreDoc, proofs, err := inv.createProofs(fields) if err != nil { - return nil, err + return nil, errors.NewTypedError(documents.ErrDocumentProof, err) } return &documents.DocumentProof{ DocumentID: coreDoc.DocumentIdentifier, @@ -111,7 +110,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume var model documents.Model = new(Invoice) err := model.UnpackCoreDocument(cd) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } return model, nil @@ -120,13 +119,13 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { - return nil, centerrors.New(code.DocumentInvalid, "input is nil") + return nil, documents.ErrDocumentNil } invoiceModel := new(Invoice) err := invoiceModel.InitInvoiceInput(payload, contextHeader) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } return invoiceModel, nil @@ -136,25 +135,25 @@ func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreateP func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { inv, ok := new.(*Invoice) if !ok { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("unknown document type: %T", new)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, fmt.Errorf("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields err := inv.calculateDataRoot() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } // validate the invoice err = validator.Validate(old, inv) if err != nil { - return nil, centerrors.NewWithErrors(code.DocumentInvalid, "validations failed", documents.ConvertToMap(err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document err = s.repo.Create(inv.CoreDocument.CurrentVersion, inv) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } return inv, nil @@ -169,7 +168,7 @@ func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documen inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.repo.Update) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } return inv, nil @@ -179,12 +178,12 @@ func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documen func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { cd, err := inv.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(cd.DocumentIdentifier) if err != nil { - return nil, centerrors.New(code.DocumentNotFound, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } inv, err = s.calculateDataRoot(old, inv, UpdateValidator()) @@ -194,7 +193,7 @@ func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documen inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.repo.Update) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } return inv, nil @@ -204,7 +203,7 @@ func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documen func (s service) GetVersion(documentID []byte, version []byte) (doc documents.Model, err error) { inv, err := s.getInvoiceVersion(documentID, version) if err != nil { - return nil, centerrors.Wrap(err, "document not found for the given version") + return nil, err } return inv, nil } @@ -213,12 +212,13 @@ func (s service) GetVersion(documentID []byte, version []byte) (doc documents.Mo func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err error) { inv, err := s.getInvoiceVersion(documentID, documentID) if err != nil { - return nil, centerrors.Wrap(err, "document not found") + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } nextVersion := inv.CoreDocument.NextVersion for nextVersion != nil { temp, err := s.getInvoiceVersion(documentID, nextVersion) if err != nil { + // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration return inv, nil } @@ -232,15 +232,15 @@ func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, er var doc documents.Model = new(Invoice) err = s.repo.LoadByID(version, doc) if err != nil { - return nil, err + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } inv, ok := doc.(*Invoice) if !ok { - return nil, err + return nil, documents.ErrDocumentInvalidType } if !bytes.Equal(inv.CoreDocument.DocumentIdentifier, documentID) { - return nil, centerrors.New(code.DocumentInvalid, "version is not valid for this identifier") + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, fmt.Errorf("version is not valid for this identifier")) } return inv, nil } @@ -249,14 +249,14 @@ func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, er func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.InvoiceResponse, error) { cd, err := doc.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { cid, err := identity.ToCentID(c) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentCollaborator, err) } collaborators[i] = cid.String() } @@ -283,7 +283,7 @@ func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.In func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.InvoiceData, error) { inv, ok := doc.(*Invoice) if !ok { - return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") + return nil, documents.ErrDocumentInvalidType } return inv.getClientData(), nil @@ -292,37 +292,37 @@ func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.Invoic // DeriveFromUpdatePayload returns a new version of the old invoice identified by identifier in payload func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { - return nil, centerrors.New(code.DocumentInvalid, "invalid payload") + return nil, documents.ErrDocumentNil } // get latest old version of the document id, err := hexutil.Decode(payload.Identifier) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to decode identifier: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, fmt.Errorf("failed to decode identifier: %v", err)) } old, err := s.GetCurrentVersion(id) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to fetch old version: %v", err)) + return nil, err } // load invoice data inv := new(Invoice) err = inv.initInvoiceFromData(payload.Data) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to load invoice from data: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, fmt.Errorf("failed to load invoice from data: %v", err)) } // update core document oldCD, err := old.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) inv.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to prepare new version: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) } return inv, nil @@ -331,38 +331,38 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP // RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } doc, err := model.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] if !ok { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("missing signing key")) + return nil, errors.NewTypedError(documents.ErrDocumentSigning, fmt.Errorf("missing signing key")) } sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to Unpack CoreDocument: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { err = s.repo.Create(doc.DocumentIdentifier, model) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store local first version of the document: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } err = s.repo.Create(doc.CurrentVersion, model) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store document: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) @@ -372,17 +372,17 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m // ReceiveAnchoredDocument receives a new anchored document, validates and updates the document in DB func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return centerrors.New(code.DocumentInvalid, err.Error()) + return errors.NewTypedError(documents.ErrDocumentInvalid, err) } doc, err := model.PackCoreDocument() if err != nil { - return centerrors.New(code.DocumentInvalid, err.Error()) + return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } err = s.repo.Update(doc.CurrentVersion, model) if err != nil { - return centerrors.New(code.Unknown, err.Error()) + return errors.NewTypedError(documents.ErrDocumentPersistence, err) } ts, _ := ptypes.TimestampProto(time.Now().UTC()) diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 50a500389..d9f673d95 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -6,14 +6,13 @@ import ( "context" "fmt" "math/big" - "strconv" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -161,7 +160,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { assert.Nil(t, err) mod, err := invSrv.GetVersion(utils.RandomSlice(32), currentVersion) - assert.EqualError(t, err, "[4]document not found for the given version: version is not valid for this identifier") + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) assert.Nil(t, mod) } @@ -341,14 +340,14 @@ func TestService_CreateProofsInvalidField(t *testing.T) { idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) - assert.Equal(t, "createProofs error No such field: invalid_field in obj", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, invService := getServiceWithMockedLayers() _, err := invService.CreateProofs(utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) - assert.Equal(t, "document not found: leveldb: not found", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) } func TestService_CreateProofsForVersion(t *testing.T) { @@ -373,7 +372,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { assert.Nil(t, err) _, err = invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) - assert.Equal(t, "document not found for the given version: leveldb: not found", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { @@ -385,8 +384,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { ctxh, err := header.NewContextHeader(context.Background(), cfg) signature, err := invSrv.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) - assert.Contains(t, err.Error(), strconv.Itoa(int(code.DocumentInvalid))) - assert.Contains(t, err.Error(), "signing root missing") + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, signature) } @@ -488,13 +486,13 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // nil payload doc, err := invSrv.DeriveFromUpdatePayload(nil, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid payload") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // nil payload data doc, err = invSrv.DeriveFromUpdatePayload(&clientinvoicepb.InvoiceUpdatePayload{}, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid payload") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // messed up identifier @@ -503,6 +501,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentIdentifier, err)) assert.Contains(t, err.Error(), "failed to decode identifier") assert.Nil(t, doc) @@ -511,7 +510,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload.Identifier = hexutil.Encode(id) doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch old version") + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) assert.Nil(t, doc) // failed to load from data @@ -533,7 +532,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { } doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to load invoice from data") + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, doc) // failed core document new version @@ -541,7 +540,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload.Collaborators = []string{"some wrong ID"} doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to prepare new version") + assert.True(t, errors.IsOfType(documents.ErrDocumentPrepareCoreDocument, err)) assert.Nil(t, doc) // success diff --git a/documents/invoice/validator.go b/documents/invoice/validator.go index c012501eb..d01aa6aa8 100644 --- a/documents/invoice/validator.go +++ b/documents/invoice/validator.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" ) @@ -22,7 +23,7 @@ func fieldValidator() documents.Validator { var err error if !documents.IsCurrencyValid(inv.Currency) { - err = documents.AppendError(err, documents.NewError("inv_currency", "currency is invalid")) + err = errors.AppendError(err, documents.NewError("inv_currency", "currency is invalid")) } return err diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index c3eb2ab74..1b9aa63d6 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -9,7 +9,7 @@ import ( "context" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -22,21 +22,21 @@ func TestFieldValidator_Validate(t *testing.T) { // nil error err := fv.Validate(nil, nil) assert.Error(t, err) - errs := documents.Errors(err) + errs := errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be one") assert.Contains(t, errs[0].Error(), "nil document") // unknown type err = fv.Validate(nil, &mockModel{}) assert.Error(t, err) - errs = documents.Errors(err) + errs = errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be one") assert.Contains(t, errs[0].Error(), "unknown document type") // fail err = fv.Validate(nil, new(Invoice)) assert.Error(t, err) - errs = documents.Errors(err) + errs = errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be 2") assert.Contains(t, errs[0].Error(), "currency is invalid") diff --git a/documents/leveldb.go b/documents/leveldb.go index 65cbfb0e9..0de8b01c7 100644 --- a/documents/leveldb.go +++ b/documents/leveldb.go @@ -6,7 +6,35 @@ import ( "github.com/syndtr/goleveldb/leveldb" ) +// LegacyRepository should be implemented by any type that wants to store a document in key-value storage. +// Deprecated: Use the single collection DB -> `Repository` +type LegacyRepository interface { + // GetKey will prepare the the identifier key from ID + // Deprecated: Use the single collection DB functions -> `Repository` + GetKey(id []byte) (key []byte) + + // GetByID finds the doc with identifier and marshals it into message + // Deprecated: Use the single collection DB functions -> `Repository` + LoadByID(id []byte, model Model) error + + // Exists checks for document existence + // True if exists else false + // Deprecated: Use the single collection DB functions -> `Repository` + Exists(id []byte) bool + + // Create stores the initial document + // If document exist, it errors out + // Deprecated: Use the single collection DB functions -> `Repository` + Create(id []byte, model Model) error + + // Update updates the already stored document + // errors out when document is missing + // Deprecated: Use the single collection DB functions -> `Repository` + Update(id []byte, model Model) error +} + // LevelDBRepository is implements repository +// Deprecated: in favour of `levelDBRepo` type LevelDBRepository struct { KeyPrefix string LevelDB *leveldb.DB diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 7db80a36b..51cea4a17 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -49,17 +49,23 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc doc, err := h.service.DeriveFromCreatePayload(req, ctxh) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive create payload") } // validate, persist, and anchor doc, err = h.service.Create(ctxh, doc) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not create document") } - return h.service.DerivePurchaseOrderResponse(doc) + resp, err := h.service.DerivePurchaseOrderResponse(doc) + if err != nil { + apiLog.Error(err) + return nil, centerrors.Wrap(err, "could not derive response") + } + + return resp, nil } // Update handles the document update and anchoring @@ -74,16 +80,22 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. doc, err := h.service.DeriveFromUpdatePayload(payload, ctxHeader) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive update payload") } doc, err = h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not update document") } - return h.service.DerivePurchaseOrderResponse(doc) + resp, err := h.service.DerivePurchaseOrderResponse(doc) + if err != nil { + apiLog.Error(err) + return nil, centerrors.Wrap(err, "could not derive response") + } + + return resp, nil } // GetVersion returns the requested version of a purchase order @@ -110,7 +122,7 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. resp, err := h.service.DerivePurchaseOrderResponse(model) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive response") } return resp, nil @@ -134,7 +146,7 @@ func (h grpcHandler) Get(ctx context.Context, getRequest *clientpurchaseorderpb. resp, err := h.service.DerivePurchaseOrderResponse(model) if err != nil { apiLog.Error(err) - return nil, err + return nil, centerrors.Wrap(err, "could not derive response") } return resp, nil diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 487b60b7c..7dfdf340d 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -9,11 +9,10 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" @@ -51,7 +50,7 @@ type Service interface { } // service implements Service and handles all purchase order related persistence and validations -// service always returns errors of type `centerrors` with proper error code +// service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { repo documents.LegacyRepository coreDocProcessor coredocument.Processor @@ -70,7 +69,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume var model documents.Model = new(PurchaseOrder) err := model.UnpackCoreDocument(cd) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } return model, nil @@ -80,25 +79,25 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { po, ok := new.(*PurchaseOrder) if !ok { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("unknown document type: %T", new)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, fmt.Errorf("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields err := po.calculateDataRoot() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - // validate the purchase order + // validate the invoice err = validator.Validate(old, po) if err != nil { - return nil, centerrors.NewWithErrors(code.DocumentInvalid, "validations failed", documents.ConvertToMap(err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document err = s.repo.Create(po.CoreDocument.CurrentVersion, po) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } return po, nil @@ -113,7 +112,7 @@ func (s service) Create(ctx *header.ContextHeader, po documents.Model) (document po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.repo.Update) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } return po, nil @@ -123,12 +122,12 @@ func (s service) Create(ctx *header.ContextHeader, po documents.Model) (document func (s service) Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { cd, err := po.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(cd.DocumentIdentifier) if err != nil { - return nil, centerrors.New(code.DocumentNotFound, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } po, err = s.calculateDataRoot(old, po, UpdateValidator()) @@ -138,7 +137,7 @@ func (s service) Update(ctx *header.ContextHeader, po documents.Model) (document po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.repo.Update) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } return po, nil @@ -147,13 +146,13 @@ func (s service) Update(ctx *header.ContextHeader, po documents.Model) (document // DeriveFromCreatePayload derives purchase order from create payload func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { - return nil, centerrors.New(code.DocumentInvalid, "input is nil") + return nil, documents.ErrDocumentNil } po := new(PurchaseOrder) err := po.InitPurchaseOrderInput(payload, ctxH) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("purchase order init failed: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } return po, nil @@ -162,37 +161,37 @@ func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreate // DeriveFromUpdatePayload derives purchase order from update payload func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *header.ContextHeader) (documents.Model, error) { if payload == nil || payload.Data == nil { - return nil, centerrors.New(code.DocumentInvalid, "invalid payload") + return nil, documents.ErrDocumentNil } // get latest old version of the document id, err := hexutil.Decode(payload.Identifier) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to decode identifier: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, fmt.Errorf("failed to decode identifier: %v", err)) } old, err := s.GetCurrentVersion(id) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to fetch old version: %v", err)) + return nil, err } // load purchase order data po := new(PurchaseOrder) err = po.initPurchaseOrderFromData(payload.Data) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to load purchase order from data: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, fmt.Errorf("failed to load purchase order from data: %v", err)) } // update core document oldCD, err := old.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } collaborators := append([]string{ctxH.Self().ID.String()}, payload.Collaborators...) po.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, fmt.Sprintf("failed to prepare new version: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) } return po, nil @@ -202,7 +201,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdate func (s service) DerivePurchaseOrderData(doc documents.Model) (*clientpopb.PurchaseOrderData, error) { po, ok := doc.(*PurchaseOrder) if !ok { - return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") + return nil, documents.ErrDocumentInvalidType } return po.getClientData(), nil @@ -212,14 +211,14 @@ func (s service) DerivePurchaseOrderData(doc documents.Model) (*clientpopb.Purch func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.PurchaseOrderResponse, error) { cd, err := doc.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { cid, err := identity.ToCentID(c) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentCollaborator, err) } collaborators[i] = cid.String() } @@ -245,15 +244,15 @@ func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *Pur var doc documents.Model = new(PurchaseOrder) err = s.repo.LoadByID(version, doc) if err != nil { - return nil, err + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } model, ok := doc.(*PurchaseOrder) if !ok { - return nil, err + return nil, documents.ErrDocumentInvalidType } if !bytes.Equal(model.CoreDocument.DocumentIdentifier, documentID) { - return nil, centerrors.New(code.DocumentInvalid, "version is not valid for this identifier") + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, fmt.Errorf("version is not valid for this identifier")) } return model, nil } @@ -262,12 +261,13 @@ func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *Pur func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { model, err := s.getPurchaseOrderVersion(documentID, documentID) if err != nil { - return nil, centerrors.Wrap(err, "document not found") + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } nextVersion := model.CoreDocument.NextVersion for nextVersion != nil { temp, err := s.getPurchaseOrderVersion(documentID, nextVersion) if err != nil { + // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration return model, nil } @@ -281,7 +281,7 @@ func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, error) { po, err := s.getPurchaseOrderVersion(documentID, version) if err != nil { - return nil, centerrors.Wrap(err, "document not found for the given version") + return nil, err } return po, nil @@ -291,14 +291,14 @@ func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, func (s service) purchaseOrderProof(model documents.Model, fields []string) (*documents.DocumentProof, error) { po, ok := model.(*PurchaseOrder) if !ok { - return nil, centerrors.New(code.DocumentInvalid, "document of invalid type") + return nil, documents.ErrDocumentInvalidType } if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, po); err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } coreDoc, proofs, err := po.createProofs(fields) if err != nil { - return nil, err + return nil, errors.NewTypedError(documents.ErrDocumentProof, err) } return &documents.DocumentProof{ DocumentID: coreDoc.DocumentIdentifier, @@ -330,38 +330,38 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str // will remove this once we have a common implementation for documents.Service func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } cd, err := model.PackCoreDocument() if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } srvLog.Infof("coredoc received %x with signing root %x", cd.DocumentIdentifier, cd.SigningRoot) idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] if !ok { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("missing signing key")) + return nil, errors.NewTypedError(documents.ErrDocumentSigning, fmt.Errorf("missing signing key")) } sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to Unpack CoreDocument: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { err = s.repo.Create(cd.DocumentIdentifier, model) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store local first version of the document: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } err = s.repo.Create(cd.CurrentVersion, model) if err != nil { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to store document: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } srvLog.Infof("signed coredoc %x with version %x", cd.DocumentIdentifier, cd.CurrentVersion) @@ -373,17 +373,17 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m // will remove this once we have a common implementation for documents.Service func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return centerrors.New(code.DocumentInvalid, err.Error()) + return errors.NewTypedError(documents.ErrDocumentInvalid, err) } doc, err := model.PackCoreDocument() if err != nil { - return centerrors.New(code.DocumentInvalid, err.Error()) + return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } err = s.repo.Update(doc.CurrentVersion, model) if err != nil { - return centerrors.New(code.Unknown, err.Error()) + return errors.NewTypedError(documents.ErrDocumentPersistence, err) } ts, _ := ptypes.TimestampProto(time.Now().UTC()) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index ba33648a7..46284820d 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -132,13 +133,13 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // nil payload doc, err := poSrv.DeriveFromUpdatePayload(nil, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid payload") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // nil payload data doc, err = poSrv.DeriveFromUpdatePayload(&clientpurchaseorderpb.PurchaseOrderUpdatePayload{}, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid payload") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // messed up identifier @@ -155,7 +156,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload.Identifier = hexutil.Encode(id) doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch old version") + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) assert.Nil(t, doc) // failed to load from data @@ -183,7 +184,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload.Collaborators = []string{"some wrong ID"} doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to prepare new version") + assert.True(t, errors.IsOfType(documents.ErrDocumentPrepareCoreDocument, err)) assert.Nil(t, doc) // success @@ -215,13 +216,13 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { m, err := poSrv.DeriveFromCreatePayload(nil, ctxh) assert.Nil(t, m) assert.Error(t, err) - assert.Contains(t, err.Error(), "input is nil") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) // nil data payload m, err = poSrv.DeriveFromCreatePayload(&clientpurchaseorderpb.PurchaseOrderCreatePayload{}, ctxh) assert.Nil(t, m) assert.Error(t, err) - assert.Contains(t, err.Error(), "input is nil") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) // Init fails payload := &clientpurchaseorderpb.PurchaseOrderCreatePayload{ @@ -233,7 +234,7 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { m, err = poSrv.DeriveFromCreatePayload(payload, ctxh) assert.Nil(t, m) assert.Error(t, err) - assert.Contains(t, err.Error(), "purchase order init failed") + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) // success payload.Data.ExtraData = "0x01020304050607" @@ -414,14 +415,14 @@ func TestService_CreateProofsInvalidField(t *testing.T) { idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) - assert.Equal(t, "createProofs error No such field: invalid_field in obj", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, poSrv := getServiceWithMockedLayers() _, err := poSrv.CreateProofs(utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) - assert.Equal(t, "document not found: leveldb: not found", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) } func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseOrder, error) { @@ -482,7 +483,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { assert.Nil(t, err) _, err = poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) - assert.Equal(t, "document not found for the given version: leveldb: not found", err.Error()) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } func TestService_DerivePurchaseOrderData(t *testing.T) { @@ -496,7 +497,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { d, err := poSrv.DerivePurchaseOrderData(m) assert.Nil(t, d) assert.Error(t, err) - assert.Contains(t, err.Error(), "document of invalid type") + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalidType, err)) // success payload := testingdocuments.CreatePOPayload() @@ -540,7 +541,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { m.AssertExpectations(t) assert.Nil(t, r) assert.Error(t, err) - assert.Contains(t, err.Error(), "document of invalid type") + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalidType, err)) // success payload := testingdocuments.CreatePOPayload() @@ -616,7 +617,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { assert.Nil(t, err) mod, err := poSrv.GetVersion(utils.RandomSlice(32), currentVersion) - assert.EqualError(t, err, "[4]document not found for the given version: version is not valid for this identifier") + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) assert.Nil(t, mod) } diff --git a/documents/purchaseorder/validator.go b/documents/purchaseorder/validator.go index 0881a07e5..1ef2a35d5 100644 --- a/documents/purchaseorder/validator.go +++ b/documents/purchaseorder/validator.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" ) @@ -15,14 +16,14 @@ func fieldValidator() documents.Validator { return fmt.Errorf("nil document") } - inv, ok := new.(*PurchaseOrder) + po, ok := new.(*PurchaseOrder) if !ok { return fmt.Errorf("unknown document type") } var err error - if !documents.IsCurrencyValid(inv.Currency) { - err = documents.AppendError(err, documents.NewError("po_currency", "currency is invalid")) + if !documents.IsCurrencyValid(po.Currency) { + err = errors.AppendError(err, documents.NewError("po_currency", "currency is invalid")) } return err diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 4f39ab007..7271c28be 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -9,7 +9,7 @@ import ( "context" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -22,21 +22,21 @@ func TestFieldValidator_Validate(t *testing.T) { // nil error err := fv.Validate(nil, nil) assert.Error(t, err) - errs := documents.Errors(err) + errs := errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be one") assert.Contains(t, errs[0].Error(), "nil document") // unknown type err = fv.Validate(nil, &testingdocuments.MockModel{}) assert.Error(t, err) - errs = documents.Errors(err) + errs = errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be one") assert.Contains(t, errs[0].Error(), "unknown document type") // fail err = fv.Validate(nil, new(PurchaseOrder)) assert.Error(t, err) - errs = documents.Errors(err) + errs = errors.GetErrs(err) assert.Len(t, errs, 1, "errors length must be 2") assert.Contains(t, errs[0].Error(), "currency is invalid") diff --git a/documents/repository.go b/documents/repository.go index d0c73d625..6c81c3fed 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -9,28 +9,6 @@ import ( "github.com/syndtr/goleveldb/leveldb" ) -// LegacyRepository should be implemented by any type that wants to store a document in key-value storage. -// Deprecated: Use the single collection DB. -type LegacyRepository interface { - // GetKey will prepare the the identifier key from ID - GetKey(id []byte) (key []byte) - - // GetByID finds the doc with identifier and marshals it into message - LoadByID(id []byte, model Model) error - - // Exists checks for document existence - // True if exists else false - Exists(id []byte) bool - - // Create stores the initial document - // If document exist, it errors out - Create(id []byte, model Model) error - - // Update updates the already stored document - // errors out when document is missing - Update(id []byte, model Model) error -} - // Repository defines the required methods for a document repository. // Can be implemented by any type that stores the documents. Ex: levelDB, sql etc... type Repository interface { diff --git a/documents/validator.go b/documents/validator.go index df04de457..d2256d06e 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -1,6 +1,7 @@ package documents import ( + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" ) @@ -14,14 +15,14 @@ type Validator interface { type ValidatorGroup []Validator //Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(oldState Model, newState Model) (errors error) { +func (group ValidatorGroup) Validate(oldState Model, newState Model) (errs error) { for _, v := range group { if err := v.Validate(oldState, newState); err != nil { - errors = AppendError(errors, err) + errs = errors.AppendError(errs, err) } } - return errors + return errs } // IsCurrencyValid checks if the currency is of length 3 diff --git a/documents/validator_test.go b/documents/validator_test.go index 5759f60f3..bad7395b8 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -6,6 +6,7 @@ import ( "fmt" "testing" + "github.com/centrifuge/go-centrifuge/errors" "github.com/stretchr/testify/assert" ) @@ -20,7 +21,7 @@ type MockValidatorWithErrors struct{} func (m MockValidatorWithErrors) Validate(oldState Model, newState Model) error { err := NewError("error_test", "error msg 1") - err = AppendError(err, NewError("error_test2", "error msg 2")) + err = errors.AppendError(err, NewError("error_test2", "error msg 2")) return err } @@ -36,23 +37,20 @@ func TestValidatorInterface(t *testing.T) { // no error validator = MockValidator{} - errors := validator.Validate(nil, nil) - assert.Nil(t, errors, "") + errs := validator.Validate(nil, nil) + assert.Nil(t, errs, "") //one error validator = MockValidatorWithOneError{} - errors = validator.Validate(nil, nil) - assert.Error(t, errors, "error should be returned") - assert.Equal(t, 1, LenError(errors), "errors should include one error") + errs = validator.Validate(nil, nil) + assert.Error(t, errs, "error should be returned") + assert.Equal(t, 1, errors.Len(errs), "errors should include one error") // more than one error validator = MockValidatorWithErrors{} - errors = validator.Validate(nil, nil) - assert.Error(t, errors, "error should be returned") - assert.Equal(t, 2, LenError(errors), "errors should include two error") - - errorArray := Errors(errors) - assert.Equal(t, 2, len(errorArray), "error array should include two error") + errs = validator.Validate(nil, nil) + assert.Error(t, errs, "error should be returned") + assert.Equal(t, 2, errors.Len(errs), "errors should include two errors") } func TestValidatorGroup_Validate(t *testing.T) { @@ -62,21 +60,21 @@ func TestValidatorGroup_Validate(t *testing.T) { MockValidatorWithOneError{}, MockValidatorWithErrors{}, } - errors := testValidatorGroup.Validate(nil, nil) - assert.Equal(t, 3, len(Errors(errors)), "Validate should return 2 errors") + errs := testValidatorGroup.Validate(nil, nil) + assert.Equal(t, 3, errors.Len(errs), "Validate should return 2 errors") testValidatorGroup = ValidatorGroup{ MockValidator{}, MockValidatorWithErrors{}, MockValidatorWithErrors{}, } - errors = testValidatorGroup.Validate(nil, nil) - assert.Equal(t, 4, len(Errors(errors)), "Validate should return 4 errors") + errs = testValidatorGroup.Validate(nil, nil) + assert.Equal(t, 4, errors.Len(errs), "Validate should return 4 errors") // empty group testValidatorGroup = ValidatorGroup{} - errors = testValidatorGroup.Validate(nil, nil) - assert.Equal(t, 0, len(Errors(errors)), "Validate should return no error") + errs = testValidatorGroup.Validate(nil, nil) + assert.Equal(t, 0, errors.Len(errs), "Validate should return no error") // group with no errors at all testValidatorGroup = ValidatorGroup{ @@ -84,8 +82,8 @@ func TestValidatorGroup_Validate(t *testing.T) { MockValidator{}, MockValidator{}, } - errors = testValidatorGroup.Validate(nil, nil) - assert.Equal(t, 0, len(Errors(errors)), "Validate should return no error") + errs = testValidatorGroup.Validate(nil, nil) + assert.Equal(t, 0, errors.Len(errs), "Validate should return no error") } func TestIsCurrencyValid(t *testing.T) { diff --git a/errors/errors.go b/errors/errors.go index 877155958..f4afa817b 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -27,18 +27,16 @@ func New(format string, args ...interface{}) error { } // listError holds a list of errors -type listError struct { - errs []error -} +type listError []error // Error formats the underlying errs into string -func (l *listError) Error() string { - if len(l.errs) == 0 { +func (l listError) Error() string { + if len(l) == 0 { return "" } var errs []string - for _, err := range l.errs { + for _, err := range l { errs = append(errs, err.Error()) } @@ -46,14 +44,14 @@ func (l *listError) Error() string { return "[" + res + "]" } -// append appends the err to the list of errs -func getErrs(err error) []error { +// GetErrs gets the list of errors if its a list +func GetErrs(err error) []error { if err == nil { return nil } - if errl, ok := err.(*listError); ok { - return errl.errs + if errl, ok := err.(listError); ok { + return errl } return []error{err} @@ -64,10 +62,10 @@ func getErrs(err error) []error { // if err is of type listError and if errn is of type listerror, // append errn errors to err and return err func AppendError(err, errn error) error { - var errs []error + var errs listError for _, e := range []error{err, errn} { - if serrs := getErrs(e); len(serrs) > 0 { + if serrs := GetErrs(e); len(serrs) > 0 { errs = append(errs, serrs...) } } @@ -76,7 +74,7 @@ func AppendError(err, errn error) error { return nil } - return &listError{errs} + return errs } // Len returns the total number of errors @@ -88,45 +86,45 @@ func Len(err error) int { return 0 } - if lerr, ok := err.(*listError); ok { - return len(lerr.errs) + if lerr, ok := err.(listError); ok { + return len(lerr) } return 1 } -// typeError holds a type of error and an context error -type typeError struct { +// typedError holds a type of error and an context error +type typedError struct { terr error ctxErr error } // Error returns the error in string -func (t *typeError) Error() string { +func (t *typedError) Error() string { return fmt.Sprintf("%v: %v", t.terr, t.ctxErr) } -// NewTypeError returns a new error of type typeError -func NewTypeError(terr, err error) error { +// NewTypedError returns a new error of type typedError +func NewTypedError(terr, err error) error { if terr == nil { terr = ErrUnknown } - return &typeError{terr: terr, ctxErr: err} + return &typedError{terr: terr, ctxErr: err} } -// TypeError can be implemented by any type error -type TypeError interface { +// TypedError can be implemented by any type error +type TypedError interface { IsOfType(terr error) bool } // IsOfType returns if the err t is of type terr -func (t *typeError) IsOfType(terr error) bool { +func (t *typedError) IsOfType(terr error) bool { if t.terr.Error() == terr.Error() { return true } - if cterr, ok := t.ctxErr.(TypeError); ok { + if cterr, ok := t.ctxErr.(TypedError); ok { return cterr.IsOfType(terr) } @@ -135,7 +133,7 @@ func (t *typeError) IsOfType(terr error) bool { // IsOfType returns if the err is of type terr func IsOfType(terr, err error) bool { - if errt, ok := err.(TypeError); ok { + if errt, ok := err.(TypedError); ok { return errt.IsOfType(terr) } diff --git a/errors/errors_test.go b/errors/errors_test.go index a565709c5..8239b7315 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -40,7 +40,7 @@ func TestNew(t *testing.T) { func checkListError(t *testing.T, lerr error, len int, result string) { assert.NotNil(t, lerr) - _, ok := lerr.(*listError) + _, ok := lerr.(listError) assert.True(t, ok) assert.Equal(t, len, Len(lerr)) assert.Equal(t, result, lerr.Error()) @@ -88,13 +88,13 @@ func TestIsOfType(t *testing.T) { // single type error const errBadErr = Error("bad error") serr := New("some error") - terr := NewTypeError(ErrUnknown, serr) + terr := NewTypedError(ErrUnknown, serr) assert.True(t, IsOfType(ErrUnknown, terr)) assert.False(t, IsOfType(errBadErr, terr)) assert.Equal(t, "unknown error: some error", terr.Error()) // recursive error - terr = NewTypeError(errBadErr, terr) + terr = NewTypedError(errBadErr, terr) assert.True(t, IsOfType(ErrUnknown, terr)) assert.True(t, IsOfType(errBadErr, terr)) assert.Equal(t, "bad error: unknown error: some error", terr.Error()) @@ -108,6 +108,6 @@ func TestIsOfType(t *testing.T) { lerr := AppendError(serr, nil) assert.False(t, IsOfType(ErrUnknown, lerr)) assert.False(t, IsOfType(errBadErr, lerr)) - terr = NewTypeError(errBadErr, lerr) + terr = NewTypedError(errBadErr, lerr) assert.True(t, IsOfType(errBadErr, terr)) } diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 1a0f0e4f1..7fdb99cf9 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -19,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/version" @@ -135,12 +136,12 @@ func TestP2PService_basicChecks(t *testing.T) { }{ { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "someversion", NetworkIdentifier: 12}, - err: documents.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), + err: errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), }, { header: &p2ppb.CentrifugeHeader{CentNodeVersion: "0.0.1", NetworkIdentifier: 12}, - err: documents.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), + err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), }, { diff --git a/p2p/validator.go b/p2p/validator.go index f282ffcbf..1f681defa 100644 --- a/p2p/validator.go +++ b/p2p/validator.go @@ -6,7 +6,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/version" ) @@ -20,13 +20,13 @@ type Validator interface { type ValidatorGroup []Validator // Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(header *p2ppb.CentrifugeHeader) (errors error) { +func (group ValidatorGroup) Validate(header *p2ppb.CentrifugeHeader) (errs error) { for _, v := range group { if err := v.Validate(header); err != nil { - errors = documents.AppendError(errors, err) + errs = errors.AppendError(errs, err) } } - return errors + return errs } // ValidatorFunc implements Validator and can be used as a adaptor for functions From d1a8004a6b6a8da8d3d745e0e641b874bc5b5a49 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 12 Dec 2018 14:21:41 +0100 Subject: [PATCH 076/220] Migrate invoice service to new repo (#554) * Migrate documents package to use new errors * typeerror -> typederror * Fix failing tests * Migrate invoice service to new repo * Fix fmt errors * Migrate new repository to new errors * Fix test * Fix test * Fix lint issue * Fix error name * Fix error name --- documents/bootstrapper.go | 15 ++++ documents/bootstrapper_test.go | 3 + documents/error.go | 26 +++++++ documents/invoice/bootstrapper.go | 15 ++-- documents/invoice/repository.go | 21 ------ documents/invoice/repository_test.go | 67 ----------------- documents/invoice/service.go | 64 ++++++++++++---- documents/invoice/service_test.go | 63 ++++++++++------ documents/leveldb_test.go | 106 --------------------------- documents/repository.go | 21 +++--- documents/service.go | 7 ++ documents/test_bootstrapper.go | 4 +- p2p/handler_integration_test.go | 4 +- 13 files changed, 166 insertions(+), 250 deletions(-) delete mode 100644 documents/invoice/repository.go delete mode 100644 documents/invoice/repository_test.go delete mode 100644 documents/leveldb_test.go diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index f810d8214..41ec72820 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -1,13 +1,28 @@ package documents +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/syndtr/goleveldb/leveldb" +) + // BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context const BootstrappedRegistry = "BootstrappedRegistry" +// BootstrappedDocumentRepository is the key to the database repository of documents +const BootstrappedDocumentRepository = "BootstrappedDocumentRepository" + // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { ctx[BootstrappedRegistry] = NewServiceRegistry() + ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + if !ok { + return errors.Error(ErrDocumentBootstrap) + } + repo := NewLevelDBRepository(ldb) + ctx[BootstrappedDocumentRepository] = repo return nil } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 1da47e0b5..dea6e5383 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -5,11 +5,14 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" + "github.com/syndtr/goleveldb/leveldb" ) func TestBootstrapper_Bootstrap(t *testing.T) { ctx := make(map[string]interface{}) + ctx[storage.BootstrappedLevelDB] = &leveldb.DB{} err := Bootstrapper{}.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRegistry]) diff --git a/documents/error.go b/documents/error.go index 6e95df30a..5f0ecbfdb 100644 --- a/documents/error.go +++ b/documents/error.go @@ -8,6 +8,12 @@ import ( const ( + // ErrDocumentConfigTenantID must be used for errors related to tenantID operations + ErrDocumentConfigTenantID = errors.Error("error with tenantID operations") + + // ErrDocumentBootstrap must be used for errors related to documents package bootstrapping + ErrDocumentBootstrap = errors.Error("error when bootstrapping document package") + // ErrDocumentIdentifier must be used for errors caused by document identifier problems ErrDocumentIdentifier = errors.Error("document identifier error") @@ -49,6 +55,26 @@ const ( // ErrDocumentProof must be used when document proof creation fails ErrDocumentProof = errors.Error("document proof error") + + // Document repository errors + + // ErrDocumentRepositoryModelNotRegistered must be used when the model hasn't been registered in the database repository + ErrDocumentRepositoryModelNotRegistered = errors.Error("document model hasn't been registered in the database repository") + + // ErrDocumentRepositorySerialisation must be used when document repository encounters a marshalling error + ErrDocumentRepositorySerialisation = errors.Error("document repository encountered a marshalling error") + + // ErrDocumentRepositoryModelNotFound must be used when document repository can not locate the given model + ErrDocumentRepositoryModelNotFound = errors.Error("document repository could not locate the given model") + + // ErrDocumentRepositoryModelSave must be used when document repository can not save the given model + ErrDocumentRepositoryModelSave = errors.Error("document repository could not save the given model") + + // ErrDocumentRepositoryModelAllReadyExists must be used when document repository finds an already existing model when saving + ErrDocumentRepositoryModelAllReadyExists = errors.Error("document repository found an already existing model when saving") + + // ErrDocumentRepositoryModelDoesntExist must be used when document repository does not find an existing model for an update + ErrDocumentRepositoryModelDoesntExist = errors.Error("document repository did not find an existing model for an update") ) // Error wraps an error with specific key diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 209a43289..dc7b9b1d3 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -11,8 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -26,11 +24,6 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg := ctx[config.BootstrappedConfig].(config.Configuration) - ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) - if !ok { - return errors.New("initializing LevelDB repository failed") - } - p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") @@ -51,8 +44,14 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("identity service not initialised") } + repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) + if !ok { + return fmt.Errorf("document db repository not initialised") + } + repo.Register(&Invoice{}) + // register service - srv := DefaultService(cfg, getRepository(ldb), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register invoice service: %v", err) diff --git a/documents/invoice/repository.go b/documents/invoice/repository.go deleted file mode 100644 index 97c0ec9ca..000000000 --- a/documents/invoice/repository.go +++ /dev/null @@ -1,21 +0,0 @@ -package invoice - -import ( - "github.com/centrifuge/go-centrifuge/documents" - "github.com/syndtr/goleveldb/leveldb" -) - -// repository is the invoice repository -type repository struct { - documents.LevelDBRepository -} - -// getRepository returns the implemented documents.legacyRepo for invoices -func getRepository(ldb *leveldb.DB) documents.LegacyRepository { - return &repository{ - documents.LevelDBRepository{ - KeyPrefix: "invoice", - LevelDB: ldb, - }, - } -} diff --git a/documents/invoice/repository_test.go b/documents/invoice/repository_test.go deleted file mode 100644 index a71d059b7..000000000 --- a/documents/invoice/repository_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// +build unit - -package invoice - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -func TestRepository(t *testing.T) { - repo := testRepo() - invRepo := repo.(*repository) - assert.Equal(t, invRepo.KeyPrefix, "invoice") - assert.NotNil(t, invRepo.LevelDB, "missing leveldb instance") - - id := utils.RandomSlice(32) - doc := &Invoice{ - InvoiceNumber: "inv1234", - SenderName: "Jack", - SenderZipcode: "921007", - SenderCountry: "AUS", - RecipientName: "John", - RecipientZipcode: "12345", - RecipientCountry: "Germany", - Currency: "EUR", - GrossAmount: 800, - } - - err := repo.Create(id, doc) - assert.Nil(t, err, "create must pass") - - // successful get - getDoc := new(Invoice) - err = repo.LoadByID(id, getDoc) - assert.Nil(t, err, "get must pass") - assert.Equal(t, getDoc, doc, "documents mismatch") - - // successful update - doc.GrossAmount = 200 - err = repo.Update(id, doc) - assert.Nil(t, err, "update must pass") - assert.Nil(t, repo.LoadByID(id, getDoc), "get must pass") - assert.Equal(t, getDoc.GrossAmount, doc.GrossAmount, "amount must match") -} - -func TestRepository_getRepository(t *testing.T) { - r := testRepo() - assert.NotNil(t, r) - assert.Equal(t, "invoice", r.(*repository).KeyPrefix) -} - -var testRepoGlobal documents.LegacyRepository - -func testRepo() documents.LegacyRepository { - if testRepoGlobal == nil { - ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) - if err != nil { - panic(err) - } - testRepoGlobal = getRepository(ldb) - } - return testRepoGlobal -} diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 2ab543d54..97b50c95b 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -52,7 +52,8 @@ type Service interface { // service implements Service and handles all invoice related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - repo documents.LegacyRepository + config documents.Config + repo documents.Repository coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -60,8 +61,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} +func DefaultService(config config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{config: config, repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } // CreateProofs creates proofs for the latest version document given the fields @@ -150,8 +151,14 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(inv.CoreDocument.CurrentVersion, inv) + err = s.repo.Create(tenantID, inv.CoreDocument.CurrentVersion, inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -166,7 +173,7 @@ func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documen return nil, err } - inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.repo.Update) + inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.updater) if err != nil { return nil, err } @@ -174,6 +181,16 @@ func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documen return inv, nil } +// updater wraps logic related to updating documents so that it can be executed as a closure +func (s service) updater(id []byte, model documents.Model) error { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + return s.repo.Update(tenantID, id, model) +} + // Update finds the old document, validates the new version and persists the updated document func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { cd, err := inv.PackCoreDocument() @@ -191,7 +208,7 @@ func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documen return nil, err } - inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.repo.Update) + inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.updater) if err != nil { return nil, err } @@ -229,8 +246,12 @@ func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err } func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, err error) { - var doc documents.Model = new(Invoice) - err = s.repo.LoadByID(version, doc) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + doc, err := s.repo.Get(tenantID, version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -352,15 +373,21 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(doc.DocumentIdentifier, model) + if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } - err = s.repo.Create(doc.CurrentVersion, model) + err = s.repo.Create(tenantID, doc.CurrentVersion, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -380,7 +407,13 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - err = s.repo.Update(doc.CurrentVersion, model) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + err = s.repo.Update(tenantID, doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -402,5 +435,10 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C // Exists checks if an invoice exists func (s service) Exists(documentID []byte) bool { - return s.repo.Exists(documentID) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return false + } + return s.repo.Exists(tenantID, documentID) } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index d9f673d95..26c1bdd09 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" @@ -44,14 +45,18 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func TestDefaultService(t *testing.T) { - srv := DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil).Once() + srv := DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) assert.NotNil(t, srv, "must be non-nil") } func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) + return idService, DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) } func createMockDocument() (*Invoice, error) { @@ -66,7 +71,7 @@ func createMockDocument() (*Invoice, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(documentIdentifier, inv1) + err := testRepo().Create(centIDBytes, documentIdentifier, inv1) return inv1, err } @@ -135,7 +140,7 @@ func TestService_GetLastVersion(t *testing.T) { }, } - err = testRepo().Create(doc.CoreDocument.NextVersion, inv2) + err = testRepo().Create(centIDBytes, doc.CoreDocument.NextVersion, inv2) assert.Nil(t, err) mod2, err := invSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -156,7 +161,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(currentVersion, inv) + err := testRepo().Create(centIDBytes, currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -175,7 +180,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(currentVersion, inv) + err := testRepo().Create(centIDBytes, currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(documentIdentifier, currentVersion) @@ -198,7 +203,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(documentIdentifier, inv) + err := testRepo().Create(centIDBytes, documentIdentifier, inv) assert.Nil(t, err) exists := invSrv.Exists(documentIdentifier) @@ -212,7 +217,8 @@ func TestService_Exists(t *testing.T) { func TestService_Create(t *testing.T) { ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) - invSrv := service{repo: testRepo()} + _, srv := getServiceWithMockedLayers() + invSrv := srv.(service) // calculate data root fails m, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) @@ -248,8 +254,8 @@ func TestService_Create(t *testing.T) { newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) } func TestService_DeriveInvoiceData(t *testing.T) { @@ -325,7 +331,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) @@ -436,7 +442,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { } if !skipSave { - err = testRepo().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -474,7 +480,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { if err != nil { return nil, err } - err = testRepo().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -520,7 +526,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(id, old) + err = testRepo().Create(centIDBytes, id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ Sender: "0x010101010101", @@ -564,7 +570,8 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { } func TestService_Update(t *testing.T) { - invSrv := service{repo: testRepo()} + _, srv := getServiceWithMockedLayers() + invSrv := srv.(service) ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -593,7 +600,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) inv.(*Invoice).CoreDocument = cd - testRepo().Create(cd.CurrentVersion, inv) + testRepo().Create(centIDBytes, cd.CurrentVersion, inv) // calculate data root fails model = &mockModel{} @@ -632,9 +639,9 @@ func TestService_Update(t *testing.T) { newCD, err := inv.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.PreviousVersion)) newData, err = invSrv.DeriveInvoiceData(inv) assert.Nil(t, err) @@ -670,12 +677,12 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - err = invSrv.repo.Create(inv.(*Invoice).CoreDocument.CurrentVersion, inv) + err = invSrv.repo.Create(centIDBytes, inv.(*Invoice).CoreDocument.CurrentVersion, inv) assert.Nil(t, err) inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) assert.Nil(t, inv) assert.Error(t, err) - assert.Contains(t, err.Error(), "document already exists") + assert.Contains(t, err.Error(), "document repository found an already existing model when saving") // success inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) @@ -686,3 +693,17 @@ func TestService_calculateDataRoot(t *testing.T) { assert.NotNil(t, inv) assert.NotNil(t, inv.(*Invoice).CoreDocument.DataRoot) } + +var testRepoGlobal documents.Repository + +func testRepo() documents.Repository { + if testRepoGlobal == nil { + ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + if err != nil { + panic(err) + } + testRepoGlobal = documents.NewLevelDBRepository(ldb) + testRepoGlobal.Register(&Invoice{}) + } + return testRepoGlobal +} diff --git a/documents/leveldb_test.go b/documents/leveldb_test.go deleted file mode 100644 index b287526da..000000000 --- a/documents/leveldb_test.go +++ /dev/null @@ -1,106 +0,0 @@ -// +build unit - -package documents - -import ( - "encoding/json" - "fmt" - "reflect" - "testing" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -type model struct { - shouldError bool - Data string `json:"data"` -} - -func (m *model) ID() ([]byte, error) { return []byte{}, nil } -func (m *model) Type() reflect.Type { return reflect.TypeOf(m) } -func (m *model) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { return nil, nil } -func (m *model) UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error { return nil } - -func (m *model) JSON() ([]byte, error) { - if m.shouldError { - return nil, fmt.Errorf("failed to marshal") - } - - return json.Marshal(m) -} - -func (m *model) FromJSON(data []byte) error { - if m.shouldError { - return fmt.Errorf("failed to unmarshal") - } - - return json.Unmarshal(data, m) -} - -func TestDefaultLevelDB_LoadByID(t *testing.T) { - id := utils.RandomSlice(32) - - // missing ID - err := testLevelDB.LoadByID(id, new(model)) - assert.Error(t, err, "error must be non nil") - - // nil document - err = testLevelDB.LoadByID(id, nil) - assert.Error(t, err, "error must be non nil") - - // Failed unmarshal - m := &model{shouldError: true} - err = testLevelDB.LoadByID(id, m) - assert.Error(t, err, "error must be non nil") - - // success - m = &model{Data: "hello, world"} - err = testLevelDB.Create(id, m) - assert.Nil(t, err, "error should be nil") - nm := new(model) - err = testLevelDB.LoadByID(id, nm) - assert.Nil(t, err, "error should be nil") - assert.Equal(t, m, nm, "models must match") -} - -func TestDefaultLevelDB_Create(t *testing.T) { - id := utils.RandomSlice(32) - d := &model{Data: "Create it"} - err := testLevelDB.Create(id, d) - assert.Nil(t, err, "create must pass") - - // same id - err = testLevelDB.Create(id, new(model)) - assert.Error(t, err, "create must fail") - - // nil model - err = testLevelDB.Create(id, nil) - assert.Error(t, err, "create must fail") -} - -func TestDefaultLevelDB_UpdateModel(t *testing.T) { - id := utils.RandomSlice(32) - - // missing Id - err := testLevelDB.Update(id, new(model)) - assert.Error(t, err, "update must fail") - - // nil model - err = testLevelDB.Update(id, nil) - assert.Error(t, err, "update must fail") - - m := &model{Data: "create it"} - err = testLevelDB.Create(id, m) - assert.Nil(t, err, "create must pass") - - // successful one - m.Data = "update it" - err = testLevelDB.Update(id, m) - assert.Nil(t, err, "update must pass") - nm := new(model) - err = testLevelDB.LoadByID(id, nm) - assert.Nil(t, err, "get mode must pass") - assert.Equal(t, m, nm) -} diff --git a/documents/repository.go b/documents/repository.go index 6c81c3fed..53720b2e1 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -6,6 +6,7 @@ import ( "reflect" "sync" + "github.com/centrifuge/go-centrifuge/errors" "github.com/syndtr/goleveldb/leveldb" ) @@ -72,7 +73,7 @@ func (l *levelDBRepo) Exists(tenantID, id []byte) bool { func (l *levelDBRepo) getModel(mt string) (Model, error) { tp, ok := l.models[mt] if !ok { - return nil, fmt.Errorf("type %s not registered", mt) + return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotRegistered, fmt.Errorf("type %s not registered", mt)) } return reflect.New(tp).Interface().(Model), nil @@ -83,25 +84,25 @@ func (l *levelDBRepo) Get(tenantID, id []byte) (Model, error) { key := getKey(tenantID, id) data, err := l.db.Get(key, nil) if err != nil { - return nil, fmt.Errorf("document missing: %v", err) + return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotFound, fmt.Errorf("document missing: %v", err)) } v := new(value) err = json.Unmarshal(data, v) if err != nil { - return nil, fmt.Errorf("failed to unmarshal value: %v", err) + return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to unmarshal value: %v", err)) } l.mu.RLock() defer l.mu.RUnlock() nm, err := l.getModel(v.Type) if err != nil { - return nil, fmt.Errorf("failed to get model type: %v", err) + return nil, err } err = nm.FromJSON([]byte(v.Data)) if err != nil { - return nil, fmt.Errorf("failed to unmarshal to model: %v", err) + return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to unmarshal to model: %v", err)) } return nm, nil @@ -120,7 +121,7 @@ func getTypeIndirect(tp reflect.Type) reflect.Type { func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { data, err := model.JSON() if err != nil { - return fmt.Errorf("failed to marshall model: %v", err) + return errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to marshall model: %v", err)) } tp := getTypeIndirect(model.Type()) @@ -131,13 +132,13 @@ func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { data, err = json.Marshal(v) if err != nil { - return fmt.Errorf("failed to marshall value: %v", err) + return errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to marshall value: %v", err)) } key := getKey(tenantID, id) err = l.db.Put(key, data, nil) if err != nil { - return fmt.Errorf("failed to save model to DB: %v", err) + return errors.NewTypedError(ErrDocumentRepositoryModelSave, fmt.Errorf("%v", err)) } return nil @@ -147,7 +148,7 @@ func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { // Errors out if the model already exists. func (l *levelDBRepo) Create(tenantID, id []byte, model Model) error { if l.Exists(tenantID, id) { - return fmt.Errorf("model already exists") + return ErrDocumentRepositoryModelAllReadyExists } return l.save(tenantID, id, model) @@ -157,7 +158,7 @@ func (l *levelDBRepo) Create(tenantID, id []byte, model Model) error { // Errors out if model doesn't exist func (l *levelDBRepo) Update(tenantID, id []byte, model Model) error { if !l.Exists(tenantID, id) { - return fmt.Errorf("model doesn't exist") + return ErrDocumentRepositoryModelDoesntExist } return l.save(tenantID, id, model) diff --git a/documents/service.go b/documents/service.go index d703b3408..cbe126990 100644 --- a/documents/service.go +++ b/documents/service.go @@ -7,6 +7,13 @@ import ( "github.com/centrifuge/precise-proofs/proofs/proto" ) +// Config specified configs required by documents package +type Config interface { + + // GetIdentityID retrieves the centID(TenentID) configured + GetIdentityID() ([]byte, error) +} + // DocumentProof is a value to represent a document and its field proofs type DocumentProof struct { DocumentID []byte diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 400b637c4..3f8c37d7f 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -10,13 +10,13 @@ import ( ) // initialized ONLY for tests -var testLevelDB LegacyRepository +var testLevelDB Repository func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { if _, ok := context[storage.BootstrappedLevelDB]; !ok { return errors.New("initializing LevelDB repository failed") } - testLevelDB = LevelDBRepository{LevelDB: context[storage.BootstrappedLevelDB].(*leveldb.DB)} + testLevelDB = NewLevelDBRepository(context[storage.BootstrappedLevelDB].(*leveldb.DB)) return b.Bootstrap(context) } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index d9b0ab58f..026e13bc0 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -74,7 +74,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { req = getSignatureRequest(doc) resp, err = handler.RequestDocumentSignature(context.Background(), req) assert.NotNil(t, err, "must not be nil") - assert.Contains(t, err.Error(), "document already exists") + assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelAllReadyExists.Error()) } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { @@ -147,7 +147,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { anchorReq := getAnchoredRequest(doc) anchorResp, err := handler.SendAnchoredDocument(context.Background(), anchorReq) assert.Error(t, err) - assert.Contains(t, err.Error(), "document doesn't exists") + assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelDoesntExist.Error()) assert.Nil(t, anchorResp) } From 69894e31ad85bada9005d64acc8b54a19985bf51 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 12 Dec 2018 14:48:44 +0100 Subject: [PATCH 077/220] added testworld tests for proofs (#556) * added testworld tests for proofs * added proof check for bob --- testworld/httputils.go | 9 +++++++++ testworld/nft_test.go | 3 +++ testworld/payloads.go | 7 +++++++ testworld/proof_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 testworld/proof_test.go diff --git a/testworld/httputils.go b/testworld/httputils.go index 01da7f820..8fcd2a8cf 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -70,6 +70,15 @@ func mintNFT(e *httpexpect.Expect, httpStatus int, payload map[string]interface{ return httpObj } +func getProof(e *httpexpect.Expect, httpStatus int, documentID string, payload map[string]interface{}) *httpexpect.Object { + resp := e.POST("/document/"+documentID+"/proof"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + WithJSON(payload). + Expect().Status(httpStatus) + return resp.JSON().Object() +} + func createInsecureClient() *http.Client { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, diff --git a/testworld/nft_test.go b/testworld/nft_test.go index e8aaa4316..15c913e50 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -12,6 +12,7 @@ import ( const tokenIdLength = 77 func TestPaymentObligationMint_successful(t *testing.T) { + t.Parallel() alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") @@ -56,6 +57,8 @@ func TestPaymentObligationMint_successful(t *testing.T) { } func TestPaymentObligationMint_errors(t *testing.T) { + t.Parallel() + alice := doctorFord.getHostTestSuite(t, "Alice") tests := []struct { diff --git a/testworld/payloads.go b/testworld/payloads.go index a79d27580..65e4c09ea 100644 --- a/testworld/payloads.go +++ b/testworld/payloads.go @@ -46,3 +46,10 @@ func updatedInvoicePayload(collaborators []string) map[string]interface{} { } } + +func defaultProofPayload() map[string]interface{} { + return map[string]interface{}{ + "type": "http://github.com/centrifuge/centrifuge-protobufs/invoice/#invoice.InvoiceData", + "fields": []string{"invoice.net_amount", "invoice.currency"}, + } +} diff --git a/testworld/proof_test.go b/testworld/proof_test.go new file mode 100644 index 000000000..1cf3720eb --- /dev/null +++ b/testworld/proof_test.go @@ -0,0 +1,44 @@ +// +build testworld + +package testworld + +import ( + "net/http" + "testing" + + "github.com/gavv/httpexpect" +) + +func TestProofWithMultipleFields_successful(t *testing.T) { + alice := doctorFord.getHostTestSuite(t, "Alice") + bob := doctorFord.getHostTestSuite(t, "Bob") + + // Alice shares invoice document with Bob + res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultNFTPayload([]string{bob.id.String()})) + if err != nil { + t.Error(err) + } + + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + + proofPayload := defaultProofPayload() + + proofFromAlice := getProof(alice.httpExpect, http.StatusOK, docIdentifier, proofPayload) + proofFromBob := getProof(bob.httpExpect, http.StatusOK, docIdentifier, proofPayload) + + checkProof(proofFromAlice, docIdentifier) + checkProof(proofFromBob, docIdentifier) + +} + +func checkProof(objProof *httpexpect.Object, docIdentifier string) { + objProof.Path("$.header.document_id").String().Equal(docIdentifier) + objProof.Path("$.field_proofs[0].property").String().Equal("invoice.net_amount") + objProof.Path("$.field_proofs[0].sorted_hashes").NotNull() + objProof.Path("$.field_proofs[1].property").String().Equal("invoice.currency") + objProof.Path("$.field_proofs[1].sorted_hashes").NotNull() + +} From 0858f86c8c3cdc41967c32fe1fe0753abbf7cdef Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 12 Dec 2018 18:21:56 +0100 Subject: [PATCH 078/220] Migrate po service to new repo (#557) * Migrate documents package to use new errors * typeerror -> typederror * Fix failing tests * Migrate invoice service to new repo * Fix fmt errors * Migrate new repository to new errors * Fix test * Fix test * Fix lint issue * Fix error name * Fix error name * Migrate PO service to new repository --- documents/purchaseorder/bootstrapper.go | 15 ++-- documents/purchaseorder/repository.go | 21 ------ documents/purchaseorder/repository_test.go | 30 -------- documents/purchaseorder/service.go | 64 +++++++++++++---- documents/purchaseorder/service_test.go | 81 +++++++++++++++------- 5 files changed, 114 insertions(+), 97 deletions(-) delete mode 100644 documents/purchaseorder/repository.go delete mode 100644 documents/purchaseorder/repository_test.go diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index a128993ce..2bfe8c271 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -11,8 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -25,11 +23,6 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } cfg := ctx[config.BootstrappedConfig].(config.Configuration) - ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) - if !ok { - return errors.New("initializing LevelDB repository failed") - } - p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { return fmt.Errorf("p2p client not initialised") @@ -50,8 +43,14 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return fmt.Errorf("identity service not initialised") } + repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) + if !ok { + return fmt.Errorf("document db repository not initialised") + } + repo.Register(&PurchaseOrder{}) + // register service - srv := DefaultService(cfg, getRepository(ldb), coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return fmt.Errorf("failed to register purchase order service") diff --git a/documents/purchaseorder/repository.go b/documents/purchaseorder/repository.go deleted file mode 100644 index b05faad69..000000000 --- a/documents/purchaseorder/repository.go +++ /dev/null @@ -1,21 +0,0 @@ -package purchaseorder - -import ( - "github.com/centrifuge/go-centrifuge/documents" - "github.com/syndtr/goleveldb/leveldb" -) - -// repository is the purchase order repository -type repository struct { - documents.LevelDBRepository -} - -// getRepository returns the implemented documents.legacyRepo for purchase orders -func getRepository(ldb *leveldb.DB) documents.LegacyRepository { - return &repository{ - documents.LevelDBRepository{ - KeyPrefix: "purchaseorder", - LevelDB: ldb, - }, - } -} diff --git a/documents/purchaseorder/repository_test.go b/documents/purchaseorder/repository_test.go deleted file mode 100644 index c4e5043e3..000000000 --- a/documents/purchaseorder/repository_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build unit - -package purchaseorder - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/stretchr/testify/assert" -) - -func TestRepository_getRepository(t *testing.T) { - r := testRepo() - assert.NotNil(t, r) - assert.Equal(t, "purchaseorder", r.(*repository).KeyPrefix) -} - -var testRepoGlobal documents.LegacyRepository - -func testRepo() documents.LegacyRepository { - if testRepoGlobal == nil { - ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) - if err != nil { - panic(err) - } - testRepoGlobal = getRepository(ldb) - } - return testRepoGlobal -} diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 7dfdf340d..23a6fb148 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -52,7 +52,8 @@ type Service interface { // service implements Service and handles all purchase order related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - repo documents.LegacyRepository + config documents.Config + repo documents.Repository coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -60,8 +61,8 @@ type service struct { } // DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo documents.LegacyRepository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} +func DefaultService(config config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { + return service{config: config, repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} } // DeriveFromCoreDocument takes a core document and returns a purchase order @@ -94,8 +95,14 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(po.CoreDocument.CurrentVersion, po) + err = s.repo.Create(tenantID, po.CoreDocument.CurrentVersion, po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -110,7 +117,7 @@ func (s service) Create(ctx *header.ContextHeader, po documents.Model) (document return nil, err } - po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.repo.Update) + po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.updater) if err != nil { return nil, err } @@ -118,6 +125,16 @@ func (s service) Create(ctx *header.ContextHeader, po documents.Model) (document return po, nil } +// updater wraps logic related to updating documents so that it can be executed as a closure +func (s service) updater(id []byte, model documents.Model) error { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + return s.repo.Update(tenantID, id, model) +} + // Update validates, persists, and anchors a new version of purchase order func (s service) Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { cd, err := po.PackCoreDocument() @@ -135,7 +152,7 @@ func (s service) Update(ctx *header.ContextHeader, po documents.Model) (document return nil, err } - po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.repo.Update) + po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.updater) if err != nil { return nil, err } @@ -241,8 +258,12 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P } func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *PurchaseOrder, err error) { - var doc documents.Model = new(PurchaseOrder) - err = s.repo.LoadByID(version, doc) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + doc, err := s.repo.Get(tenantID, version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -351,15 +372,21 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { - err = s.repo.Create(cd.DocumentIdentifier, model) + if !s.repo.Exists(tenantID, cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { + err = s.repo.Create(tenantID, cd.DocumentIdentifier, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } - err = s.repo.Create(cd.CurrentVersion, model) + err = s.repo.Create(tenantID, cd.CurrentVersion, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -381,7 +408,13 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - err = s.repo.Update(doc.CurrentVersion, model) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + err = s.repo.Update(tenantID, doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -403,5 +436,10 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C // Exists checks if an purchase order exists func (s service) Exists(documentID []byte) bool { - return s.repo.Exists(documentID) + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return false + } + return s.repo.Exists(tenantID, documentID) } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 46284820d..70eda819f 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" @@ -44,13 +45,17 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(new(testingconfig.MockConfig), testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + return idService, DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) } func TestService_Update(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -79,7 +84,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) po.(*PurchaseOrder).CoreDocument = cd - testRepo().Create(cd.CurrentVersion, po) + testRepo().Create(centIDBytes, cd.CurrentVersion, po) // calculate data root fails model = &testingdocuments.MockModel{} @@ -118,9 +123,9 @@ func TestService_Update(t *testing.T) { newCD, err := po.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.PreviousVersion)) newData, err = poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -128,7 +133,9 @@ func TestService_Update(t *testing.T) { } func TestService_DeriveFromUpdatePayload(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} // nil payload doc, err := poSrv.DeriveFromUpdatePayload(nil, nil) @@ -166,7 +173,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(id, old) + err = testRepo().Create(centIDBytes, id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "0x010203040506", @@ -266,7 +273,9 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { func TestService_Create(t *testing.T) { ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} // calculate data root fails m, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) @@ -303,8 +312,8 @@ func TestService_Create(t *testing.T) { newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) } func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, error) { @@ -355,7 +364,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er } if !skipSave { - err = testRepo().Create(i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -400,7 +409,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) @@ -454,7 +463,7 @@ func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseO if err != nil { return nil, err } - err = testRepo().Create(model.CoreDocument.CurrentVersion, model) + err = testRepo().Create(centIDBytes, model.CoreDocument.CurrentVersion, model) if err != nil { return nil, err } @@ -566,12 +575,14 @@ func createMockDocument() (*PurchaseOrder, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(documentIdentifier, model) + err := testRepo().Create(centIDBytes, documentIdentifier, model) return model, err } func TestService_GetCurrentVersion(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) @@ -591,7 +602,7 @@ func TestService_GetCurrentVersion(t *testing.T) { }, } - err = testRepo().Create(doc.CoreDocument.NextVersion, po2) + err = testRepo().Create(centIDBytes, doc.CoreDocument.NextVersion, po2) assert.Nil(t, err) mod2, err := poSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -603,7 +614,9 @@ func TestService_GetCurrentVersion(t *testing.T) { } func TestService_GetVersion_invalid_version(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} currentVersion := utils.RandomSlice(32) po := &PurchaseOrder{ @@ -613,7 +626,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(currentVersion, po) + err := testRepo().Create(centIDBytes, currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -622,7 +635,9 @@ func TestService_GetVersion_invalid_version(t *testing.T) { } func TestService_GetVersion(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) @@ -633,7 +648,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(currentVersion, po) + err := testRepo().Create(centIDBytes, currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(documentIdentifier, currentVersion) @@ -656,7 +671,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(documentIdentifier, po) + err := testRepo().Create(centIDBytes, documentIdentifier, po) assert.Nil(t, err) exists := poSrv.Exists(documentIdentifier) @@ -683,7 +698,9 @@ func TestService_RequestDocumentSignature(t *testing.T) { } func TestService_calculateDataRoot(t *testing.T) { - poSrv := service{repo: testRepo()} + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + poSrv := service{config: c, repo: testRepo()} ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) @@ -709,12 +726,12 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - err = poSrv.repo.Create(po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) + err = poSrv.repo.Create(centIDBytes, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) assert.Nil(t, err) po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) assert.Nil(t, po) assert.Error(t, err) - assert.Contains(t, err.Error(), "document already exists") + assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelAllReadyExists) // success po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) @@ -725,3 +742,17 @@ func TestService_calculateDataRoot(t *testing.T) { assert.NotNil(t, po) assert.NotNil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) } + +var testRepoGlobal documents.Repository + +func testRepo() documents.Repository { + if testRepoGlobal == nil { + ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + if err != nil { + panic(err) + } + testRepoGlobal = documents.NewLevelDBRepository(ldb) + testRepoGlobal.Register(&PurchaseOrder{}) + } + return testRepoGlobal +} From 3b0a572874becb59be5e250703a1fe33ef2e5ced Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 12 Dec 2018 18:55:54 +0100 Subject: [PATCH 079/220] Remove legacy repo (#558) * Migrate documents package to use new errors * typeerror -> typederror * Fix failing tests * Migrate invoice service to new repo * Fix fmt errors * Migrate new repository to new errors * Fix test * Fix test * Fix lint issue * Fix error name * Fix error name * Migrate PO service to new repository * Remove legacy repo --- documents/leveldb.go | 113 ------------------------------------------- p2p/handler_test.go | 10 ---- 2 files changed, 123 deletions(-) delete mode 100644 documents/leveldb.go diff --git a/documents/leveldb.go b/documents/leveldb.go deleted file mode 100644 index 0de8b01c7..000000000 --- a/documents/leveldb.go +++ /dev/null @@ -1,113 +0,0 @@ -package documents - -import ( - "fmt" - - "github.com/syndtr/goleveldb/leveldb" -) - -// LegacyRepository should be implemented by any type that wants to store a document in key-value storage. -// Deprecated: Use the single collection DB -> `Repository` -type LegacyRepository interface { - // GetKey will prepare the the identifier key from ID - // Deprecated: Use the single collection DB functions -> `Repository` - GetKey(id []byte) (key []byte) - - // GetByID finds the doc with identifier and marshals it into message - // Deprecated: Use the single collection DB functions -> `Repository` - LoadByID(id []byte, model Model) error - - // Exists checks for document existence - // True if exists else false - // Deprecated: Use the single collection DB functions -> `Repository` - Exists(id []byte) bool - - // Create stores the initial document - // If document exist, it errors out - // Deprecated: Use the single collection DB functions -> `Repository` - Create(id []byte, model Model) error - - // Update updates the already stored document - // errors out when document is missing - // Deprecated: Use the single collection DB functions -> `Repository` - Update(id []byte, model Model) error -} - -// LevelDBRepository is implements repository -// Deprecated: in favour of `levelDBRepo` -type LevelDBRepository struct { - KeyPrefix string - LevelDB *leveldb.DB -} - -// Exists returns if the document exists in the repository -func (repo LevelDBRepository) Exists(id []byte) bool { - _, err := repo.LevelDB.Get(repo.GetKey(id), nil) - if err != nil { - return false - } - - return true -} - -// GetKey prepends the id with prefix and returns the result -func (repo LevelDBRepository) GetKey(id []byte) []byte { - return append([]byte(repo.KeyPrefix), id...) -} - -// LoadByID finds the document by id and marshals into message -func (repo LevelDBRepository) LoadByID(id []byte, model Model) error { - if model == nil { - return fmt.Errorf("nil document provided") - } - - data, err := repo.LevelDB.Get(repo.GetKey(id), nil) - if err != nil { - return err - } - - err = model.FromJSON(data) - if err != nil { - return err - } - - return nil -} - -// Create creates the document if not exists -// errors out if document exists -func (repo LevelDBRepository) Create(id []byte, model Model) error { - if model == nil { - return fmt.Errorf("nil model provided") - } - - if repo.Exists(id) { - return fmt.Errorf("document already exists") - } - - data, err := model.JSON() - if err != nil { - return err - } - - return repo.LevelDB.Put(repo.GetKey(id), data, nil) -} - -// Update updates the doc with ID if exists -// errors out if the document -func (repo LevelDBRepository) Update(id []byte, model Model) error { - if model == nil { - return fmt.Errorf("nil document provided") - } - - if !repo.Exists(id) { - return fmt.Errorf("document doesn't exists") - } - - data, err := model.JSON() - if err != nil { - return err - } - - return repo.LevelDB.Put(repo.GetKey(id), data, nil) -} diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 7fdb99cf9..77ef986bc 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -162,16 +162,6 @@ func TestP2PService_basicChecks(t *testing.T) { } -type mockRepo struct { - mock.Mock - documents.LegacyRepository -} - -func (r mockRepo) Update(id []byte, m documents.Model) error { - args := r.Called(id, m) - return args.Error(0) -} - type mockModel struct { mock.Mock documents.Model From 95fdcbb813013ae4ecebc78ff0640d792975ac70 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 12 Dec 2018 22:47:41 +0100 Subject: [PATCH 080/220] added support for PO tests to testworld (#566) * added testworld tests for proofs * simple tests refactored * added PO basic tests * updated all PO tests * included tests for NFT * correct travis config * fixed nft for PO * fixed linting and pararell collaborator timeout * deactivate unstable testcase --- testworld/document_consensus_test.go | 64 ++++++++++--------- testworld/httputils.go | 16 +++-- testworld/nft_test.go | 33 +++++++--- testworld/park.go | 10 +-- testworld/park_test.go | 11 ++-- testworld/payloads.go | 96 ++++++++++++++++++++++++++-- testworld/proof_test.go | 38 +++++++---- 7 files changed, 189 insertions(+), 79 deletions(-) diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 4147a912c..ac865f72c 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -7,17 +7,23 @@ import ( "testing" ) -func TestHost_AddExternalCollaborator(t *testing.T) { +func TestHost_AddExternalCollaborator_invoice(t *testing.T) { t.Parallel() + addExternalCollaborator(t, typeInvoice) +} + +func TestHost_AddExternalCollaborator_po(t *testing.T) { + t.Parallel() + addExternalCollaborator(t, typePO) +} + +func addExternalCollaborator(t *testing.T, documentType string) { alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") - // Alice shares invoice document with Bob first - res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) - if err != nil { - t.Error(err) - } + // Alice shares document with Bob first + res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -28,36 +34,37 @@ func TestHost_AddExternalCollaborator(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(alice.httpExpect, params) - getInvoiceAndCheck(bob.httpExpect, params) + getDocumentAndCheck(alice.httpExpect, documentType, params) + getDocumentAndCheck(bob.httpExpect, documentType, params) // Bob updates invoice and shares with Charlie as well - res, err = bob.host.updateInvoice(bob.httpExpect, http.StatusOK, docIdentifier, updatedInvoicePayload([]string{alice.id.String(), charlie.id.String()})) - if err != nil { - t.Error(err) - } + res = updateDocument(bob.httpExpect, documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{alice.id.String(), charlie.id.String()})) docIdentifier = getDocumentIdentifier(t, res) if docIdentifier == "" { t.Error("docIdentifier empty") } params["currency"] = "EUR" - getInvoiceAndCheck(alice.httpExpect, params) - getInvoiceAndCheck(bob.httpExpect, params) - getInvoiceAndCheck(charlie.httpExpect, params) + getDocumentAndCheck(alice.httpExpect, documentType, params) + getDocumentAndCheck(bob.httpExpect, documentType, params) + getDocumentAndCheck(charlie.httpExpect, documentType, params) } func TestHost_CollaboratorTimeOut(t *testing.T) { t.Parallel() + + //currently can't be run in parallel (because of node kill) + collaboratorTimeOut(t, typeInvoice) + collaboratorTimeOut(t, typePO) +} + +func collaboratorTimeOut(t *testing.T, documentType string) { + kenny := doctorFord.getHostTestSuite(t, "Kenny") bob := doctorFord.getHostTestSuite(t, "Bob") - // Kenny shares an invoice with Bob - response, err := kenny.host.createInvoice(kenny.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) - - if err != nil { - t.Error(err) - } + // Kenny shares a document with Bob + response := createDocument(kenny.httpExpect, documentType, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) // check if Bob and Kenny received the document docIdentifier := getDocumentIdentifier(t, response) @@ -65,32 +72,29 @@ func TestHost_CollaboratorTimeOut(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(kenny.httpExpect, paramsV1) - getInvoiceAndCheck(bob.httpExpect, paramsV1) + getDocumentAndCheck(kenny.httpExpect, documentType, paramsV1) + getDocumentAndCheck(bob.httpExpect, documentType, paramsV1) // Kenny gets killed kenny.host.kill() // Bob updates and sends to Alice - updatedPayload := updatedInvoicePayload([]string{kenny.id.String()}) + updatedPayload := updatedDocumentPayload(documentType, []string{kenny.id.String()}) // Bob will anchor the document without Alice signature but will receive an error because kenny is dead - response, err = bob.host.updateInvoice(bob.httpExpect, http.StatusInternalServerError, docIdentifier, updatedPayload) - if err != nil { - t.Error(err) - } + response = updateDocument(bob.httpExpect, documentType, http.StatusInternalServerError, docIdentifier, updatedPayload) // check if bob saved the updated document paramsV2 := map[string]interface{}{ "document_id": docIdentifier, "currency": "EUR", } - getInvoiceAndCheck(bob.httpExpect, paramsV2) + getDocumentAndCheck(bob.httpExpect, documentType, paramsV2) // bring Kenny back to life doctorFord.reLive(t, kenny.name) // Kenny should NOT have latest version - getInvoiceAndCheck(kenny.httpExpect, paramsV1) + getDocumentAndCheck(kenny.httpExpect, documentType, paramsV1) } diff --git a/testworld/httputils.go b/testworld/httputils.go index 8fcd2a8cf..d6a17acdf 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -8,6 +8,10 @@ import ( "github.com/gavv/httpexpect" ) +const typeInvoice string = "invoice" +const typePO string = "purchaseorder" +const poPrefix string = "po" + func createInsecureClientWithExpect(t *testing.T, baseURL string) *httpexpect.Expect { config := httpexpect.Config{ BaseURL: baseURL, @@ -20,10 +24,10 @@ func createInsecureClientWithExpect(t *testing.T, baseURL string) *httpexpect.Ex return httpexpect.WithConfig(config) } -func getInvoiceAndCheck(e *httpexpect.Expect, params map[string]interface{}) *httpexpect.Value { +func getDocumentAndCheck(e *httpexpect.Expect, documentType string, params map[string]interface{}) *httpexpect.Value { docIdentifier := params["document_id"].(string) - objGet := e.GET("/invoice/"+docIdentifier). + objGet := e.GET("/"+documentType+"/"+docIdentifier). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). Expect().Status(http.StatusOK).JSON().NotNull() @@ -33,8 +37,8 @@ func getInvoiceAndCheck(e *httpexpect.Expect, params map[string]interface{}) *ht return objGet } -func createInvoice(e *httpexpect.Expect, status int, payload map[string]interface{}) *httpexpect.Object { - obj := e.POST("/invoice"). +func createDocument(e *httpexpect.Expect, documentType string, status int, payload map[string]interface{}) *httpexpect.Object { + obj := e.POST("/"+documentType). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). WithJSON(payload). @@ -42,8 +46,8 @@ func createInvoice(e *httpexpect.Expect, status int, payload map[string]interfac return obj } -func updateInvoice(e *httpexpect.Expect, status int, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { - obj := e.PUT("/invoice/"+docIdentifier). +func updateDocument(e *httpexpect.Expect, documentType string, status int, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { + obj := e.PUT("/"+documentType+"/"+docIdentifier). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). WithJSON(payload). diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 15c913e50..7d09d8501 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -11,17 +11,27 @@ import ( const tokenIdLength = 77 -func TestPaymentObligationMint_successful(t *testing.T) { +func TestPaymentObligationMint_invoice_successful(t *testing.T) { t.Parallel() + paymentObligationMint(t, typeInvoice) + +} + +/* TODO: testcase not stable +func TestPaymentObligationMint_po_successful(t *testing.T) { + t.Parallel() + paymentObligationMint(t, typePO) + +} +*/ + +func paymentObligationMint(t *testing.T, documentType string) { alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") - // Alice shares invoice document with Bob - res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultNFTPayload([]string{bob.id.String()})) - if err != nil { - t.Error(err) - } + // Alice shares document with Bob + res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultNFTPayload(documentType, []string{bob.id.String()})) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -32,8 +42,13 @@ func TestPaymentObligationMint_successful(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(alice.httpExpect, params) - getInvoiceAndCheck(bob.httpExpect, params) + getDocumentAndCheck(alice.httpExpect, documentType, params) + getDocumentAndCheck(bob.httpExpect, documentType, params) + + proofPrefix := documentType + if proofPrefix == typePO { + proofPrefix = poPrefix + } // mint an NFT test := struct { @@ -46,7 +61,7 @@ func TestPaymentObligationMint_successful(t *testing.T) { "identifier": docIdentifier, "registryAddress": doctorFord.contractAddresses.PaymentObligationAddr, "depositAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", // dummy address - "proofFields": []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, + "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", "collaborators[0]"}, }, } diff --git a/testworld/park.go b/testworld/park.go index d001b4309..b9376886f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -36,7 +36,7 @@ var hostConfig = []struct { {"Kenny", 8087, 38207}, } -const defaultP2PTimeout = "2s" +const defaultP2PTimeout = "10s" // hostTestSuite encapsulates test utilities on top of each host type hostTestSuite struct { @@ -327,18 +327,10 @@ func (h *host) isLive(softTimeOut time.Duration) (bool, error) { } } -func (h *host) createInvoice(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { - return createInvoice(e, status, inv), nil -} - func (h *host) mintNFT(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { return mintNFT(e, status, inv), nil } -func (h *host) updateInvoice(e *httpexpect.Expect, status int, docIdentifier string, inv map[string]interface{}) (*httpexpect.Object, error) { - return updateInvoice(e, status, docIdentifier, inv), nil -} - func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { return createInsecureClientWithExpect(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) } diff --git a/testworld/park_test.go b/testworld/park_test.go index fab470377..e0bea509d 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -15,10 +15,7 @@ func TestHost_Happy(t *testing.T) { charlie := doctorFord.getHostTestSuite(t, "Charlie") // alice shares a document with bob and charlie - res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) - if err != nil { - t.Error(err) - } + res := createDocument(alice.httpExpect, typeInvoice, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) docIdentifier := getDocumentIdentifier(t, res) @@ -29,8 +26,8 @@ func TestHost_Happy(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getInvoiceAndCheck(alice.httpExpect, params) - getInvoiceAndCheck(bob.httpExpect, params) - getInvoiceAndCheck(charlie.httpExpect, params) + getDocumentAndCheck(alice.httpExpect, typeInvoice, params) + getDocumentAndCheck(bob.httpExpect, typeInvoice, params) + getDocumentAndCheck(charlie.httpExpect, typeInvoice, params) fmt.Println("Host test success") } diff --git a/testworld/payloads.go b/testworld/payloads.go index 65e4c09ea..684d6ae76 100644 --- a/testworld/payloads.go +++ b/testworld/payloads.go @@ -2,8 +2,33 @@ package testworld -func defaultInvoicePayload(collaborators []string) map[string]interface{} { +func defaultDocumentPayload(documentType string, collaborators []string) map[string]interface{} { + + switch documentType { + case typeInvoice: + return defaultInvoicePayload(collaborators) + case typePO: + return defaultPOPayload(collaborators) + default: + return defaultInvoicePayload(collaborators) + } + +} + +func defaultPOPayload(collaborators []string) map[string]interface{} { + return map[string]interface{}{ + "data": map[string]interface{}{ + "po_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "USD", + "net_amount": "40", + }, + "collaborators": collaborators, + } +} +func defaultInvoicePayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ "invoice_number": "12324", @@ -17,8 +42,7 @@ func defaultInvoicePayload(collaborators []string) map[string]interface{} { } -func defaultNFTPayload(collaborators []string) map[string]interface{} { - +func invoiceNFTPayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ "invoice_number": "12324", @@ -33,6 +57,59 @@ func defaultNFTPayload(collaborators []string) map[string]interface{} { } +func pONFTPayload(collaborators []string) map[string]interface{} { + return map[string]interface{}{ + "data": map[string]interface{}{ + "po_number": "123245", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "USD", + "net_amount": "40", + "document_type": "po", + }, + "collaborators": collaborators, + } + +} + +func defaultNFTPayload(documentType string, collaborators []string) map[string]interface{} { + + switch documentType { + case typeInvoice: + return invoiceNFTPayload(collaborators) + case typePO: + return pONFTPayload(collaborators) + default: + return invoiceNFTPayload(collaborators) + } + +} + +func updatedDocumentPayload(documentType string, collaborators []string) map[string]interface{} { + switch documentType { + case typeInvoice: + return updatedInvoicePayload(collaborators) + case typePO: + return updatedPOPayload(collaborators) + default: + return updatedInvoicePayload(collaborators) + } +} + +func updatedPOPayload(collaborators []string) map[string]interface{} { + return map[string]interface{}{ + "data": map[string]interface{}{ + "po_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "gross_amount": "40", + "currency": "EUR", + "net_amount": "42", + }, + "collaborators": collaborators, + } + +} + func updatedInvoicePayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ @@ -47,9 +124,16 @@ func updatedInvoicePayload(collaborators []string) map[string]interface{} { } -func defaultProofPayload() map[string]interface{} { +func defaultProofPayload(documentType string) map[string]interface{} { + if documentType == typeInvoice { + + return map[string]interface{}{ + "type": "http://github.com/centrifuge/centrifuge-protobufs/invoice/#invoice.InvoiceData", + "fields": []string{"invoice.net_amount", "invoice.currency"}, + } + } return map[string]interface{}{ - "type": "http://github.com/centrifuge/centrifuge-protobufs/invoice/#invoice.InvoiceData", - "fields": []string{"invoice.net_amount", "invoice.currency"}, + "type": "http://github.com/centrifuge/centrifuge-protobufs/purchaseorder/#purchaseorder.PurchaseOrderData", + "fields": []string{"po.net_amount", "po.currency"}, } } diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 1cf3720eb..c4f0882e2 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -9,36 +9,50 @@ import ( "github.com/gavv/httpexpect" ) -func TestProofWithMultipleFields_successful(t *testing.T) { +func TestProofWithMultipleFields_invoice_successful(t *testing.T) { + t.Parallel() + proofWithMultipleFields_successful(t, typeInvoice) + +} + +func TestProofWithMultipleFields_po_successful(t *testing.T) { + t.Parallel() + proofWithMultipleFields_successful(t, typePO) + +} + +func proofWithMultipleFields_successful(t *testing.T, documentType string) { alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") - // Alice shares invoice document with Bob - res, err := alice.host.createInvoice(alice.httpExpect, http.StatusOK, defaultNFTPayload([]string{bob.id.String()})) - if err != nil { - t.Error(err) - } + // Alice shares a document with Bob + res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { t.Error("docIdentifier empty") } - proofPayload := defaultProofPayload() + proofPayload := defaultProofPayload(documentType) proofFromAlice := getProof(alice.httpExpect, http.StatusOK, docIdentifier, proofPayload) proofFromBob := getProof(bob.httpExpect, http.StatusOK, docIdentifier, proofPayload) - checkProof(proofFromAlice, docIdentifier) - checkProof(proofFromBob, docIdentifier) + checkProof(proofFromAlice, documentType, docIdentifier) + checkProof(proofFromBob, documentType, docIdentifier) } -func checkProof(objProof *httpexpect.Object, docIdentifier string) { +func checkProof(objProof *httpexpect.Object, documentType string, docIdentifier string) { + + if documentType == typePO { + documentType = poPrefix + } + objProof.Path("$.header.document_id").String().Equal(docIdentifier) - objProof.Path("$.field_proofs[0].property").String().Equal("invoice.net_amount") + objProof.Path("$.field_proofs[0].property").String().Equal(documentType + ".net_amount") objProof.Path("$.field_proofs[0].sorted_hashes").NotNull() - objProof.Path("$.field_proofs[1].property").String().Equal("invoice.currency") + objProof.Path("$.field_proofs[1].property").String().Equal(documentType + ".currency") objProof.Path("$.field_proofs[1].sorted_hashes").NotNull() } From 408e49b4a95a29e962c882fa5965367b58509377 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 13 Dec 2018 12:24:45 +0100 Subject: [PATCH 081/220] Fixing some possible bugs because of colliding variable names with packages (#568) --- coredocument/validator_test.go | 24 ++++++++++++------------ documents/invoice/service.go | 4 ++-- documents/purchaseorder/service.go | 4 ++-- p2p/client.go | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 6dc80d751..e60db3ec8 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -31,21 +31,21 @@ func TestUpdateVersionValidator(t *testing.T) { // old model pack core doc fail old := mockModel{} - new := mockModel{} + newM := mockModel{} old.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err = uvv.Validate(old, new) + err = uvv.Validate(old, newM) old.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to fetch old core document") - // new model pack core doc fail + // newM model pack core doc fail oldCD := New() oldCD.DocumentRoot = utils.RandomSlice(32) old.On("PackCoreDocument").Return(oldCD, nil).Once() - new.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() - err = uvv.Validate(old, new) + newM.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + err = uvv.Validate(old, newM) old.AssertExpectations(t) - new.AssertExpectations(t) + newM.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to fetch new core document") @@ -53,10 +53,10 @@ func TestUpdateVersionValidator(t *testing.T) { newCD := New() newCD.NextVersion = nil old.On("PackCoreDocument").Return(oldCD, nil).Once() - new.On("PackCoreDocument").Return(newCD, nil).Once() - err = uvv.Validate(old, new) + newM.On("PackCoreDocument").Return(newCD, nil).Once() + err = uvv.Validate(old, newM) old.AssertExpectations(t) - new.AssertExpectations(t) + newM.AssertExpectations(t) assert.Error(t, err) assert.Equal(t, 5, errors.Len(err)) @@ -64,10 +64,10 @@ func TestUpdateVersionValidator(t *testing.T) { newCD, err = PrepareNewVersion(*oldCD, nil) assert.Nil(t, err) old.On("PackCoreDocument").Return(oldCD, nil).Once() - new.On("PackCoreDocument").Return(newCD, nil).Once() - err = uvv.Validate(old, new) + newM.On("PackCoreDocument").Return(newCD, nil).Once() + err = uvv.Validate(old, newM) old.AssertExpectations(t) - new.AssertExpectations(t) + newM.AssertExpectations(t) assert.Nil(t, err) } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 97b50c95b..223de38e1 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -282,7 +282,7 @@ func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.In collaborators[i] = cid.String() } - header := &clientinvoicepb.ResponseHeader{ + h := &clientinvoicepb.ResponseHeader{ DocumentId: hexutil.Encode(cd.DocumentIdentifier), VersionId: hexutil.Encode(cd.CurrentVersion), Collaborators: collaborators, @@ -294,7 +294,7 @@ func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.In } return &clientinvoicepb.InvoiceResponse{ - Header: header, + Header: h, Data: data, }, nil diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 23a6fb148..05264a17b 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -240,7 +240,7 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P collaborators[i] = cid.String() } - header := &clientpopb.ResponseHeader{ + h := &clientpopb.ResponseHeader{ DocumentId: hexutil.Encode(cd.DocumentIdentifier), VersionId: hexutil.Encode(cd.CurrentVersion), Collaborators: collaborators, @@ -252,7 +252,7 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P } return &clientpopb.PurchaseOrderResponse{ - Header: header, + Header: h, Data: data, }, nil } diff --git a/p2p/client.go b/p2p/client.go index 7733513e4..5d4155a6d 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -70,14 +70,14 @@ func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService return nil, err } - header := p2ppb.CentrifugeHeader{ + h := p2ppb.CentrifugeHeader{ NetworkIdentifier: s.config.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), SenderCentrifugeId: senderID, } req := &p2ppb.SignatureRequest{ - Header: &header, + Header: &h, Document: &doc, } From 4d752969ba53d51d42572b9bf2c1fa3d91284990 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 13 Dec 2018 15:02:55 +0100 Subject: [PATCH 082/220] Remove fmt.Errorf in favour of errors.New (#559) * Migrate documents package to use new errors * typeerror -> typederror * Fix failing tests * Migrate invoice service to new repo * Fix fmt errors * Migrate new repository to new errors * Fix test * Fix test * Fix lint issue * Fix error name * Fix error name * Migrate PO service to new repository * Remove legacy repo * Remove fmt.Errorf in favour of errors.New * Fix problems * Fix lint * Missed stuff --- anchors/anchor.go | 3 +- anchors/anchor_confirmation_task.go | 19 ++++---- anchors/anchor_confirmation_task_test.go | 6 +-- anchors/bootstrapper.go | 2 +- anchors/ethereum_anchor_repository.go | 10 ++-- anchors/test_bootstrapper.go | 2 +- api/bootstrapper.go | 7 ++- api/server.go | 3 +- api/service.go | 11 ++--- centerrors/error_test.go | 4 +- config/bootstrapper.go | 2 +- config/configuration.go | 5 +- coredocument/coredocument.go | 35 +++++++------- coredocument/processor.go | 48 +++++++++---------- coredocument/processor_test.go | 22 ++++----- coredocument/validator.go | 38 +++++++-------- coredocument/validator_test.go | 19 ++++---- documents/anchor.go | 12 ++--- documents/error.go | 2 +- documents/invoice/bootstrapper.go | 15 +++--- documents/invoice/handler_test.go | 18 +++---- documents/invoice/model.go | 21 ++++---- documents/invoice/service.go | 11 ++--- documents/invoice/service_test.go | 7 ++- documents/invoice/validator.go | 20 ++++---- documents/invoice/validator_test.go | 3 +- documents/purchaseorder/bootstrapper.go | 15 +++--- documents/purchaseorder/handler.go | 3 +- documents/purchaseorder/handler_test.go | 16 +++---- documents/purchaseorder/model.go | 16 +++---- documents/purchaseorder/service.go | 11 ++--- documents/purchaseorder/service_test.go | 9 ++-- documents/purchaseorder/validator.go | 20 ++++---- documents/purchaseorder/validator_test.go | 3 +- documents/registry.go | 9 ++-- documents/repository.go | 15 +++--- documents/test/anchor_test.go | 14 +++--- documents/test_bootstrapper.go | 2 +- documents/validator_test.go | 3 +- errors/errors_test.go | 3 +- ethereum/bootstrapper.go | 2 +- ethereum/geth_client.go | 26 +++++----- ethereum/geth_client_test.go | 13 +++-- header/context.go | 4 +- identity/bootstrapper.go | 2 +- identity/ethereum_identity.go | 27 +++++------ identity/ethereum_identity_test.go | 2 +- identity/id_registration_confirmation_task.go | 8 ++-- identity/identity.go | 5 +- identity/identity_test.go | 8 ++-- .../key_registration_confirmation_task.go | 16 +++---- identity/util.go | 2 +- keytools/ed25519/ed25519.go | 11 ++--- keytools/secp256k1/secp256k1.go | 5 +- keytools/sign.go | 6 +-- nft/bootstrapper.go | 7 ++- nft/ethereum_payment_obligation.go | 4 +- nft/ethereum_payment_obligation_test.go | 3 +- nft/handler_test.go | 2 +- nft/minting_confirmation_task.go | 12 ++--- node/bootstrapper.go | 10 ++-- node/node_test.go | 3 +- notification/notification.go | 4 +- p2p/bootstrapper.go | 7 ++- p2p/client.go | 3 +- p2p/client_test.go | 4 +- p2p/handler.go | 9 ++-- p2p/handler_test.go | 3 +- p2p/server.go | 9 ++-- p2p/validator.go | 4 +- queue/bootstrapper.go | 2 +- queue/server.go | 3 +- signatures/signatures.go | 4 +- storage/bootstrapper.go | 5 +- storage/test_bootstrapper.go | 3 +- testworld/park.go | 9 ++-- utils/events_test.go | 4 +- utils/io.go | 7 +-- utils/tools.go | 3 +- 79 files changed, 367 insertions(+), 378 deletions(-) diff --git a/anchors/anchor.go b/anchors/anchor.go index 5bb046289..1c1d739e5 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -1,9 +1,10 @@ package anchors import ( - "errors" "math/big" + "github.com/centrifuge/go-centrifuge/errors" + "time" "github.com/centrifuge/go-centrifuge/identity" diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go index f977be8ee..6b5e52993 100644 --- a/anchors/anchor_confirmation_task.go +++ b/anchors/anchor_confirmation_task.go @@ -2,18 +2,17 @@ package anchors import ( "context" - "fmt" "math/big" "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/go-errors/errors" ) const ( @@ -71,12 +70,12 @@ func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { anchorID, ok := kwargs[anchorIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + anchorIDParam) + return errors.New("undefined kwarg " + anchorIDParam) } anchorIDBytes, err := getBytesAnchorID(anchorID) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", anchorIDParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", anchorIDParam, err.Error()) } act.AnchorID = anchorIDBytes @@ -84,12 +83,12 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er //parse the centrifuge id centID, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + centIDParam) + return errors.New("undefined kwarg " + centIDParam) } centIDBytes, err := getBytesCentrifugeID(centID) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } act.CentrifugeID = centIDBytes @@ -97,17 +96,17 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er // parse the address address, ok := kwargs[addressParam] if !ok { - return fmt.Errorf("undefined kwarg " + addressParam) + return errors.New("undefined kwarg " + addressParam) } addressStr, ok := address.(string) if !ok { - return fmt.Errorf("param is not hex string " + addressParam) + return errors.New("param is not hex string " + addressParam) } addressTyped, err := getAddressFromHexString(addressStr) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", addressParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", addressParam, err.Error()) } act.From = addressTyped @@ -123,7 +122,7 @@ func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) er if ok { td, err := queue.GetDuration(tdRaw) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } act.Timeout = td } diff --git a/anchors/anchor_confirmation_task_test.go b/anchors/anchor_confirmation_task_test.go index 36427f161..35f610abd 100644 --- a/anchors/anchor_confirmation_task_test.go +++ b/anchors/anchor_confirmation_task_test.go @@ -4,11 +4,11 @@ package anchors import ( "context" - "fmt" "math/big" "testing" "time" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/testingutils" @@ -130,7 +130,7 @@ func TestAnchoringConfirmationTask_RunTaskIterError(t *testing.T) { act := anchorConfirmationTask{ AnchorID: anchorID, From: address, - AnchorCommittedFilterer: &MockAnchorCommittedFilter{err: fmt.Errorf("failed iterator")}, + AnchorCommittedFilterer: &MockAnchorCommittedFilter{err: errors.New("failed iterator")}, EthContext: context.Background(), } @@ -148,7 +148,7 @@ func TestAnchoringConfirmationTask_RunTaskWatchError(t *testing.T) { AnchorID: anchorID, From: address, AnchorCommittedFilterer: &MockAnchorCommittedFilter{iter: &EthereumAnchorRepositoryContractAnchorCommittedIterator{ - fail: fmt.Errorf("watch error"), + fail: errors.New("watch error"), sub: &testingutils.MockSubscription{}, }}, EthContext: ctx, diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 50c2dba17..1c8e8e648 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -1,7 +1,7 @@ package anchors import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index ddf7db2d1..ab2defb0a 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -6,6 +6,7 @@ import ( "time" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -13,7 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" - "github.com/go-errors/errors" ) type anchorRepositoryContract interface { @@ -61,7 +61,7 @@ func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(anchorID AnchorID err = sendPreCommitTransaction(ethRepositoryContract, opts, preCommitData) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Errorf("Failed to send Ethereum pre-commit transaction [id: %x, signingRoot: %x, SchemaVersion:%v]: %v", preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.SchemaVersion, wError) return confirmations, err @@ -87,7 +87,7 @@ func (ethRepository *ethereumAnchorRepository) CommitAnchor(anchorID AnchorID, d confirmations, err = ethRepository.setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Errorf("Failed to set up event listener for commit transaction [id: %x, hash: %x]: %v", cd.AnchorID, cd.DocumentRoot, wError) return @@ -95,7 +95,7 @@ func (ethRepository *ethereumAnchorRepository) CommitAnchor(anchorID AnchorID, d err = sendCommitTransaction(ethRepository.anchorRepositoryContract, opts, cd) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Errorf("Failed to send Ethereum commit transaction[id: %x, hash: %x, SchemaVersion:%v]: %v", cd.AnchorID, cd.DocumentRoot, cd.SchemaVersion, wError) return @@ -163,7 +163,7 @@ func setUpPreCommitEventListener(contractEvent watchAnchorPreCommitted, from com // Subscriptions a bit better before writing this code. _, err = contractEvent.WatchAnchorPreCommitted(watchOpts, anchorPreCommittedEvents, []common.Address{from}, []*big.Int{preCommitData.AnchorID.BigInt()}) if err != nil { - wError := errors.WrapPrefix(err, "Could not subscribe to event logs for anchor registration", 1) + wError := errors.New("Could not subscribe to event logs for anchor registration: %v", err) log.Errorf("Failed to watch anchor registered event: %v", wError.Error()) cancelFunc() // cancel the event router return confirmations, wError diff --git a/anchors/test_bootstrapper.go b/anchors/test_bootstrapper.go index dda502e8f..35d8fe55b 100644 --- a/anchors/test_bootstrapper.go +++ b/anchors/test_bootstrapper.go @@ -3,7 +3,7 @@ package anchors import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/config" ) diff --git a/api/bootstrapper.go b/api/bootstrapper.go index bbe4bb7d7..ff8d4b8de 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -1,11 +1,10 @@ package api import ( - "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" ) // Bootstrapper implements bootstrapper.Bootstrapper @@ -15,13 +14,13 @@ type Bootstrapper struct{} func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg, ok := ctx[config.BootstrappedConfig].(Config) if !ok { - return fmt.Errorf("config not initialised") + return errors.New("config not initialised") } // just check to make sure that registry is initialised _, ok = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("service registry not initialised") + return errors.New("service registry not initialised") } srv := apiServer{config: cfg} diff --git a/api/server.go b/api/server.go index 675de006f..b0e77cc65 100644 --- a/api/server.go +++ b/api/server.go @@ -3,7 +3,6 @@ package api import ( "crypto/tls" "crypto/x509" - "errors" "net" "net/http" _ "net/http/pprof" // we need this side effect that loads the pprof endpoints to defaultServerMux @@ -11,6 +10,8 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/grpc-ecosystem/grpc-gateway/runtime" logging "github.com/ipfs/go-log" diff --git a/api/service.go b/api/service.go index 92e307f4b..70a9e1135 100644 --- a/api/service.go +++ b/api/service.go @@ -1,13 +1,12 @@ package api import ( - "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/healthcheck" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" @@ -25,17 +24,17 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, // node object registry nodeObjReg, ok := ctx.Value(bootstrap.NodeObjRegistry).(map[string]interface{}) if !ok { - return fmt.Errorf("failed to get %s", bootstrap.NodeObjRegistry) + return errors.New("failed to get %s", bootstrap.NodeObjRegistry) } // load dependencies registry, ok := nodeObjReg[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("failed to get %s", documents.BootstrappedRegistry) + return errors.New("failed to get %s", documents.BootstrappedRegistry) } payObService, ok := nodeObjReg[nft.BootstrappedPayObService].(nft.PaymentObligation) if !ok { - return fmt.Errorf("failed to get %s", nft.BootstrappedPayObService) + return errors.New("failed to get %s", nft.BootstrappedPayObService) } // documents (common) @@ -61,7 +60,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, poCfg := cfg.(config.Configuration) srv, err := purchaseorder.GRPCHandler(poCfg, registry) if err != nil { - return fmt.Errorf("failed to get purchase order handler: %v", err) + return errors.New("failed to get purchase order handler: %v", err) } purchaseorderpb.RegisterDocumentServiceServer(grpcServer, srv) diff --git a/centerrors/error_test.go b/centerrors/error_test.go index 87588c108..ce386f589 100644 --- a/centerrors/error_test.go +++ b/centerrors/error_test.go @@ -3,11 +3,11 @@ package centerrors import ( - "fmt" "reflect" "testing" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/errors" "github.com/magiconair/properties/assert" ) @@ -62,7 +62,7 @@ func TestP2PError(t *testing.T) { func TestWrap(t *testing.T) { // simple error - err := fmt.Errorf("simple-error") + err := errors.New("simple-error") err = Wrap(err, "wrapped error") assert.Equal(t, err.Error(), "wrapped error: simple-error") diff --git a/config/bootstrapper.go b/config/bootstrapper.go index 11e1a62db..a0d0426c2 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -1,7 +1,7 @@ package config import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" ) // Bootstrap constants are keys to the value mappings in context bootstrap. diff --git a/config/configuration.go b/config/configuration.go index a07da71cd..96aed72ad 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -7,7 +7,6 @@ package config import ( "bytes" - "errors" "fmt" "io/ioutil" "math/big" @@ -16,6 +15,8 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/resources" "github.com/ethereum/go-ethereum/common" @@ -230,7 +231,7 @@ func (c *configuration) GetEthereumAccount(accountName string) (account *Account k := fmt.Sprintf("ethereum.accounts.%s", accountName) if !c.IsSet(k) { - return nil, fmt.Errorf("no account found with account name %s", accountName) + return nil, errors.New("no account found with account name %s", accountName) } // Workaround for bug https://github.com/spf13/viper/issues/309 && https://github.com/spf13/viper/issues/513 diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index 7a9bc5786..d3bb495d9 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -61,7 +62,7 @@ func CalculateSigningRoot(doc *coredocumentpb.CoreDocument) error { // CalculateDocumentRoot calculates the document root of the core document func CalculateDocumentRoot(document *coredocumentpb.CoreDocument) error { if len(document.SigningRoot) != 32 { - return fmt.Errorf("signing root invalid") + return errors.New("signing root invalid") } tree, err := GetDocumentRootTree(document) @@ -126,7 +127,7 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs } if document.EmbeddedData == nil { - return nil, fmt.Errorf("EmbeddedData cannot be nil when generating signing tree") + return nil, errors.New("EmbeddedData cannot be nil when generating signing tree") } // Adding document type as it is an excluded field in the tree documentTypeNode := proofs.LeafNode{ @@ -157,22 +158,22 @@ func PrepareNewVersion(oldCD coredocumentpb.CoreDocument, collaborators []string } if oldCD.DocumentIdentifier == nil { - return nil, fmt.Errorf("coredocument.DocumentIdentifier is nil") + return nil, errors.New("coredocument.DocumentIdentifier is nil") } newCD.DocumentIdentifier = oldCD.DocumentIdentifier if oldCD.CurrentVersion == nil { - return nil, fmt.Errorf("coredocument.CurrentVersion is nil") + return nil, errors.New("coredocument.CurrentVersion is nil") } newCD.PreviousVersion = oldCD.CurrentVersion if oldCD.NextVersion == nil { - return nil, fmt.Errorf("coredocument.NextVersion is nil") + return nil, errors.New("coredocument.NextVersion is nil") } newCD.CurrentVersion = oldCD.NextVersion newCD.NextVersion = utils.RandomSlice(32) if oldCD.DocumentRoot == nil { - return nil, fmt.Errorf("coredocument.DocumentRoot is nil") + return nil, errors.New("coredocument.DocumentRoot is nil") } newCD.PreviousRoot = oldCD.DocumentRoot return newCD, nil @@ -194,7 +195,7 @@ func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, cd := New() ids, err := identity.CentIDsFromStrings(collaborators) if err != nil { - return nil, fmt.Errorf("failed to decode collaborator: %v", err) + return nil, errors.New("failed to decode collaborator: %v", err) } for i := range ids { @@ -216,7 +217,7 @@ func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.Co for _, collab := range doc.Collaborators { collabID, err := identity.ToCentID(collab) if err != nil { - return nil, fmt.Errorf("failed to convert to CentID: %v", err) + return nil, errors.New("failed to convert to CentID: %v", err) } if !selfCentID.Equal(collabID) { collabs = append(collabs, collab) @@ -231,7 +232,7 @@ func FillSalts(doc *coredocumentpb.CoreDocument) error { salts := &coredocumentpb.CoreDocumentSalts{} err := proofs.FillSalts(doc, salts) if err != nil { - return fmt.Errorf("failed to fill coredocument salts: %v", err) + return errors.New("failed to fill coredocument salts: %v", err) } doc.CoredocumentSalts = salts @@ -242,15 +243,15 @@ func FillSalts(doc *coredocumentpb.CoreDocument) error { func GetTypeURL(coreDocument *coredocumentpb.CoreDocument) (string, error) { if coreDocument == nil { - return "", fmt.Errorf("core document is nil") + return "", errors.New("core document is nil") } if coreDocument.EmbeddedData == nil { - return "", fmt.Errorf("core document doesn't have embedded data") + return "", errors.New("core document doesn't have embedded data") } if coreDocument.EmbeddedData.TypeUrl == "" { - return "", fmt.Errorf("typeUrl not set properly") + return "", errors.New("typeUrl not set properly") } return coreDocument.EmbeddedData.TypeUrl, nil } @@ -259,17 +260,17 @@ func GetTypeURL(coreDocument *coredocumentpb.CoreDocument) (string, error) { func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDocument, fields []string) (proofs []*proofspb.Proof, err error) { dataRootHashes, err := getDataProofHashes(coreDoc) if err != nil { - return nil, fmt.Errorf("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } signingRootHashes, err := getSigningProofHashes(coreDoc) if err != nil { - return nil, fmt.Errorf("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } cdtree, err := GetDocumentSigningTree(coreDoc) if err != nil { - return nil, fmt.Errorf("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } // We support fields that belong to different document trees, as we do not prepend a tree prefix to the field, the approach @@ -281,11 +282,11 @@ func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDoc if strings.Contains(err.Error(), "No such field") { proof, err = cdtree.CreateProof(field) if err != nil { - return nil, fmt.Errorf("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } rootHashes = signingRootHashes } else { - return nil, fmt.Errorf("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } } proof.SortedHashes = append(proof.SortedHashes, rootHashes...) diff --git a/coredocument/processor.go b/coredocument/processor.go index ffd74b77a..fc9b8452d 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -86,7 +86,7 @@ func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredoc clientWithProtocol := fmt.Sprintf("/ipfs/%s", lastB58Key) client, err := dp.p2pClient.OpenClient(clientWithProtocol) if err != nil { - return fmt.Errorf("failed to open client: %v", err) + return errors.New("failed to open client: %v", err) } log.Infof("Done opening connection against [%s]\n", lastB58Key) @@ -111,13 +111,13 @@ func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredoc func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack core document: %v", err) + return errors.New("failed to pack core document: %v", err) } // calculate the signing root err = CalculateSigningRoot(cd) if err != nil { - return fmt.Errorf("failed to calculate signing root: %v", err) + return errors.New("failed to calculate signing root: %v", err) } sig := identity.Sign(ctx.Self(), identity.KeyPurposeSigning, cd.SigningRoot) @@ -125,7 +125,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader err = model.UnpackCoreDocument(cd) if err != nil { - return fmt.Errorf("failed to unpack the core document: %v", err) + return errors.New("failed to unpack the core document: %v", err) } return nil @@ -136,28 +136,28 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader func (dp defaultProcessor) RequestSignatures(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack core document: %v", err) + return errors.New("failed to pack core document: %v", err) } idKeys, ok := ctx.Self().Keys[identity.KeyPurposeSigning] if !ok { - return fmt.Errorf("missing keys for signing") + return errors.New("missing keys for signing") } psv := PreSignatureRequestValidator(ctx.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) err = psv.Validate(nil, model) if err != nil { - return fmt.Errorf("failed to validate model for signature request: %v", err) + return errors.New("failed to validate model for signature request: %v", err) } err = dp.p2pClient.GetSignaturesForDocument(ctx, dp.identityService, cd) if err != nil { - return fmt.Errorf("failed to collect signatures from the collaborators: %v", err) + return errors.New("failed to collect signatures from the collaborators: %v", err) } err = model.UnpackCoreDocument(cd) if err != nil { - return fmt.Errorf("failed to unpack core document: %v", err) + return errors.New("failed to unpack core document: %v", err) } return nil @@ -167,23 +167,23 @@ func (dp defaultProcessor) RequestSignatures(ctx *header.ContextHeader, model do func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack core document: %v", err) + return errors.New("failed to pack core document: %v", err) } psv := PostSignatureRequestValidator(dp.identityService) err = psv.Validate(nil, model) if err != nil { - return fmt.Errorf("failed to validate signatures: %v", err) + return errors.New("failed to validate signatures: %v", err) } err = CalculateDocumentRoot(cd) if err != nil { - return fmt.Errorf("failed to generate document root: %v", err) + return errors.New("failed to generate document root: %v", err) } err = model.UnpackCoreDocument(cd) if err != nil { - return fmt.Errorf("failed to unpack core document: %v", err) + return errors.New("failed to unpack core document: %v", err) } return nil @@ -193,45 +193,45 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { func (dp defaultProcessor) AnchorDocument(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack core document: %v", err) + return errors.New("failed to pack core document: %v", err) } pav := PreAnchorValidator(dp.identityService) err = pav.Validate(nil, model) if err != nil { - return fmt.Errorf("pre anchor validation failed: %v", err) + return errors.New("pre anchor validation failed: %v", err) } rootHash, err := anchors.ToDocumentRoot(cd.DocumentRoot) if err != nil { - return fmt.Errorf("failed to get document root: %v", err) + return errors.New("failed to get document root: %v", err) } id, err := dp.config.GetIdentityID() if err != nil { - return fmt.Errorf("failed to get self cent ID: %v", err) + return errors.New("failed to get self cent ID: %v", err) } centID, err := identity.ToCentID(id) if err != nil { - return fmt.Errorf("centID invalid: %v", err) + return errors.New("centID invalid: %v", err) } anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { - return fmt.Errorf("failed to get anchor ID: %v", err) + return errors.New("failed to get anchor ID: %v", err) } // generate message authentication code for the anchor call mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), ctx.Self().Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { - return fmt.Errorf("failed to generate ethereum MAC: %v", err) + return errors.New("failed to generate ethereum MAC: %v", err) } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) confirmations, err := dp.anchorRepository.CommitAnchor(anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) if err != nil { - return fmt.Errorf("failed to commit anchor: %v", err) + return errors.New("failed to commit anchor: %v", err) } <-confirmations @@ -243,18 +243,18 @@ func (dp defaultProcessor) AnchorDocument(ctx *header.ContextHeader, model docum func (dp defaultProcessor) SendDocument(ctx *header.ContextHeader, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack core document: %v", err) + return errors.New("failed to pack core document: %v", err) } av := PostAnchoredValidator(dp.identityService, dp.anchorRepository) err = av.Validate(nil, model) if err != nil { - return fmt.Errorf("post anchor validations failed: %v", err) + return errors.New("post anchor validations failed: %v", err) } extCollaborators, err := GetExternalCollaborators(ctx.Self().ID, cd) if err != nil { - return fmt.Errorf("get external collaborators failed: %v", err) + return errors.New("get external collaborators failed: %v", err) } for _, c := range extCollaborators { diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index e58b69806..b4826fa89 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -4,12 +4,12 @@ package coredocument import ( "context" - "fmt" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -47,7 +47,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() ctxh, err := header.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) err = dp.PrepareForSignatureRequests(ctxh, model) @@ -79,7 +79,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // failed unpack model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() + model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -118,7 +118,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { assert.Nil(t, err) // pack failed model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -148,7 +148,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { assert.Nil(t, err) model.AssertExpectations(t) c := p2pClient{} - c.On("GetSignaturesForDocument", ctxh, cd).Return(fmt.Errorf("error")).Once() + c.On("GetSignaturesForDocument", ctxh, cd).Return(errors.New("error")).Once() dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) @@ -164,7 +164,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() + model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) @@ -189,7 +189,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err := dp.PrepareForAnchoring(model) model.AssertExpectations(t) assert.Error(t, err) @@ -216,7 +216,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { assert.Nil(t, err) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(fmt.Errorf("error")).Once() + model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) @@ -267,7 +267,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // pack failed model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -327,7 +327,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() repo := mockRepo{} - repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error")).Once() + repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("error")).Once() dp.anchorRepository = repo err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) @@ -362,7 +362,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Nil(t, err) // pack failed model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) diff --git a/coredocument/validator.go b/coredocument/validator.go index b16830edb..ff39ff592 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -18,17 +18,17 @@ import ( func UpdateVersionValidator() documents.Validator { return documents.ValidatorFunc(func(old, new documents.Model) error { if old == nil || new == nil { - return fmt.Errorf("need both the old and new model") + return errors.New("need both the old and new model") } oldCD, err := old.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to fetch old core document: %v", err) + return errors.New("failed to fetch old core document: %v", err) } newCD, err := new.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to fetch new core document: %v", err) + return errors.New("failed to fetch new core document: %v", err) } checks := []struct { @@ -82,12 +82,12 @@ func UpdateVersionValidator() documents.Validator { // getCoreDocument takes an model and returns the core document of the model func getCoreDocument(model documents.Model) (*coredocumentpb.CoreDocument, error) { if model == nil { - return nil, fmt.Errorf("nil model") + return nil, errors.New("nil model") } cd, err := model.PackCoreDocument() if err != nil { - return nil, fmt.Errorf("failed to pack core document: %v", err) + return nil, errors.New("failed to pack core document: %v", err) } return cd, nil @@ -102,7 +102,7 @@ func baseValidator() documents.Validator { } if cd == nil { - return fmt.Errorf("nil document") + return errors.New("nil document") } if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { @@ -156,16 +156,16 @@ func signingRootValidator() documents.Validator { } if utils.IsEmptyByteSlice(cd.SigningRoot) { - return fmt.Errorf("signing root missing") + return errors.New("signing root missing") } tree, err := GetDocumentSigningTree(cd) if err != nil { - return fmt.Errorf("failed to calculate signing root: %v", err) + return errors.New("failed to calculate signing root: %v", err) } if !utils.IsSameByteSlice(cd.SigningRoot, tree.RootHash()) { - return fmt.Errorf("signing root mismatch") + return errors.New("signing root mismatch") } return nil @@ -182,16 +182,16 @@ func documentRootValidator() documents.Validator { } if utils.IsEmptyByteSlice(cd.DocumentRoot) { - return fmt.Errorf("document root missing") + return errors.New("document root missing") } tree, err := GetDocumentRootTree(cd) if err != nil { - return fmt.Errorf("failed to calculate document root: %v", err) + return errors.New("failed to calculate document root: %v", err) } if !utils.IsSameByteSlice(cd.DocumentRoot, tree.RootHash()) { - return fmt.Errorf("document root mismatch") + return errors.New("document root mismatch") } return nil @@ -210,7 +210,7 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) documents.Valida } if len(cd.Signatures) != 1 { - return fmt.Errorf("expecting only one signature") + return errors.New("expecting only one signature") } s := signatures.Sign(centIDBytes, priv, pub, cd.SigningRoot) @@ -243,7 +243,7 @@ func signaturesValidator(idService identity.Service) documents.Validator { } if len(cd.Signatures) < 1 { - return fmt.Errorf("atleast one signature expected") + return errors.New("atleast one signature expected") } for _, sig := range cd.Signatures { @@ -266,26 +266,26 @@ func anchoredValidator(repo anchors.AnchorRepository) documents.Validator { return documents.ValidatorFunc(func(_, new documents.Model) error { cd, err := getCoreDocument(new) if err != nil { - return fmt.Errorf("failed to get core document: %v", err) + return errors.New("failed to get core document: %v", err) } anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { - return fmt.Errorf("failed to get anchorID: %v", err) + return errors.New("failed to get anchorID: %v", err) } docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) if err != nil { - return fmt.Errorf("failed to get document root: %v", err) + return errors.New("failed to get document root: %v", err) } gotRoot, err := repo.GetDocumentRootOf(anchorID) if err != nil { - return fmt.Errorf("failed to get document root from chain: %v", err) + return errors.New("failed to get document root from chain: %v", err) } if !utils.IsSameByteSlice(docRoot[:], gotRoot[:]) { - return fmt.Errorf("mismatched document roots") + return errors.New("mismatched document roots") } return nil diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index e60db3ec8..3b7a64e6f 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -3,7 +3,6 @@ package coredocument import ( - "fmt" "testing" "context" @@ -32,7 +31,7 @@ func TestUpdateVersionValidator(t *testing.T) { // old model pack core doc fail old := mockModel{} newM := mockModel{} - old.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + old.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = uvv.Validate(old, newM) old.AssertExpectations(t) assert.Error(t, err) @@ -42,7 +41,7 @@ func TestUpdateVersionValidator(t *testing.T) { oldCD := New() oldCD.DocumentRoot = utils.RandomSlice(32) old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + newM.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = uvv.Validate(old, newM) old.AssertExpectations(t) newM.AssertExpectations(t) @@ -79,7 +78,7 @@ func Test_getCoreDocument(t *testing.T) { // pack core document fail model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() cd, err = getCoreDocument(model) model.AssertExpectations(t) assert.Error(t, err) @@ -100,7 +99,7 @@ func TestValidator_baseValidator(t *testing.T) { // fail getCoreDocument model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() err := bv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -127,7 +126,7 @@ func TestValidator_signingRootValidator(t *testing.T) { // fail getCoreDoc model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() err := sv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -171,7 +170,7 @@ func TestValidator_documentRootValidator(t *testing.T) { // fail getCoreDoc model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() err := dv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -214,7 +213,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { // fail getCoreDoc model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -263,7 +262,7 @@ func TestValidator_signatureValidator(t *testing.T) { // fail getCoreDoc model := mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("err")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() err := ssv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -350,7 +349,7 @@ func TestValidator_anchoredValidator(t *testing.T) { r := &repo{} av = anchoredValidator(r) cd.CurrentVersion = anchorID[:] - r.On("GetDocumentRootOf", anchorID).Return(nil, fmt.Errorf("error")).Once() + r.On("GetDocumentRootOf", anchorID).Return(nil, errors.New("error")).Once() cd.DocumentRoot = utils.RandomSlice(32) model = &mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() diff --git a/documents/anchor.go b/documents/anchor.go index 8c1646382..558c468d5 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -1,8 +1,6 @@ package documents import ( - "fmt" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" ) @@ -32,7 +30,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor id := cd.CurrentVersion err = proc.PrepareForSignatureRequests(ctx, model) if err != nil { - return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to prepare document for signatures: %v", err)) + return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to prepare document for signatures: %v", err)) } err = updater(id, model) @@ -42,7 +40,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.RequestSignatures(ctx, model) if err != nil { - return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to collect signatures: %v", err)) + return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to collect signatures: %v", err)) } err = updater(id, model) @@ -52,7 +50,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.PrepareForAnchoring(model) if err != nil { - return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to prepare for anchoring: %v", err)) + return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to prepare for anchoring: %v", err)) } err = updater(id, model) @@ -62,7 +60,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.AnchorDocument(ctx, model) if err != nil { - return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to anchor document: %v", err)) + return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to anchor document: %v", err)) } err = updater(id, model) @@ -72,7 +70,7 @@ func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor err = proc.SendDocument(ctx, model) if err != nil { - return nil, errors.NewTypedError(ErrDocumentAnchoring, fmt.Errorf("failed to send anchored document: %v", err)) + return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to send anchored document: %v", err)) } err = updater(id, model) diff --git a/documents/error.go b/documents/error.go index 5f0ecbfdb..40cd52fef 100644 --- a/documents/error.go +++ b/documents/error.go @@ -92,6 +92,6 @@ func (e Error) Error() string { // NewError creates a new error from a key and a msg. // Deprecated: in favour of Error type in `github.com/centrifuge/go-centrifuge/errors` func NewError(key, msg string) error { - err := fmt.Errorf(msg) + err := errors.New(msg) return Error{key: key, err: err} } diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index dc7b9b1d3..7f47d4fc8 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,8 +1,7 @@ package invoice import ( - "errors" - "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" @@ -26,27 +25,27 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { - return fmt.Errorf("p2p client not initialised") + return errors.New("p2p client not initialised") } registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("service registry not initialised") + return errors.New("service registry not initialised") } anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) if !ok { - return fmt.Errorf("anchor repository not initialised") + return errors.New("anchor repository not initialised") } idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { - return fmt.Errorf("identity service not initialised") + return errors.New("identity service not initialised") } repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) if !ok { - return fmt.Errorf("document db repository not initialised") + return errors.New("document db repository not initialised") } repo.Register(&Invoice{}) @@ -54,7 +53,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { - return fmt.Errorf("failed to register invoice service: %v", err) + return errors.New("failed to register invoice service: %v", err) } return nil diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index aeb203270..cdf518c1b 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -4,11 +4,11 @@ package invoice import ( "context" - "fmt" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" @@ -77,7 +77,7 @@ func TestGRPCHandler_Create_derive_fail(t *testing.T) { // DeriveFrom payload fails h := getHandler() srv := h.service.(*mockService) - srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("derive failed")).Once() + srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(nil, errors.New("derive failed")).Once() _, err := h.Create(context.Background(), nil) srv.AssertExpectations(t) assert.Error(t, err, "must be non nil") @@ -88,7 +88,7 @@ func TestGRPCHandler_Create_create_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(new(Invoice), nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("create failed")).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(nil, errors.New("create failed")).Once() payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}} _, err := h.Create(context.Background(), payload) srv.AssertExpectations(t) @@ -120,7 +120,7 @@ func TestGRPCHandler_Create_DeriveInvoiceResponse_fail(t *testing.T) { model := new(Invoice) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() srv.On("Create", mock.Anything, mock.Anything).Return(model, nil).Once() - srv.On("DeriveInvoiceResponse", mock.Anything).Return(nil, fmt.Errorf("derive response failed")) + srv.On("DeriveInvoiceResponse", mock.Anything).Return(nil, errors.New("derive response failed")) payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{Currency: "EUR"}} _, err := h.Create(context.Background(), payload) srv.AssertExpectations(t) @@ -156,7 +156,7 @@ func TestGrpcHandler_Get_invalid_input(t *testing.T) { assert.EqualError(t, err, "identifier is an invalid hex string: hex string without 0x prefix") payload.Identifier = identifier - srv.On("GetCurrentVersion", identifierBytes).Return(nil, fmt.Errorf("not found")) + srv.On("GetCurrentVersion", identifierBytes).Return(nil, errors.New("not found")) res, err = h.Get(context.Background(), payload) srv.AssertExpectations(t) assert.Nil(t, res) @@ -195,7 +195,7 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { payload.Version = "0x00" payload.Identifier = "0x01" - mockErr := fmt.Errorf("not found") + mockErr := errors.New("not found") srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(nil, mockErr) res, err = h.GetVersion(context.Background(), payload) srv.AssertExpectations(t) @@ -224,7 +224,7 @@ func TestGrpcHandler_Update_derive_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} - srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(nil, fmt.Errorf("derive error")).Once() + srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(nil, errors.New("derive error")).Once() res, err := h.Update(context.Background(), payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -241,7 +241,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, fmt.Errorf("update error")).Once() + srv.On("Update", ctxh, model).Return(nil, errors.New("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -259,7 +259,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() - srv.On("DeriveInvoiceResponse", model).Return(nil, fmt.Errorf("derive response error")).Once() + srv.On("DeriveInvoiceResponse", model).Return(nil, errors.New("derive response error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 01ac5f429..9b215f853 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -3,7 +3,6 @@ package invoice import ( "crypto/sha256" "encoding/json" - "fmt" "reflect" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -159,7 +158,7 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload i.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { - return fmt.Errorf("failed to init core document: %v", err) + return errors.New("failed to init core document: %v", err) } return nil @@ -202,7 +201,7 @@ func (i *Invoice) initInvoiceFromData(data *clientinvoicepb.InvoiceData) error { if data.ExtraData != "" { ed, err := hexutil.Decode(data.ExtraData) if err != nil { - return errors.NewTypedError(err, fmt.Errorf("failed to decode extra data")) + return errors.NewTypedError(err, errors.New("failed to decode extra data")) } i.ExtraData = ed @@ -275,7 +274,7 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { invoiceData := i.createP2PProtobuf() serializedInvoice, err := proto.Marshal(invoiceData) if err != nil { - return nil, errors.NewTypedError(err, fmt.Errorf("couldn't serialise InvoiceData")) + return nil, errors.NewTypedError(err, errors.New("couldn't serialise InvoiceData")) } invoiceAny := any.Any{ @@ -287,7 +286,7 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { serializedSalts, err := proto.Marshal(invoiceSalt) if err != nil { - return nil, errors.NewTypedError(err, fmt.Errorf("couldn't serialise InvoiceSalts")) + return nil, errors.NewTypedError(err, errors.New("couldn't serialise InvoiceSalts")) } invoiceSaltsAny := any.Any{ @@ -312,7 +311,7 @@ func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error coreDoc.EmbeddedData.TypeUrl != documenttypes.InvoiceDataTypeUrl || coreDoc.EmbeddedDataSalts == nil || coreDoc.EmbeddedDataSalts.TypeUrl != documenttypes.InvoiceSaltsTypeUrl { - return fmt.Errorf("trying to convert document with incorrect schema") + return errors.New("trying to convert document with incorrect schema") } invoiceData := &invoicepb.InvoiceData{} @@ -356,7 +355,7 @@ func (i *Invoice) Type() reflect.Type { func (i *Invoice) calculateDataRoot() error { t, err := i.getDocumentDataTree() if err != nil { - return fmt.Errorf("calculateDataRoot error %v", err) + return errors.New("calculateDataRoot error %v", err) } i.CoreDocument.DataRoot = t.RootHash() return nil @@ -369,11 +368,11 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { invoiceData := i.createP2PProtobuf() err = t.AddLeavesFromDocument(invoiceData, i.getInvoiceSalts(invoiceData)) if err != nil { - return nil, fmt.Errorf("getDocumentDataTree error %v", err) + return nil, errors.New("getDocumentDataTree error %v", err) } err = t.Generate() if err != nil { - return nil, fmt.Errorf("getDocumentDataTree error %v", err) + return nil, errors.New("getDocumentDataTree error %v", err) } return &t, nil } @@ -384,12 +383,12 @@ func (i *Invoice) createProofs(fields []string) (coreDoc *coredocumentpb.CoreDoc // is still not saved with roots in db due to failures during getting signatures. coreDoc, err = i.PackCoreDocument() if err != nil { - return nil, nil, fmt.Errorf("createProofs error %v", err) + return nil, nil, errors.New("createProofs error %v", err) } tree, err := i.getDocumentDataTree() if err != nil { - return coreDoc, nil, fmt.Errorf("createProofs error %v", err) + return coreDoc, nil, errors.New("createProofs error %v", err) } proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 223de38e1..14958155e 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -2,7 +2,6 @@ package invoice import ( "bytes" - "fmt" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -136,7 +135,7 @@ func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreateP func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { inv, ok := new.(*Invoice) if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, fmt.Errorf("unknown document type: %T", new)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields @@ -261,7 +260,7 @@ func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, er } if !bytes.Equal(inv.CoreDocument.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, fmt.Errorf("version is not valid for this identifier")) + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) } return inv, nil } @@ -319,7 +318,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP // get latest old version of the document id, err := hexutil.Decode(payload.Identifier) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, fmt.Errorf("failed to decode identifier: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, errors.New("failed to decode identifier: %v", err)) } old, err := s.GetCurrentVersion(id) @@ -331,7 +330,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP inv := new(Invoice) err = inv.initInvoiceFromData(payload.Data) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, fmt.Errorf("failed to load invoice from data: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, errors.New("failed to load invoice from data: %v", err)) } // update core document @@ -364,7 +363,7 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentSigning, fmt.Errorf("missing signing key")) + return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 26c1bdd09..705f4b1ed 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -4,7 +4,6 @@ package invoice import ( "context" - "fmt" "math/big" "testing" @@ -230,7 +229,7 @@ func TestService_Create(t *testing.T) { po, err := invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) assert.Nil(t, err) proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() + proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() invSrv.coreDocProcessor = proc m, err = invSrv.Create(ctxh, po) proc.AssertExpectations(t) @@ -577,7 +576,7 @@ func TestService_Update(t *testing.T) { // pack failed model := &mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("pack error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -666,7 +665,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { - return fmt.Errorf("validations fail") + return errors.New("validations fail") }) inv, err = invSrv.calculateDataRoot(nil, inv, v) assert.Nil(t, inv) diff --git a/documents/invoice/validator.go b/documents/invoice/validator.go index d01aa6aa8..9dd89a909 100644 --- a/documents/invoice/validator.go +++ b/documents/invoice/validator.go @@ -1,8 +1,6 @@ package invoice import ( - "fmt" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -13,12 +11,12 @@ import ( func fieldValidator() documents.Validator { return documents.ValidatorFunc(func(_, new documents.Model) error { if new == nil { - return fmt.Errorf("nil document") + return errors.New("nil document") } inv, ok := new.(*Invoice) if !ok { - return fmt.Errorf("unknown document type") + return errors.New("unknown document type") } var err error @@ -35,34 +33,34 @@ func dataRootValidator() documents.Validator { return documents.ValidatorFunc(func(_, model documents.Model) (err error) { defer func() { if err != nil { - err = fmt.Errorf("data root validation failed: %v", err) + err = errors.New("data root validation failed: %v", err) } }() if model == nil { - return fmt.Errorf("nil document") + return errors.New("nil document") } coreDoc, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack coredocument: %v", err) + return errors.New("failed to pack coredocument: %v", err) } if utils.IsEmptyByteSlice(coreDoc.DataRoot) { - return fmt.Errorf("data root missing") + return errors.New("data root missing") } inv, ok := model.(*Invoice) if !ok { - return fmt.Errorf("unknown document type: %T", model) + return errors.New("unknown document type: %T", model) } if err = inv.calculateDataRoot(); err != nil { - return fmt.Errorf("failed to calculate data root: %v", err) + return errors.New("failed to calculate data root: %v", err) } if !utils.IsSameByteSlice(inv.CoreDocument.DataRoot, coreDoc.DataRoot) { - return fmt.Errorf("mismatched data root") + return errors.New("mismatched data root") } return nil diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 1b9aa63d6..4ecc74d0c 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -3,7 +3,6 @@ package invoice import ( - "fmt" "testing" "context" @@ -57,7 +56,7 @@ func TestDataRootValidation_Validate(t *testing.T) { // pack coredoc failed model := &mockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = drv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 2bfe8c271..e2add12fb 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,8 +1,7 @@ package purchaseorder import ( - "errors" - "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" @@ -25,27 +24,27 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { - return fmt.Errorf("p2p client not initialised") + return errors.New("p2p client not initialised") } registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("service registry not initialised") + return errors.New("service registry not initialised") } anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) if !ok { - return fmt.Errorf("anchor repository not initialised") + return errors.New("anchor repository not initialised") } idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { - return fmt.Errorf("identity service not initialised") + return errors.New("identity service not initialised") } repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) if !ok { - return fmt.Errorf("document db repository not initialised") + return errors.New("document db repository not initialised") } repo.Register(&PurchaseOrder{}) @@ -53,7 +52,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { - return fmt.Errorf("failed to register purchase order service") + return errors.New("failed to register purchase order service") } return nil diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 51cea4a17..11e540977 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/ethereum/go-ethereum/common/hexutil" @@ -28,7 +29,7 @@ type grpcHandler struct { func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { - return nil, fmt.Errorf("failed to fetch purchase order service") + return nil, errors.New("failed to fetch purchase order service") } return grpcHandler{ diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index fa6a84024..b81d677c1 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -4,11 +4,11 @@ package purchaseorder import ( "context" - "fmt" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -80,7 +80,7 @@ func TestGRPCHandler_Create(t *testing.T) { // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromCreatePayload", req, ctxh).Return(nil, fmt.Errorf("derive failed")).Once() + srv.On("DeriveFromCreatePayload", req, ctxh).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Create(ctx, req) srv.AssertExpectations(t) @@ -90,7 +90,7 @@ func TestGRPCHandler_Create(t *testing.T) { // create fails srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(nil, fmt.Errorf("create failed")).Once() + srv.On("Create", ctxh, model).Return(nil, errors.New("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -101,7 +101,7 @@ func TestGRPCHandler_Create(t *testing.T) { // derive response fails srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() srv.On("Create", ctxh, model).Return(model, nil).Once() - srv.On("DerivePurchaseOrderResponse", model).Return(nil, fmt.Errorf("derive response fails")).Once() + srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -136,7 +136,7 @@ func TestGrpcHandler_Update(t *testing.T) { // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromUpdatePayload", req, ctxh).Return(nil, fmt.Errorf("derive failed")).Once() + srv.On("DeriveFromUpdatePayload", req, ctxh).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Update(ctx, req) srv.AssertExpectations(t) @@ -146,7 +146,7 @@ func TestGrpcHandler_Update(t *testing.T) { // create fails srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, fmt.Errorf("update failed")).Once() + srv.On("Update", ctxh, model).Return(nil, errors.New("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -157,7 +157,7 @@ func TestGrpcHandler_Update(t *testing.T) { // derive response fails srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() - srv.On("DerivePurchaseOrderResponse", model).Return(nil, fmt.Errorf("derive response fails")).Once() + srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -220,7 +220,7 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { payload.Version = "0x00" payload.Identifier = "0x01" - mockErr := fmt.Errorf("not found") + mockErr := errors.New("not found") srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(nil, mockErr) res, err = h.GetVersion(context.Background(), payload) srv.AssertExpectations(t) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 01fce2aa7..6d0977724 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -3,7 +3,6 @@ package purchaseorder import ( "crypto/sha256" "encoding/json" - "fmt" "reflect" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -11,6 +10,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -156,7 +156,7 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) p.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { - return fmt.Errorf("failed to init core document: %v", err) + return errors.New("failed to init core document: %v", err) } return nil @@ -297,7 +297,7 @@ func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) coreDoc.EmbeddedData.TypeUrl != documenttypes.PurchaseOrderDataTypeUrl || coreDoc.EmbeddedDataSalts == nil || coreDoc.EmbeddedDataSalts.TypeUrl != documenttypes.PurchaseOrderSaltsTypeUrl { - return fmt.Errorf("trying to convert document with incorrect schema") + return errors.New("trying to convert document with incorrect schema") } poData := &purchaseorderpb.PurchaseOrderData{} @@ -341,7 +341,7 @@ func (p *PurchaseOrder) Type() reflect.Type { func (p *PurchaseOrder) calculateDataRoot() error { t, err := p.getDocumentDataTree() if err != nil { - return fmt.Errorf("calculateDataRoot error %v", err) + return errors.New("calculateDataRoot error %v", err) } p.CoreDocument.DataRoot = t.RootHash() return nil @@ -354,11 +354,11 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er poData := p.createP2PProtobuf() err = t.AddLeavesFromDocument(poData, p.getPurchaseOrderSalts(poData)) if err != nil { - return nil, fmt.Errorf("getDocumentDataTree error %v", err) + return nil, errors.New("getDocumentDataTree error %v", err) } err = t.Generate() if err != nil { - return nil, fmt.Errorf("getDocumentDataTree error %v", err) + return nil, errors.New("getDocumentDataTree error %v", err) } return &t, nil } @@ -369,12 +369,12 @@ func (p *PurchaseOrder) createProofs(fields []string) (coreDoc *coredocumentpb.C // is still not saved with roots in db due to failures during getting signatures. coreDoc, err = p.PackCoreDocument() if err != nil { - return nil, nil, fmt.Errorf("createProofs error %v", err) + return nil, nil, errors.New("createProofs error %v", err) } tree, err := p.getDocumentDataTree() if err != nil { - return coreDoc, nil, fmt.Errorf("createProofs error %v", err) + return coreDoc, nil, errors.New("createProofs error %v", err) } proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 05264a17b..b6a8cf4fc 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -2,7 +2,6 @@ package purchaseorder import ( "bytes" - "fmt" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -80,7 +79,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { po, ok := new.(*PurchaseOrder) if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, fmt.Errorf("unknown document type: %T", new)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields @@ -184,7 +183,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdate // get latest old version of the document id, err := hexutil.Decode(payload.Identifier) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, fmt.Errorf("failed to decode identifier: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, errors.New("failed to decode identifier: %v", err)) } old, err := s.GetCurrentVersion(id) @@ -196,7 +195,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdate po := new(PurchaseOrder) err = po.initPurchaseOrderFromData(payload.Data) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, fmt.Errorf("failed to load purchase order from data: %v", err)) + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, errors.New("failed to load purchase order from data: %v", err)) } // update core document @@ -273,7 +272,7 @@ func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *Pur } if !bytes.Equal(model.CoreDocument.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, fmt.Errorf("version is not valid for this identifier")) + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) } return model, nil } @@ -363,7 +362,7 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentSigning, fmt.Errorf("missing signing key")) + return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 70eda819f..f561bcc88 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -4,7 +4,6 @@ package purchaseorder import ( "context" - "fmt" "math/big" "testing" @@ -61,7 +60,7 @@ func TestService_Update(t *testing.T) { // pack failed model := &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("pack error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -287,7 +286,7 @@ func TestService_Create(t *testing.T) { po, err := poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) assert.Nil(t, err) proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(fmt.Errorf("anchoring failed")).Once() + proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() poSrv.coreDocProcessor = proc m, err = poSrv.Create(ctxh, po) proc.AssertExpectations(t) @@ -524,7 +523,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { // pack fails m := &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(nil, fmt.Errorf("pack core document failed")).Once() + m.On("PackCoreDocument").Return(nil, errors.New("pack core document failed")).Once() r, err := poSrv.DerivePurchaseOrderResponse(m) m.AssertExpectations(t) assert.Nil(t, r) @@ -715,7 +714,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { - return fmt.Errorf("validations fail") + return errors.New("validations fail") }) po, err = poSrv.calculateDataRoot(nil, po, v) assert.Nil(t, po) diff --git a/documents/purchaseorder/validator.go b/documents/purchaseorder/validator.go index 1ef2a35d5..bba33373b 100644 --- a/documents/purchaseorder/validator.go +++ b/documents/purchaseorder/validator.go @@ -1,8 +1,6 @@ package purchaseorder import ( - "fmt" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -13,12 +11,12 @@ import ( func fieldValidator() documents.Validator { return documents.ValidatorFunc(func(_, new documents.Model) error { if new == nil { - return fmt.Errorf("nil document") + return errors.New("nil document") } po, ok := new.(*PurchaseOrder) if !ok { - return fmt.Errorf("unknown document type") + return errors.New("unknown document type") } var err error @@ -35,34 +33,34 @@ func dataRootValidator() documents.Validator { return documents.ValidatorFunc(func(_, model documents.Model) (err error) { defer func() { if err != nil { - err = fmt.Errorf("data root validation failed: %v", err) + err = errors.New("data root validation failed: %v", err) } }() if model == nil { - return fmt.Errorf("nil document") + return errors.New("nil document") } coreDoc, err := model.PackCoreDocument() if err != nil { - return fmt.Errorf("failed to pack coredocument: %v", err) + return errors.New("failed to pack coredocument: %v", err) } if utils.IsEmptyByteSlice(coreDoc.DataRoot) { - return fmt.Errorf("data root missing") + return errors.New("data root missing") } inv, ok := model.(*PurchaseOrder) if !ok { - return fmt.Errorf("unknown document type: %T", model) + return errors.New("unknown document type: %T", model) } if err = inv.calculateDataRoot(); err != nil { - return fmt.Errorf("failed to calculate data root: %v", err) + return errors.New("failed to calculate data root: %v", err) } if !utils.IsSameByteSlice(inv.CoreDocument.DataRoot, coreDoc.DataRoot) { - return fmt.Errorf("mismatched data root") + return errors.New("mismatched data root") } return nil diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 7271c28be..0dc56c63c 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -3,7 +3,6 @@ package purchaseorder import ( - "fmt" "testing" "context" @@ -59,7 +58,7 @@ func TestDataRootValidation_Validate(t *testing.T) { // pack coredoc failed model := &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(nil, fmt.Errorf("error")).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = drv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) diff --git a/documents/registry.go b/documents/registry.go index 15ab2af69..49848237d 100644 --- a/documents/registry.go +++ b/documents/registry.go @@ -1,8 +1,9 @@ package documents import ( - "fmt" "sync" + + "github.com/centrifuge/go-centrifuge/errors" ) //ServiceRegistry matches for a provided coreDocument the corresponding service @@ -23,7 +24,7 @@ func (s *ServiceRegistry) Register(serviceID string, service Service) error { s.mutex.Lock() defer s.mutex.Unlock() if _, ok := s.services[serviceID]; ok { - return fmt.Errorf("service with provided id already registered") + return errors.New("service with provided id already registered") } s.services[serviceID] = service @@ -35,7 +36,7 @@ func (s *ServiceRegistry) LocateService(serviceID string) (Service, error) { s.mutex.RLock() defer s.mutex.RUnlock() if s.services[serviceID] == nil { - return nil, fmt.Errorf("no service for core document type is registered") + return nil, errors.New("no service for core document type is registered") } return s.services[serviceID], nil @@ -55,6 +56,6 @@ func (s *ServiceRegistry) FindService(documentID []byte) (Service, error) { } } - return nil, fmt.Errorf("no service exists for provided documentID") + return nil, errors.New("no service exists for provided documentID") } diff --git a/documents/repository.go b/documents/repository.go index 53720b2e1..5e7a3d254 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -2,7 +2,6 @@ package documents import ( "encoding/json" - "fmt" "reflect" "sync" @@ -73,7 +72,7 @@ func (l *levelDBRepo) Exists(tenantID, id []byte) bool { func (l *levelDBRepo) getModel(mt string) (Model, error) { tp, ok := l.models[mt] if !ok { - return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotRegistered, fmt.Errorf("type %s not registered", mt)) + return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotRegistered, errors.New("type %s not registered", mt)) } return reflect.New(tp).Interface().(Model), nil @@ -84,13 +83,13 @@ func (l *levelDBRepo) Get(tenantID, id []byte) (Model, error) { key := getKey(tenantID, id) data, err := l.db.Get(key, nil) if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotFound, fmt.Errorf("document missing: %v", err)) + return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotFound, errors.New("document missing: %v", err)) } v := new(value) err = json.Unmarshal(data, v) if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to unmarshal value: %v", err)) + return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to unmarshal value: %v", err)) } l.mu.RLock() @@ -102,7 +101,7 @@ func (l *levelDBRepo) Get(tenantID, id []byte) (Model, error) { err = nm.FromJSON([]byte(v.Data)) if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to unmarshal to model: %v", err)) + return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to unmarshal to model: %v", err)) } return nm, nil @@ -121,7 +120,7 @@ func getTypeIndirect(tp reflect.Type) reflect.Type { func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { data, err := model.JSON() if err != nil { - return errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to marshall model: %v", err)) + return errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to marshall model: %v", err)) } tp := getTypeIndirect(model.Type()) @@ -132,13 +131,13 @@ func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { data, err = json.Marshal(v) if err != nil { - return errors.NewTypedError(ErrDocumentRepositorySerialisation, fmt.Errorf("failed to marshall value: %v", err)) + return errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to marshall value: %v", err)) } key := getKey(tenantID, id) err = l.db.Put(key, data, nil) if err != nil { - return errors.NewTypedError(ErrDocumentRepositoryModelSave, fmt.Errorf("%v", err)) + return errors.NewTypedError(ErrDocumentRepositoryModelSave, errors.New("%v", err)) } return nil diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index 753e50144..9268b0841 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -4,7 +4,7 @@ package documents_test import ( "context" - "fmt" + "errors" "testing" "os" @@ -43,7 +43,7 @@ func TestAnchorDocument(t *testing.T) { // pack fails m := &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(nil, fmt.Errorf("pack failed")).Once() + m.On("PackCoreDocument").Return(nil, errors.New("pack failed")).Once() model, err := documents.AnchorDocument(ctxh, m, nil, updater) m.AssertExpectations(t) assert.Nil(t, model) @@ -55,7 +55,7 @@ func TestAnchorDocument(t *testing.T) { cd := coredocument.New() m.On("PackCoreDocument").Return(cd, nil).Once() proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", m).Return(fmt.Errorf("error")).Once() + proc.On("PrepareForSignatureRequests", m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) @@ -68,7 +68,7 @@ func TestAnchorDocument(t *testing.T) { m.On("PackCoreDocument").Return(cd, nil).Once() proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() - proc.On("RequestSignatures", ctxh, m).Return(fmt.Errorf("error")).Once() + proc.On("RequestSignatures", ctxh, m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) @@ -82,7 +82,7 @@ func TestAnchorDocument(t *testing.T) { proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() - proc.On("PrepareForAnchoring", m).Return(fmt.Errorf("error")).Once() + proc.On("PrepareForAnchoring", m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) @@ -97,7 +97,7 @@ func TestAnchorDocument(t *testing.T) { proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() - proc.On("AnchorDocument", m).Return(fmt.Errorf("error")).Once() + proc.On("AnchorDocument", m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) @@ -113,7 +113,7 @@ func TestAnchorDocument(t *testing.T) { proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() proc.On("AnchorDocument", m).Return(nil).Once() - proc.On("SendDocument", ctxh, m).Return(fmt.Errorf("error")).Once() + proc.On("SendDocument", ctxh, m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 3f8c37d7f..d0c4a71aa 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -3,7 +3,7 @@ package documents import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" diff --git a/documents/validator_test.go b/documents/validator_test.go index bad7395b8..34b07e8f0 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -3,7 +3,6 @@ package documents import ( - "fmt" "testing" "github.com/centrifuge/go-centrifuge/errors" @@ -29,7 +28,7 @@ func (m MockValidatorWithErrors) Validate(oldState Model, newState Model) error type MockValidatorWithOneError struct{} func (m MockValidatorWithOneError) Validate(oldState Model, newState Model) error { - return fmt.Errorf("one error") + return errors.New("one error") } func TestValidatorInterface(t *testing.T) { diff --git a/errors/errors_test.go b/errors/errors_test.go index 8239b7315..811b5c450 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -3,7 +3,6 @@ package errors import ( - "errors" "testing" "github.com/stretchr/testify/assert" @@ -51,7 +50,7 @@ func TestAppendError(t *testing.T) { assert.Nil(t, AppendError(nil, nil)) // errn nil, and err not nil but simple error - serr := errors.New("some error") + serr := New("some error") lerr := AppendError(serr, nil) checkListError(t, lerr, 1, "[some error]") diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index a12e2fa01..496b0b78a 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -1,7 +1,7 @@ package ethereum import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/config" ) diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 7bca4e372..ffa7dbf70 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -2,7 +2,6 @@ package ethereum import ( "context" - "fmt" "math/big" "net/url" "reflect" @@ -13,6 +12,7 @@ import ( "time" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -22,8 +22,8 @@ import ( ) const ( - transactionUnderpriced = "replacement transaction underpriced" - nonceTooLow = "nonce too low" + transactionUnderpriced = errors.Error("replacement transaction underpriced") + nonceTooLow = errors.Error("nonce too low") ) var log = logging.Logger("geth-client") @@ -91,12 +91,12 @@ func NewGethClient(config Config) (Client, error) { log.Info("Opening connection to Ethereum:", config.GetEthereumNodeURL()) u, err := url.Parse(config.GetEthereumNodeURL()) if err != nil { - return nil, fmt.Errorf("failed to parse ethereum node URL: %v", err) + return nil, errors.New("failed to parse ethereum node URL: %v", err) } c, err := rpc.Dial(u.String()) if err != nil { - return nil, fmt.Errorf("failed to connect to ethereum node: %v", err) + return nil, errors.New("failed to connect to ethereum node: %v", err) } return &gethClient{ @@ -164,12 +164,12 @@ func (gc *gethClient) GetNodeURL() *url.URL { func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, error) { account, err := gc.config.GetEthereumAccount(accountName) if err != nil { - return nil, fmt.Errorf("failed to get ethereum account: %v", err) + return nil, errors.New("failed to get ethereum account: %v", err) } opts, err := bind.NewTransactor(strings.NewReader(account.Key), account.Password) if err != nil { - return nil, fmt.Errorf("failed to create new transaction opts: %v", err) + return nil, errors.New("failed to create new transaction opts: %v", err) } opts.GasPrice = gc.config.GetEthereumGasPrice() @@ -199,13 +199,13 @@ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, o for { if current >= maxTries { - return nil, fmt.Errorf("max concurrent transaction tries reached: %v", err) + return nil, errors.New("max concurrent transaction tries reached: %v", err) } current++ err = gc.incrementNonce(opts, gc.config.GetTxPoolAccessEnabled(), gc.client, gc.rpcClient) if err != nil { - return nil, fmt.Errorf("failed to increment nonce: %v", err) + return nil, errors.New("failed to increment nonce: %v", err) } if opts.Nonce != nil { @@ -232,7 +232,7 @@ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, o return tx, nil } - if (err.Error() == transactionUnderpriced) || (err.Error() == nonceTooLow) { + if (err.Error() == transactionUnderpriced.Error()) || (err.Error() == nonceTooLow.Error()) { log.Warningf("Concurrent transaction identified, trying again [%d/%d]\n", current, maxTries) time.Sleep(gc.config.GetEthereumIntervalRetry()) continue @@ -281,7 +281,7 @@ func (gc *gethClient) incrementNonce(opts *bind.TransactOpts, txpoolAccessEnable // get current nonce n, err := noncer.PendingNonceAt(ctx, opts.From) if err != nil { - return fmt.Errorf("failed to get chain nonce for %s: %v", opts.From.String(), err) + return errors.New("failed to get chain nonce for %s: %v", opts.From.String(), err) } // set the nonce @@ -291,7 +291,7 @@ func (gc *gethClient) incrementNonce(opts *bind.TransactOpts, txpoolAccessEnable res := make(map[string]map[string]map[string]string) err = cc.CallContext(ctx, &res, "txpool_inspect") if err != nil { - return fmt.Errorf("failed to get txpool data: %v", err) + return errors.New("failed to get txpool data: %v", err) } // no pending transaction from this account in tx pool @@ -303,7 +303,7 @@ func (gc *gethClient) incrementNonce(opts *bind.TransactOpts, txpoolAccessEnable for k := range res["pending"][opts.From.Hex()] { ki, err := strconv.Atoi(k) if err != nil { - return fmt.Errorf("failed to convert nonce: %v", err) + return errors.New("failed to convert nonce: %v", err) } keys = append(keys, ki) diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index 21206aa4f..57f6f0acc 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -4,7 +4,6 @@ package ethereum import ( "context" - "fmt" "os" "sync" "testing" @@ -13,11 +12,11 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/go-errors/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -46,12 +45,12 @@ type MockTransactionRequest struct { func (transactionRequest *MockTransactionRequest) RegisterTransaction(opts *bind.TransactOpts, transactionName string, anotherVar string) (tx *types.Transaction, err error) { transactionRequest.count++ if transactionName == "otherError" { - err = errors.Wrap("Some other error", 1) + err = errors.New("Some other error") } else if transactionName == "optimisticLockingTimeout" { - err = errors.Wrap(transactionUnderpriced, 1) + err = transactionUnderpriced } else if transactionName == "optimisticLockingEventualSuccess" { if transactionRequest.count < 3 { - err = errors.Wrap(transactionUnderpriced, 1) + err = transactionUnderpriced } } @@ -137,7 +136,7 @@ func Test_incrementNonce(t *testing.T) { // noncer failed n := new(mockNoncer) - n.On("PendingNonceAt", mock.Anything, opts.From).Return(0, fmt.Errorf("error")).Once() + n.On("PendingNonceAt", mock.Anything, opts.From).Return(0, errors.New("error")).Once() err = gc.incrementNonce(opts, true, n, nil) n.AssertExpectations(t) assert.Error(t, err) @@ -146,7 +145,7 @@ func Test_incrementNonce(t *testing.T) { // rpc call failed n = new(mockNoncer) n.On("PendingNonceAt", mock.Anything, opts.From).Return(uint64(100), nil).Once() - n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, fmt.Errorf("error")).Once() + n.On("CallContext", mock.Anything, mock.Anything, "txpool_inspect", mock.Anything).Return(nil, errors.New("error")).Once() err = gc.incrementNonce(opts, true, n, n) n.AssertExpectations(t) assert.Error(t, err) diff --git a/header/context.go b/header/context.go index 937cda15b..3e164ee7b 100644 --- a/header/context.go +++ b/header/context.go @@ -2,9 +2,9 @@ package header import ( "context" - "fmt" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" ) @@ -18,7 +18,7 @@ type ContextHeader struct { func NewContextHeader(context context.Context, config config.Configuration) (*ContextHeader, error) { idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) if err != nil { - return nil, fmt.Errorf("failed to get id config: %v", err) + return nil, errors.New("failed to get id config: %v", err) } return &ContextHeader{self: idConfig, context: context}, nil diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 069faab14..243f4d531 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -1,7 +1,7 @@ package identity import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index daaf27323..e8c38d68a 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -10,7 +10,7 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/queue" @@ -19,7 +19,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/go-errors/errors" logging "github.com/ipfs/go-log" ) @@ -115,7 +114,7 @@ func (id *ethereumIdentity) LastKeyForPurpose(keyPurpose int) (key []byte, err e } if len(idKeys) == 0 { - return []byte{}, fmt.Errorf("no key found for type [%d] in ID [%s]", keyPurpose, id.centID) + return []byte{}, errors.New("no key found for type [%d] in ID [%s]", keyPurpose, id.centID) } return idKeys[len(idKeys)-1].Key[:32], nil @@ -225,14 +224,14 @@ func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int copy(keyFixed[:], key) confirmations, err = id.setUpKeyRegisteredEventListener(id.config, id, keyPurpose, keyFixed, h.Number.Uint64()) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Errorf("Failed to set up event listener for identity [id: %s]: %v", id, wError) return confirmations, wError } err = sendKeyRegistrationTransaction(ethIdentityContract, opts, id, keyPurpose, key) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Errorf("Failed to create transaction for identity [id: %s]: %v", id, wError) return confirmations, wError } @@ -405,14 +404,14 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden confirmations, err = ids.setUpRegistrationEventListener(ids.config, id, h.Number.Uint64()) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Infof("Failed to set up event listener for identity [mockID: %s]: %v", id, wError) return nil, confirmations, wError } err = sendIdentityCreationTransaction(ids.factoryContract, opts, id) if err != nil { - wError := errors.Wrap(err, 1) + wError := errors.New("%v", err) log.Infof("Failed to create transaction for identity [mockID: %s]: %v", id, wError) return nil, confirmations, wError } @@ -438,7 +437,7 @@ func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Ad func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Identity, error) { exists, err := ids.CheckIdentityExists(centrifugeID) if !exists { - return nil, fmt.Errorf("identity [%s] does not exist with err [%v]", centrifugeID, err) + return nil, errors.New("identity [%s] does not exist with err [%v]", centrifugeID, err) } if err != nil { @@ -451,12 +450,12 @@ func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Id func (ids *EthereumIdentityService) GetClientP2PURL(centID CentID) (url string, err error) { target, err := ids.LookupIdentityForID(centID) if err != nil { - return url, centerrors.Wrap(err, "error fetching receiver identity") + return url, errors.New("error fetching receiver identity: %v", err) } p2pKey, err := target.CurrentP2PKey() if err != nil { - return url, centerrors.Wrap(err, "error fetching p2p key") + return url, errors.New("error fetching p2p key: %v", err) } return fmt.Sprintf("/ipfs/%s", p2pKey), nil @@ -491,7 +490,7 @@ func (ids *EthereumIdentityService) GetIdentityKey(identity CentID, pubKey []byt } if utils.IsEmptyByte32(key.GetKey()) { - return keyInfo, fmt.Errorf(fmt.Sprintf("key not found for identity: %x", identity)) + return keyInfo, errors.New("key not found for identity: %x", identity) } return key, nil @@ -505,15 +504,15 @@ func (ids *EthereumIdentityService) ValidateKey(centID CentID, key []byte, purpo } if !bytes.Equal(key, utils.Byte32ToSlice(idKey.GetKey())) { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't match", idKey.GetKey())) + return errors.New("[Key: %x] Key doesn't match", idKey.GetKey()) } if !utils.ContainsBigIntInSlice(big.NewInt(int64(purpose)), idKey.GetPurposes()) { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key doesn't have purpose [%d]", idKey.GetKey(), purpose)) + return errors.New("[Key: %x] Key doesn't have purpose [%d]", idKey.GetKey(), purpose) } if idKey.GetRevokedAt().Cmp(big.NewInt(0)) != 0 { - return fmt.Errorf(fmt.Sprintf("[Key: %x] Key is currently revoked since block [%d]", idKey.GetKey(), idKey.GetRevokedAt())) + return errors.New("[Key: %x] Key is currently revoked since block [%d]", idKey.GetKey(), idKey.GetRevokedAt()) } return nil diff --git a/identity/ethereum_identity_test.go b/identity/ethereum_identity_test.go index 93f1be764..8388a36f8 100644 --- a/identity/ethereum_identity_test.go +++ b/identity/ethereum_identity_test.go @@ -8,6 +8,7 @@ import ( "net/url" "testing" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" @@ -15,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - "github.com/go-errors/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/identity/id_registration_confirmation_task.go b/identity/id_registration_confirmation_task.go index 63d5e91b6..706c30e2d 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/id_registration_confirmation_task.go @@ -2,11 +2,11 @@ package identity import ( "context" - "fmt" "math/big" "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" @@ -64,11 +64,11 @@ func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { id, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + centIDParam) + return errors.New("undefined kwarg " + centIDParam) } centID, err := getCentID(id) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } rct.centID = centID @@ -82,7 +82,7 @@ func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interfa if ok { td, err := queue.GetDuration(tdRaw) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } rct.timeout = td } diff --git a/identity/identity.go b/identity/identity.go index 00c96ae63..569747f1e 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -2,10 +2,11 @@ package identity import ( "context" - "errors" "fmt" "math/big" + "github.com/centrifuge/go-centrifuge/errors" + "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -175,7 +176,7 @@ func GetIdentityConfig(config Config) (*IDConfig, error) { // errors out if bytes are empty, nil, or len(bytes) > CentIDLength func ToCentID(bytes []byte) (centID CentID, err error) { if utils.IsEmptyByteSlice(bytes) { - return centID, fmt.Errorf("empty bytes provided") + return centID, errors.New("empty bytes provided") } if !utils.IsValidByteSliceForLength(bytes, CentIDLength) { diff --git a/identity/identity_test.go b/identity/identity_test.go index 4fbf74b53..b68318e76 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -4,12 +4,12 @@ package identity import ( "context" - "fmt" "os" "testing" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" @@ -218,17 +218,17 @@ func TestCentIDFromString(t *testing.T) { { id: "0x01020304050607", - err: fmt.Errorf("invalid length byte slice provided for centID"), + err: errors.New("invalid length byte slice provided for centID"), }, { id: "0xsome random", - err: fmt.Errorf("failed to decode id"), + err: errors.New("failed to decode id"), }, { id: "some random", - err: fmt.Errorf("hex string without 0x"), + err: errors.New("hex string without 0x"), }, } diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index 8fcf9e914..5cac6f7c1 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -2,11 +2,11 @@ package identity import ( "context" - "fmt" "math/big" "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" @@ -90,35 +90,35 @@ func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { id, ok := kwargs[centIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + centIDParam) + return errors.New("undefined kwarg " + centIDParam) } centID, err := getCentID(id) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) } krct.centID = centID // key parsing key, ok := kwargs[keyParam] if !ok { - return fmt.Errorf("undefined kwarg " + keyParam) + return errors.New("undefined kwarg " + keyParam) } keyTyped, err := getBytes32(key) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", keyParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", keyParam, err.Error()) } krct.key = keyTyped // key purpose parsing keyPurpose, ok := kwargs[keyPurposeParam] if !ok { - return fmt.Errorf("undefined kwarg " + keyPurposeParam) + return errors.New("undefined kwarg " + keyPurposeParam) } keyPurposeF, ok := keyPurpose.(float64) if ok { krct.keyPurpose = int(keyPurposeF) } else { - return fmt.Errorf("can not parse " + keyPurposeParam) + return errors.New("can not parse " + keyPurposeParam) } // block height parsing @@ -131,7 +131,7 @@ func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]inter if ok { td, err := queue.GetDuration(tdRaw) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } krct.timeout = td } diff --git a/identity/util.go b/identity/util.go index 663a19f3f..25fe92ff9 100644 --- a/identity/util.go +++ b/identity/util.go @@ -1,6 +1,6 @@ package identity -import "errors" +import "github.com/centrifuge/go-centrifuge/errors" const ( centIDParam string = "CentID" diff --git a/keytools/ed25519/ed25519.go b/keytools/ed25519/ed25519.go index 1d4d7039a..0f8dbe003 100644 --- a/keytools/ed25519/ed25519.go +++ b/keytools/ed25519/ed25519.go @@ -1,8 +1,7 @@ package ed25519 import ( - "fmt" - + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-crypto" @@ -16,7 +15,7 @@ var log = logging.Logger("ed25519") func GetPublicSigningKey(fileName string) (publicKey ed25519.PublicKey, err error) { key, err := utils.ReadKeyFromPemFile(fileName, utils.PublicKey) if err != nil { - return nil, fmt.Errorf("failed to read pem file: %v", err) + return nil, errors.New("failed to read pem file: %v", err) } return ed25519.PublicKey(key), nil @@ -26,7 +25,7 @@ func GetPublicSigningKey(fileName string) (publicKey ed25519.PublicKey, err erro func GetPrivateSigningKey(fileName string) (privateKey ed25519.PrivateKey, err error) { key, err := utils.ReadKeyFromPemFile(fileName, utils.PrivateKey) if err != nil { - return nil, fmt.Errorf("failed to read pem file: %v", err) + return nil, errors.New("failed to read pem file: %v", err) } return ed25519.PrivateKey(key), nil @@ -36,12 +35,12 @@ func GetPrivateSigningKey(fileName string) (privateKey ed25519.PrivateKey, err e func GetSigningKeyPair(pub, priv string) (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) { publicKey, err = GetPublicSigningKey(pub) if err != nil { - return nil, nil, fmt.Errorf("failed to read public key: %v", err) + return nil, nil, errors.New("failed to read public key: %v", err) } privateKey, err = GetPrivateSigningKey(priv) if err != nil { - return nil, nil, fmt.Errorf("failed to read private key: %v", err) + return nil, nil, errors.New("failed to read private key: %v", err) } return publicKey, privateKey, nil diff --git a/keytools/secp256k1/secp256k1.go b/keytools/secp256k1/secp256k1.go index 72bd91a2a..fdb540a2e 100644 --- a/keytools/secp256k1/secp256k1.go +++ b/keytools/secp256k1/secp256k1.go @@ -6,6 +6,7 @@ import ( "crypto/rand" "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -118,12 +119,12 @@ func VerifySignature(publicKey, message, signature []byte) bool { func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { privateKey, err := GetPrivateEthAuthKey(priv) if err != nil { - return nil, nil, fmt.Errorf("failed to read private key: %v", err) + return nil, nil, errors.New("failed to read private key: %v", err) } publicKey, err := GetPublicEthAuthKey(pub) if err != nil { - return nil, nil, fmt.Errorf("failed to read public key: %v", err) + return nil, nil, errors.New("failed to read public key: %v", err) } return publicKey, privateKey, nil diff --git a/keytools/sign.go b/keytools/sign.go index 4806ddd99..1b8977d95 100644 --- a/keytools/sign.go +++ b/keytools/sign.go @@ -1,9 +1,9 @@ package keytools import ( - "fmt" "strings" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" ) @@ -21,9 +21,9 @@ func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool return secp256k1.Sign(msg, privateKey) case CurveEd25519: - return nil, fmt.Errorf("curve ed25519 not supported yet") + return nil, errors.New("curve ed25519 not supported yet") default: - return nil, fmt.Errorf("curve %s not supported", curveType) + return nil, errors.New("curve %s not supported", curveType) } } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index ad7338e7c..e3e108df9 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -1,8 +1,7 @@ package nft import ( - "errors" - "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" @@ -31,12 +30,12 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("service registry not initialised") + return errors.New("service registry not initialised") } idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { - return fmt.Errorf("identity service not initialised") + return errors.New("identity service not initialised") } if _, ok := ctx[bootstrap.BootstrappedQueueServer]; !ok { diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index a010c1ea6..c1ff084b0 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -3,11 +3,11 @@ package nft import ( "context" "encoding/hex" - "fmt" "math/big" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -112,7 +112,7 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, requestData, err := s.prepareMintRequest(documentID, depositAddress, proofFields) if err != nil { - return nil, fmt.Errorf("failed to prepare mint request: %v", err) + return nil, errors.New("failed to prepare mint request: %v", err) } opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 3989033d6..b194fa56f 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -3,10 +3,11 @@ package nft import ( - "errors" "math/big" "testing" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" diff --git a/nft/handler_test.go b/nft/handler_test.go index 480ab7bce..1f59b3249 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -8,9 +8,9 @@ import ( "math/big" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/go-errors/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 3804b8950..2469ccb8e 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -2,10 +2,10 @@ package nft import ( "context" - "fmt" "time" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" @@ -70,11 +70,11 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) // parse TokenID tokenID, ok := kwargs[tokenIDParam] if !ok { - return fmt.Errorf("undefined kwarg " + tokenIDParam) + return errors.New("undefined kwarg " + tokenIDParam) } nftc.TokenID, ok = tokenID.(string) if !ok { - return fmt.Errorf("malformed kwarg [%s]", tokenIDParam) + return errors.New("malformed kwarg [%s]", tokenIDParam) } // parse BlockHeight @@ -86,12 +86,12 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) //parse RegistryAddress registryAddress, ok := kwargs[registryAddressParam] if !ok { - return fmt.Errorf("undefined kwarg " + registryAddressParam) + return errors.New("undefined kwarg " + registryAddressParam) } nftc.RegistryAddress, ok = registryAddress.(string) if !ok { - return fmt.Errorf("malformed kwarg [%s]", registryAddressParam) + return errors.New("malformed kwarg [%s]", registryAddressParam) } // override TimeoutParam if provided @@ -99,7 +99,7 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) if ok { td, err := queue.GetDuration(tdRaw) if err != nil { - return fmt.Errorf("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } nftc.Timeout = td } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 37f9059d2..719890db7 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -2,11 +2,11 @@ package node import ( "context" - "fmt" "os" "os/signal" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" ) @@ -20,7 +20,7 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { srvs, err := GetServers(c) if err != nil { cleanUp(c) - return fmt.Errorf("failed to load servers: %v", err) + return errors.New("failed to load servers: %v", err) } n := New(srvs) @@ -54,17 +54,17 @@ func cleanUp(c map[string]interface{}) { func GetServers(ctx map[string]interface{}) ([]Server, error) { p2pSrv, ok := ctx[bootstrap.BootstrappedP2PServer] if !ok { - return nil, fmt.Errorf("p2p server not initialized") + return nil, errors.New("p2p server not initialized") } apiSrv, ok := ctx[bootstrap.BootstrappedAPIServer] if !ok { - return nil, fmt.Errorf("API server not initialized") + return nil, errors.New("API server not initialized") } queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer] if !ok { - return nil, fmt.Errorf("queue server not initialized") + return nil, errors.New("queue server not initialized") } var servers []Server diff --git a/node/node_test.go b/node/node_test.go index 67fc0351c..3d973b7d0 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -4,11 +4,12 @@ package node import ( "context" - "errors" "sync" "testing" "time" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/stretchr/testify/assert" ) diff --git a/notification/notification.go b/notification/notification.go index b50feb68a..9b620fb95 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -1,10 +1,10 @@ package notification import ( - "fmt" "net/http" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/jsonpb" logging "github.com/ipfs/go-log" @@ -65,7 +65,7 @@ func (wh webhookSender) Send(notification *notificationpb.NotificationMessage) ( } if statusCode != http.StatusOK { - return Failure, fmt.Errorf("failed to send webhook: status = %v", statusCode) + return Failure, errors.New("failed to send webhook: status = %v", statusCode) } log.Infof("Sent Webhook Notification with Payload [%v] to [%s]", notification, url) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index d5527d300..bd7dcca02 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -1,11 +1,10 @@ package p2p import ( - "fmt" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" ) // Bootstrapped constants that are used as key in bootstrap context @@ -20,12 +19,12 @@ type Bootstrapper struct{} func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg, ok := ctx[config.BootstrappedConfig].(config.Configuration) if !ok { - return fmt.Errorf("config not initialised") + return errors.New("config not initialised") } registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return fmt.Errorf("registry not initialised") + return errors.New("registry not initialised") } srv := &p2pServer{config: cfg, registry: registry, handler: GRPCHandler(cfg, registry)} diff --git a/p2p/client.go b/p2p/client.go index 5d4155a6d..fb68191ea 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/version" @@ -57,7 +58,7 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { defer cancel() g, err := s.protocol.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { - return nil, fmt.Errorf("failed to dial peer [%s]: %v", peerID.Pretty(), err) + return nil, errors.New("failed to dial peer [%s]: %v", peerID.Pretty(), err) } return p2ppb.NewP2PServiceClient(g), nil diff --git a/p2p/client_test.go b/p2p/client_test.go index 3c6588e79..fb5e7681e 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -4,11 +4,11 @@ package p2p import ( "context" - "fmt" "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" @@ -25,7 +25,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("signature failed")).Once() + client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, errors.New("signature failed")).Once() resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) client.AssertExpectations(t) assert.Error(t, err, "must fail") diff --git a/p2p/handler.go b/p2p/handler.go index f2261e20c..32493347d 100644 --- a/p2p/handler.go +++ b/p2p/handler.go @@ -11,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/version" ) @@ -18,21 +19,21 @@ import ( // getService looks up the specific registry, derives service from core document func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { if cd == nil { - return nil, nil, fmt.Errorf("nil core document") + return nil, nil, errors.New("nil core document") } docType, err := coredocument.GetTypeURL(cd) if err != nil { - return nil, nil, fmt.Errorf("failed to get type of the document: %v", err) + return nil, nil, errors.New("failed to get type of the document: %v", err) } srv, err := registry.LocateService(docType) if err != nil { - return nil, nil, fmt.Errorf("failed to locate the service: %v", err) + return nil, nil, errors.New("failed to locate the service: %v", err) } model, err := srv.DeriveFromCoreDocument(cd) if err != nil { - return nil, nil, fmt.Errorf("failed to derive model from core document: %v", err) + return nil, nil, errors.New("failed to derive model from core document: %v", err) } return srv, model, nil diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 77ef986bc..00fe2d4df 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -4,7 +4,6 @@ package p2p import ( "context" - "fmt" "strconv" "testing" @@ -204,7 +203,7 @@ func Test_getServiceAndModel(t *testing.T) { // derive fails srv := mockService{} - srv.On("DeriveFromCoreDocument", cd).Return(nil, fmt.Errorf("error")).Once() + srv.On("DeriveFromCoreDocument", cd).Return(nil, errors.New("error")).Once() err = registry.Register(cd.EmbeddedData.TypeUrl, srv) assert.Nil(t, err) s, m, err = getServiceAndModel(registry, cd) diff --git a/p2p/server.go b/p2p/server.go index eb9890362..dd921594f 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -2,11 +2,12 @@ package p2p import ( "context" - "errors" "fmt" "sync" "time" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/documents" cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" @@ -196,7 +197,7 @@ func (s *p2pServer) makeBasicHost(listenPort int) (host.Host, error) { } else { extMultiAddr, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", externalIP, listenPort)) if err != nil { - return nil, fmt.Errorf("failed to create multiaddr: %v", err) + return nil, errors.New("failed to create multiaddr: %v", err) } } @@ -222,7 +223,7 @@ func (s *p2pServer) makeBasicHost(listenPort int) (host.Host, error) { hostAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", bhost.ID().Pretty())) if err != nil { - return nil, fmt.Errorf("failed to get addr: %v", err) + return nil, errors.New("failed to get addr: %v", err) } log.Infof("P2P Server at: %s %s\n", hostAddr.String(), bhost.Addrs()) @@ -233,7 +234,7 @@ func (s *p2pServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, // Create the signing key for the host publicKey, privateKey, err := cented25519.GetSigningKeyPair(s.config.GetSigningKeyPair()) if err != nil { - return nil, nil, fmt.Errorf("failed to get keys: %v", err) + return nil, nil, errors.New("failed to get keys: %v", err) } var key []byte diff --git a/p2p/validator.go b/p2p/validator.go index 1f681defa..4f1604425 100644 --- a/p2p/validator.go +++ b/p2p/validator.go @@ -42,7 +42,7 @@ func (vf ValidatorFunc) Validate(header *p2ppb.CentrifugeHeader) error { func versionValidator() Validator { return ValidatorFunc(func(header *p2ppb.CentrifugeHeader) error { if header == nil { - return fmt.Errorf("nil header") + return errors.New("nil header") } if !version.CheckVersion(header.CentNodeVersion) { return version.IncompatibleVersionError(header.CentNodeVersion) @@ -54,7 +54,7 @@ func versionValidator() Validator { func networkValidator(networkID uint32) Validator { return ValidatorFunc(func(header *p2ppb.CentrifugeHeader) error { if header == nil { - return fmt.Errorf("nil header") + return errors.New("nil header") } if networkID != header.NetworkIdentifier { return incompatibleNetworkError(networkID, header.NetworkIdentifier) diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index cb497eeb5..cff475b75 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -1,7 +1,7 @@ package queue import ( - "errors" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" diff --git a/queue/server.go b/queue/server.go index 8469ac2c9..ff4e95755 100644 --- a/queue/server.go +++ b/queue/server.go @@ -2,10 +2,11 @@ package queue import ( "context" - "errors" "sync" "time" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/gocelery" logging "github.com/ipfs/go-log" ) diff --git a/signatures/signatures.go b/signatures/signatures.go index d5929c30f..ed927c48b 100644 --- a/signatures/signatures.go +++ b/signatures/signatures.go @@ -1,7 +1,7 @@ package signatures import ( - "fmt" + "errors" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -13,7 +13,7 @@ import ( func VerifySignature(pubKey, message, signature []byte) error { valid := ed25519.Verify(pubKey, message, signature) if !valid { - return fmt.Errorf("invalid signature") + return errors.New("invalid signature") } return nil diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index 3a8d29ca2..fb7452851 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -1,8 +1,7 @@ package storage import ( - "errors" - "fmt" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/config" ) @@ -22,7 +21,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { - return fmt.Errorf("failed to init level db: %v", err) + return errors.New("failed to init level db: %v", err) } context[BootstrappedLevelDB] = levelDB diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index c85b95847..c006d8608 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" "github.com/syndtr/goleveldb/leveldb" ) @@ -21,7 +22,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { log.Info("Set storage.Path to:", cfg.GetStoragePath()) db, err = NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { - return fmt.Errorf("failed to init level db: %v", err) + return errors.New("failed to init level db: %v", err) } log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) diff --git a/testworld/park.go b/testworld/park.go index b9376886f..11e5e4c7a 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -18,6 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/config" ctx "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/node" "github.com/gavv/httpexpect" @@ -116,7 +117,7 @@ func (r *hostManager) init(createConfig bool) error { go r.bernard.live(r.cancCtx) _, err = r.bernard.isLive(10 * time.Second) if err != nil { - return fmt.Errorf("bernard couldn't be made alive %v", err) + return errors.New("bernard couldn't be made alive %v", err) } bootnode, err := r.bernard.p2pURL() @@ -139,7 +140,7 @@ func (r *hostManager) init(createConfig bool) error { for name, host := range r.niceHosts { _, err = host.isLive(10 * time.Second) if err != nil { - return fmt.Errorf("%s couldn't be made alive %v", host.name, err) + return errors.New("%s couldn't be made alive %v", host.name, err) } i, err := host.id() if err != nil { @@ -263,7 +264,7 @@ func (h *host) init() error { func (h *host) live(c context.Context) error { srvs, err := node.GetServers(h.bootstrappedCtx) if err != nil { - return fmt.Errorf("failed to load servers: %v", err) + return errors.New("failed to load servers: %v", err) } h.node = node.New(srvs) @@ -318,7 +319,7 @@ func (h *host) isLive(softTimeOut time.Duration) (bool, error) { t := time.After(softTimeOut) select { case <-t: - return false, fmt.Errorf("host failed to live even after %f seconds", softTimeOut.Seconds()) + return false, errors.New("host failed to live even after %f seconds", softTimeOut.Seconds()) case err := <-sig: if err != nil { return false, err diff --git a/utils/events_test.go b/utils/events_test.go index 22fdf5e74..0bdf2e2bf 100644 --- a/utils/events_test.go +++ b/utils/events_test.go @@ -3,9 +3,9 @@ package utils import ( - "fmt" "testing" + "github.com/centrifuge/go-centrifuge/errors" "github.com/stretchr/testify/assert" ) @@ -27,7 +27,7 @@ func (m *mockIterator) Close() error { } func TestLookForEvent_iterator_error(t *testing.T) { - iter := &mockIterator{next: false, err: fmt.Errorf("failed iterator")} + iter := &mockIterator{next: false, err: errors.New("failed iterator")} err := LookForEvent(iter) assert.NotNil(t, err, "error should be non nil") assert.Contains(t, err.Error(), "failed iterator") diff --git a/utils/io.go b/utils/io.go index 667c7100c..e7e87d57c 100644 --- a/utils/io.go +++ b/utils/io.go @@ -2,9 +2,10 @@ package utils import ( "encoding/pem" - "fmt" "io/ioutil" "os" + + "github.com/centrifuge/go-centrifuge/errors" ) // WriteKeyToPemFile writes encode of key and purpose to the file @@ -33,10 +34,10 @@ func ReadKeyFromPemFile(fileName, keyPurpose string) (key []byte, err error) { } block, _ := pem.Decode(pemData) if block == nil { - return []byte{}, fmt.Errorf("file [%s] is not a valid pem file", fileName) + return []byte{}, errors.New("file [%s] is not a valid pem file", fileName) } if block.Type != keyPurpose { - return []byte{}, fmt.Errorf("key type mismatch got [%s] but expected [%s]", block.Type, keyPurpose) + return []byte{}, errors.New("key type mismatch got [%s] but expected [%s]", block.Type, keyPurpose) } return block.Bytes, nil diff --git a/utils/tools.go b/utils/tools.go index 8e78b3b64..530004747 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -2,9 +2,10 @@ package utils import ( "crypto/rand" - "errors" "math/big" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" From 0e6891fe58286c43466065e8e0e4bf74c3ca26d0 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 13 Dec 2018 16:05:27 +0100 Subject: [PATCH 083/220] Make tests into a table and parallel (#569) * Make tests into a table and parallel * Make tests into a table and parallel * Make tests into a table and parallel --- testworld/document_consensus_test.go | 27 ++++++++++++++++++++------- testworld/nft_test.go | 15 +++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index ac865f72c..efb6b42da 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -7,14 +7,27 @@ import ( "testing" ) -func TestHost_AddExternalCollaborator_invoice(t *testing.T) { +func TestHost_AddExternalCollaborator(t *testing.T) { t.Parallel() - addExternalCollaborator(t, typeInvoice) -} - -func TestHost_AddExternalCollaborator_po(t *testing.T) { - t.Parallel() - addExternalCollaborator(t, typePO) + tests := []struct { + name string + docType string + }{ + { + "Invoice_AddExternalCollaborator", + typeInvoice, + }, + { + "PO_AddExternalCollaborator", + typePO, + }, + } + for _, test := range tests { + t.Run(test.docType, func(t *testing.T) { + t.Parallel() + addExternalCollaborator(t, test.docType) + }) + } } func addExternalCollaborator(t *testing.T, documentType string) { diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 7d09d8501..46a80363e 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -73,15 +73,14 @@ func paymentObligationMint(t *testing.T, documentType string) { func TestPaymentObligationMint_errors(t *testing.T) { t.Parallel() - alice := doctorFord.getHostTestSuite(t, "Alice") - tests := []struct { errorMsg string httpStatus int payload map[string]interface{} }{ { + "RegistryAddress is not a valid Ethereum address", http.StatusInternalServerError, map[string]interface{}{ @@ -109,12 +108,12 @@ func TestPaymentObligationMint_errors(t *testing.T) { }, }, } - for _, test := range tests { - response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) - assert.Nil(t, err, "it should be possible to call the API endpoint") - response.Value("message").String().Contains(test.errorMsg) - + t.Run(test.errorMsg, func(t *testing.T) { + t.Parallel() + response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + assert.Nil(t, err, "it should be possible to call the API endpoint") + response.Value("message").String().Contains(test.errorMsg) + }) } - } From 0ecfdfa9c355b0326f25b49e05f4176ae678c465 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 13 Dec 2018 18:37:27 +0100 Subject: [PATCH 084/220] Config repository (#560) * Config Repositories * fmt * fix test * move config around * fmt * fmt * fmt * try higher timeout * Introduce Teddy and Dolores * Revert "Introduce Teddy and Dolores" This reverts commit 1a5dbf7ab78c919c1a3a7a50f46c2bc27369980d. --- Gopkg.lock | 18 +- anchors/anchor_test.go | 2 +- anchors/bootstrapper.go | 5 +- anchors/test_bootstrapper.go | 4 +- api/bootstrapper.go | 3 +- api/bootstrapper_test.go | 3 +- api/server_test.go | 5 +- bootstrap/bootstrapper.go | 1 + build/configs/default_config.yaml | 7 +- cmd/common.go | 7 +- config/bootstrapper.go | 10 +- config/configuration.go | 9 +- config/error.go | 11 + config/model.go | 57 ++++ config/model_test.go | 7 + config/repository.go | 271 ++++++++++++++++++ config/repository_test.go | 166 +++++++++++ config/test_bootstrapper.go | 7 +- coredocument/coredocument_test.go | 2 +- documents/bootstrapper.go | 14 +- documents/invoice/bootstrapper.go | 5 +- documents/invoice/model.go | 4 +- documents/invoice/model_test.go | 2 +- documents/purchaseorder/bootstrapper.go | 5 +- documents/purchaseorder/model_test.go | 2 +- documents/test/anchor_test.go | 2 +- ethereum/bootstrapper.go | 6 +- ethereum/geth_client_integration_test.go | 3 +- ethereum/geth_client_test.go | 2 +- healthcheck/handler_test.go | 2 +- identity/bootstrapper.go | 5 +- .../ethereum_identity_integration_test.go | 3 +- identity/identity_test.go | 2 +- keytools/ed25519/ed25519_test.go | 2 +- keytools/secp256k1/secp256k1_test.go | 2 +- nft/bootstrapper.go | 5 +- nft/payment_obligation_integration_test.go | 3 +- notification/notification_test.go | 2 - p2p/bootstrapper.go | 2 +- p2p/bootstrapper_test.go | 3 +- p2p/handler_integration_test.go | 3 +- p2p/handler_test.go | 2 +- queue/bootstrapper.go | 4 +- resources/data.go | 4 +- storage/bootstrapper.go | 27 +- storage/test_bootstrapper.go | 42 +-- storage/util.go | 14 + testworld/park.go | 4 +- 48 files changed, 661 insertions(+), 110 deletions(-) create mode 100644 config/error.go create mode 100644 config/repository.go create mode 100644 config/repository_test.go create mode 100644 storage/util.go diff --git a/Gopkg.lock b/Gopkg.lock index 16b8bb44f..4686ade13 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -342,22 +342,6 @@ pruneopts = "UT" revision = "d9f6b97f8db22dd1e090fd0bbbe98f09cc7dd0a8" -[[projects]] - digest = "1:0ade334594e69404d80d9d323445d2297ff8161637f9b2d347cc6973d2d6f05b" - name = "github.com/hashicorp/errwrap" - packages = ["."] - pruneopts = "UT" - revision = "8a6fb523712970c966eefc6b39ed2c5e74880354" - version = "v1.0.0" - -[[projects]] - digest = "1:f668349b83f7d779567c880550534addeca7ebadfdcf44b0b9c39be61864b4b7" - name = "github.com/hashicorp/go-multierror" - packages = ["."] - pruneopts = "T" - revision = "886a7fbe3eb1c874d46f623bfa70af45f425b3d1" - version = "v1.0.0" - [[projects]] digest = "1:8ec8d88c248041a6df5f6574b87bc00e7e0b493881dad2e7ef47b11dc69093b5" name = "github.com/hashicorp/golang-lru" @@ -1553,7 +1537,6 @@ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options", "github.com/grpc-ecosystem/grpc-gateway/runtime", "github.com/grpc-ecosystem/grpc-gateway/utilities", - "github.com/hashicorp/go-multierror", "github.com/ipfs/go-cid", "github.com/ipfs/go-datastore", "github.com/ipfs/go-ipfs-addr", @@ -1577,6 +1560,7 @@ "github.com/stretchr/testify/assert", "github.com/stretchr/testify/mock", "github.com/syndtr/goleveldb/leveldb", + "github.com/syndtr/goleveldb/leveldb/util", "github.com/whyrusleeping/go-logging", "golang.org/x/crypto/ed25519", "golang.org/x/net/context", diff --git a/anchors/anchor_test.go b/anchors/anchor_test.go index a4ec28c71..f600210f9 100644 --- a/anchors/anchor_test.go +++ b/anchors/anchor_test.go @@ -20,7 +20,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(Config) + cfg = ctx[bootstrap.BootstrappedConfig].(Config) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 1c8e8e648..6a9e55446 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -4,7 +4,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" ) @@ -18,10 +17,10 @@ type Bootstrapper struct{} // Bootstrap initializes the anchorRepositoryContract as well as the anchorConfirmationTask that depends on it. // the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[config.BootstrappedConfig]; !ok { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(Config) + cfg := ctx[bootstrap.BootstrappedConfig].(Config) if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") diff --git a/anchors/test_bootstrapper.go b/anchors/test_bootstrapper.go index 35d8fe55b..e96c2ee28 100644 --- a/anchors/test_bootstrapper.go +++ b/anchors/test_bootstrapper.go @@ -5,13 +5,13 @@ package anchors import ( "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" ) const BootstrappedAnchorRepository string = "BootstrappedAnchorRepository" func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - if _, ok := context[config.BootstrappedConfig]; !ok { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } diff --git a/api/bootstrapper.go b/api/bootstrapper.go index ff8d4b8de..1028555af 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -2,7 +2,6 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" ) @@ -12,7 +11,7 @@ type Bootstrapper struct{} // Bootstrap initiates api server func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[config.BootstrappedConfig].(Config) + cfg, ok := ctx[bootstrap.BootstrappedConfig].(Config) if !ok { return errors.New("config not initialised") } diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index ec244e842..0c62a19c8 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -22,7 +21,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { assert.Error(t, err) // config - m[config.BootstrappedConfig] = new(testingconfig.MockConfig) + m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/api/server_test.go b/api/server_test.go index b4ab8e46b..ac03a101e 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -22,7 +24,6 @@ import ( "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" ) @@ -52,7 +53,7 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) flag.Parse() result := m.Run() diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 8e4aaacb2..5bb8bac1b 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -4,6 +4,7 @@ package bootstrap // Bootstrap constants are keys to mapped value in bootstrapped context const ( + BootstrappedConfig string = "BootstrappedConfig" BootstrappedP2PServer string = "BootstrappedP2PServer" BootstrappedAPIServer string = "BootstrappedAPIServer" BootstrappedQueueServer string = "BootstrappedQueueServer" diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index e1215fc8a..6694bb58c 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -55,11 +55,16 @@ networks: anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" paymentObligation: "0x0417eb37941164368401D666984cED7694ABcBb1" -# Local Storage configuration +# Data Storage storage: # Path for levelDB file path: /tmp/centrifuge_data.leveldb +# Configuration Storage +configStorage: + # Path for levelDB file + path: /tmp/centrifuge_config_data.leveldb + # Interface where the API and P2P Server listens to nodeHostname: 0.0.0.0 # Port where API Server listens to diff --git a/cmd/common.go b/cmd/common.go index 0c49800cc..ca7d7314f 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,6 +3,8 @@ package cmd import ( "context" + "github.com/centrifuge/go-centrifuge/storage" + logging "github.com/ipfs/go-log" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -12,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/keytools" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" ) @@ -83,7 +84,7 @@ func CreateConfig( } log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) ctx, canc, _ := CommandBootstrap(v.ConfigFileUsed()) - cfg := ctx[config.BootstrappedConfig].(config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) generateKeys(cfg) idService := ctx[identity.BootstrappedIDService].(identity.Service) @@ -104,7 +105,9 @@ func CreateConfig( } canc() db := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + dbCfg := ctx[storage.BootstrappedConfigLevelDB].(*leveldb.DB) db.Close() + dbCfg.Close() return nil } diff --git a/config/bootstrapper.go b/config/bootstrapper.go index a0d0426c2..934556882 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -1,12 +1,9 @@ package config -import ( - "github.com/centrifuge/go-centrifuge/errors" -) +import "github.com/centrifuge/go-centrifuge/bootstrap" // Bootstrap constants are keys to the value mappings in context bootstrap. const ( - BootstrappedConfig string = "BootstrappedConfig" BootstrappedConfigFile string = "BootstrappedConfigFile" ) @@ -16,9 +13,10 @@ type Bootstrapper struct{} // Bootstrap takes the passed in config file, loads the config and puts the config back into context. func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if _, ok := context[BootstrappedConfigFile]; !ok { - return errors.New("config file hasn't been provided") + return ErrConfigFileBootstrapNotFound } cfgFile := context[BootstrappedConfigFile].(string) - context[BootstrappedConfig] = LoadConfiguration(cfgFile) + context[bootstrap.BootstrappedConfig] = LoadConfiguration(cfgFile) + return nil } diff --git a/config/configuration.go b/config/configuration.go index 96aed72ad..87f22fa0c 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -41,6 +41,7 @@ type Configuration interface { GetDuration(key string) time.Duration GetStoragePath() string + GetConfigStoragePath() string GetP2PPort() int GetP2PExternalIP() string GetP2PConnectionTimeout() time.Duration @@ -143,7 +144,12 @@ func (c *configuration) get(key string) interface{} { // GetStoragePath returns the data storage backend. func (c *configuration) GetStoragePath() string { - return c.GetString("storage.Path") + return c.GetString("storage.path") +} + +// GetConfigStoragePath returns the config storage backend. +func (c *configuration) GetConfigStoragePath() string { + return c.GetString("configStorage.path") } // GetP2PPort returns P2P Port. @@ -398,6 +404,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v := viper.New() v.SetConfigType("yaml") v.Set("storage.path", targetDataDir+"/db/centrifuge_data.leveldb") + v.Set("configStorage.path", targetDataDir+"/db/centrifuge_config_data.leveldb") v.Set("identityId", "") v.Set("centrifugeNetwork", network) v.Set("nodeHostname", "0.0.0.0") diff --git a/config/error.go b/config/error.go new file mode 100644 index 000000000..51140d84f --- /dev/null +++ b/config/error.go @@ -0,0 +1,11 @@ +package config + +import "github.com/centrifuge/go-centrifuge/errors" + +const ( + // ErrConfigBootstrap used as default error type + ErrConfigBootstrap = errors.Error("error when bootstrapping config") + + // ErrConfigFileBootstrapNotFound used when config file is not found + ErrConfigFileBootstrapNotFound = errors.Error("config file hasn't been provided") +) diff --git a/config/model.go b/config/model.go index 2d62b936f..528b84f9f 100644 --- a/config/model.go +++ b/config/model.go @@ -1,10 +1,27 @@ package config import ( + "encoding/json" "math/big" + "reflect" "time" ) +// Model is an interface for both tenant and node config models +type Model interface { + // Get the ID of the document represented by this model + ID() ([]byte, error) + + //Returns the underlying type of the Model + Type() reflect.Type + + // JSON return the json representation of the model + JSON() ([]byte, error) + + // FromJSON initialize the model with a json + FromJSON(json []byte) error +} + // KeyPair represents a key pair config type KeyPair struct { Pub, Priv string @@ -40,6 +57,26 @@ type NodeConfig struct { // TODO what to do about contract addresses? } +// ID Gets the ID of the document represented by this model +func (nc *NodeConfig) ID() ([]byte, error) { + return []byte{}, nil +} + +// Type Returns the underlying type of the Model +func (nc *NodeConfig) Type() reflect.Type { + return reflect.TypeOf(nc) +} + +// JSON return the json representation of the model +func (nc *NodeConfig) JSON() ([]byte, error) { + return json.Marshal(nc) +} + +// FromJSON initialize the model with a json +func (nc *NodeConfig) FromJSON(data []byte) error { + return json.Unmarshal(data, nc) +} + // NewNodeConfig creates a new NodeConfig instance with configs func NewNodeConfig(config Configuration) *NodeConfig { return &NodeConfig{ @@ -75,6 +112,26 @@ type TenantConfig struct { EthAuthKeyPair KeyPair } +// ID Get the ID of the document represented by this model +func (tc *TenantConfig) ID() ([]byte, error) { + return tc.IdentityID, nil +} + +// Type Returns the underlying type of the Model +func (tc *TenantConfig) Type() reflect.Type { + return reflect.TypeOf(tc) +} + +// JSON return the json representation of the model +func (tc *TenantConfig) JSON() ([]byte, error) { + return json.Marshal(tc) +} + +// FromJSON initialize the model with a json +func (tc *TenantConfig) FromJSON(data []byte) error { + return json.Unmarshal(data, tc) +} + // NewTenantConfig creates a new TenantConfig instance with configs func NewTenantConfig(ethAccountName string, config Configuration) (*TenantConfig, error) { id, err := config.GetIdentityID() diff --git a/config/model_test.go b/config/model_test.go index ee38b08c8..b7b52a56c 100644 --- a/config/model_test.go +++ b/config/model_test.go @@ -1,3 +1,5 @@ +// +build unit + package config import ( @@ -21,6 +23,11 @@ func (m *mockConfig) GetStoragePath() string { return args.Get(0).(string) } +func (m *mockConfig) GetConfigStoragePath() string { + args := m.Called() + return args.Get(0).(string) +} + func (m *mockConfig) GetP2PPort() int { args := m.Called() return args.Get(0).(int) diff --git a/config/repository.go b/config/repository.go new file mode 100644 index 000000000..ca32baabc --- /dev/null +++ b/config/repository.go @@ -0,0 +1,271 @@ +package config + +import ( + "encoding/json" + "fmt" + "reflect" + "sync" + + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" +) + +const ( + configPrefix string = "config" + tenantPrefix string = "tenant-" +) + +// Repository defines the required methods for the config repository. +type Repository interface { + // Get returns the tenant config Model associated with tenant ID + GetTenant(id []byte) (Model, error) + + // GetConfig returns the node config model + GetConfig() (Model, error) + + // GetAllTenants returns a list of all tenant models in the config DB + GetAllTenants() ([]Model, error) + + // Create creates the tenant config model if not present in the DB. + // should error out if the config exists. + CreateTenant(id []byte, model Model) error + + // Create creates the node config model if not present in the DB. + // should error out if the config exists. + CreateConfig(model Model) error + + // Update strictly updates the tenant config model. + // Will error out when the config model doesn't exist in the DB. + UpdateTenant(id []byte, model Model) error + + // Update strictly updates the node config model. + // Will error out when the config model doesn't exist in the DB. + UpdateConfig(model Model) error + + // Delete deletes tenant config + // Will not error out when config model doesn't exists in DB + DeleteTenant(id []byte) error + + // Delete deletes node config + // Will not error out when config model doesn't exists in DB + DeleteConfig() error + + // Register registers the model so that the DB can return the config without knowing the type + Register(model Model) +} + +// levelDBRepo implements Repository using LevelDB as storage layer +type levelDBRepo struct { + db *leveldb.DB + models map[string]reflect.Type + mu sync.RWMutex // to protect the models +} + +// value is an internal representation of how levelDb stores the model. +type value struct { + Type string `json:"type"` + Data json.RawMessage `json:"data"` +} + +// NewLevelDBRepository returns levelDb implementation of Repository +func NewLevelDBRepository(db *leveldb.DB) Repository { + return &levelDBRepo{ + db: db, + models: make(map[string]reflect.Type), + } +} + +func (l *levelDBRepo) getTenantKey(id []byte) []byte { + return append([]byte(tenantPrefix), id...) +} + +func (l *levelDBRepo) getConfigKey() []byte { + return []byte(configPrefix) +} + +// getModel returns a new instance of the type mt. +func (l *levelDBRepo) getModel(mt string) (Model, error) { + tp, ok := l.models[mt] + if !ok { + return nil, fmt.Errorf("type %s not registered", mt) + } + + return reflect.New(tp).Interface().(Model), nil +} + +func (l *levelDBRepo) GetTenant(id []byte) (Model, error) { + key := l.getTenantKey(id) + return l.get(key) +} + +func (l *levelDBRepo) GetConfig() (Model, error) { + key := l.getConfigKey() + return l.get(key) +} + +func (l *levelDBRepo) parseModel(data []byte) (Model, error) { + v := new(value) + err := json.Unmarshal(data, v) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal value: %v", err) + } + + nm, err := l.getModel(v.Type) + if err != nil { + return nil, fmt.Errorf("failed to get model type: %v", err) + } + + err = nm.FromJSON([]byte(v.Data)) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal to model: %v", err) + } + + return nm, nil +} + +// Get returns the model associated with ID +func (l *levelDBRepo) get(id []byte) (Model, error) { + l.mu.RLock() + defer l.mu.RUnlock() + data, err := l.db.Get(id, nil) + if err != nil { + return nil, fmt.Errorf("config missing: %v", err) + } + + return l.parseModel(data) +} + +// GetAllTenants iterates over all tenant entries in DB and returns a list of Models +// If an error occur reading a tenant, throws a warning and continue +func (l *levelDBRepo) GetAllTenants() ([]Model, error) { + var models []Model + l.mu.RLock() + defer l.mu.RUnlock() + iter := l.db.NewIterator(util.BytesPrefix([]byte(tenantPrefix)), nil) + for iter.Next() { + data := iter.Value() + model, err := l.parseModel(data) + if err != nil { + log.Warningf("Error parsing tenant: %v", err) + continue + } + models = append(models, model) + } + iter.Release() + return models, iter.Error() +} + +// save stores the model. +func (l *levelDBRepo) save(id []byte, model Model) error { + data, err := model.JSON() + if err != nil { + return fmt.Errorf("failed to marshall model: %v", err) + } + + tp := getTypeIndirect(model.Type()) + v := value{ + Type: tp.String(), + Data: json.RawMessage(data), + } + + data, err = json.Marshal(v) + if err != nil { + return fmt.Errorf("failed to marshall value: %v", err) + } + + err = l.db.Put(id, data, nil) + if err != nil { + return fmt.Errorf("failed to save model to DB: %v", err) + } + + return nil +} + +// Exists returns true if the id exists. +func (l *levelDBRepo) exists(id []byte) bool { + res, err := l.db.Has(id, nil) + // TODO check this + if err != nil { + return false + } + + return res +} + +// Create creates the tenant config model if not present in the DB. +// should error out if the config exists. +func (l *levelDBRepo) CreateTenant(id []byte, model Model) error { + key := l.getTenantKey(id) + return l.create(key, model) +} + +// Create creates the node config model if not present in the DB. +// should error out if the config exists. +func (l *levelDBRepo) CreateConfig(model Model) error { + key := l.getConfigKey() + return l.create(key, model) +} + +// Create stores the model to the DB. +// Errors out if the model already exists. +func (l *levelDBRepo) create(id []byte, model Model) error { + if l.exists(id) { + return fmt.Errorf("model already exists") + } + + return l.save(id, model) +} + +// Update strictly updates the tenant config model. +// Will error out when the config model doesn't exist in the DB. +func (l *levelDBRepo) UpdateTenant(id []byte, model Model) error { + key := l.getTenantKey(id) + return l.update(key, model) +} + +// Update strictly updates the node config model. +// Will error out when the config model doesn't exist in the DB. +func (l *levelDBRepo) UpdateConfig(model Model) error { + key := l.getConfigKey() + return l.update(key, model) +} + +// Update overwrites the value at tenantID+id. +// Errors out if model doesn't exist +func (l *levelDBRepo) update(id []byte, model Model) error { + if !l.exists(id) { + return fmt.Errorf("model doesn't exist") + } + + return l.save(id, model) +} + +// Delete deletes tenant config +// Will not error out when config model doesn't exists in DB +func (l *levelDBRepo) DeleteTenant(id []byte) error { + key := l.getTenantKey(id) + return l.db.Delete(key, nil) +} + +func (l *levelDBRepo) DeleteConfig() error { + key := l.getConfigKey() + return l.db.Delete(key, nil) +} + +// Register registers the model for type less operations. +// Same type names will be overwritten. +func (l *levelDBRepo) Register(model Model) { + l.mu.Lock() + defer l.mu.Unlock() + tp := getTypeIndirect(model.Type()) + l.models[tp.String()] = tp +} + +// getTypeIndirect returns the type of the model without pointers. +func getTypeIndirect(tp reflect.Type) reflect.Type { + if tp.Kind() == reflect.Ptr { + return getTypeIndirect(tp.Elem()) + } + + return tp +} diff --git a/config/repository_test.go b/config/repository_test.go new file mode 100644 index 000000000..c5244ee83 --- /dev/null +++ b/config/repository_test.go @@ -0,0 +1,166 @@ +// +build unit + +package config + +import ( + "os" + "reflect" + "testing" + + "github.com/syndtr/goleveldb/leveldb" + + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/stretchr/testify/assert" +) + +func getRandomStorage() (*leveldb.DB, error) { + return storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) +} + +func TestMain(m *testing.M) { + result := m.Run() + os.Exit(result) +} + +func TestNewLevelDBRepository(t *testing.T) { + testStorage, _ := getRandomStorage() + repo := NewLevelDBRepository(testStorage) + assert.NotNil(t, repo) +} + +func TestUnregisteredModel(t *testing.T) { + testStorage, _ := getRandomStorage() + repo := NewLevelDBRepository(testStorage) + assert.NotNil(t, repo) + id := utils.RandomSlice(32) + newTenant := &TenantConfig{ + IdentityID: id, + EthereumDefaultAccountName: "main", + } + err := repo.CreateTenant(id, newTenant) + assert.Nil(t, err) + + // Error on non registered model + _, err = repo.GetTenant(id) + assert.NotNil(t, err) + + repo.Register(&TenantConfig{}) + + _, err = repo.GetTenant(id) + assert.Nil(t, err) +} + +func TestTenantOperations(t *testing.T) { + testStorage, _ := getRandomStorage() + repo := NewLevelDBRepository(testStorage) + assert.NotNil(t, repo) + id := utils.RandomSlice(32) + newTenant := &TenantConfig{ + IdentityID: id, + EthereumDefaultAccountName: "main", + } + repo.Register(&TenantConfig{}) + err := repo.CreateTenant(id, newTenant) + assert.Nil(t, err) + + // Create tenant already exist + err = repo.CreateTenant(id, newTenant) + assert.NotNil(t, err) + + readModel, err := repo.GetTenant(id) + assert.Nil(t, err) + readTenant := readModel.(*TenantConfig) + assert.Equal(t, reflect.TypeOf(newTenant), readTenant.Type()) + assert.Equal(t, newTenant.IdentityID, readTenant.IdentityID) + + // Update tenant + newTenant.EthereumDefaultAccountName = "secondary" + err = repo.UpdateTenant(id, newTenant) + assert.Nil(t, err) + + // Update tenant does not exist + newId := utils.RandomSlice(32) + err = repo.UpdateTenant(newId, newTenant) + assert.NotNil(t, err) + + // Delete tenant + err = repo.DeleteTenant(id) + assert.Nil(t, err) + _, err = repo.GetTenant(id) + assert.NotNil(t, err) +} + +func TestConfigOperations(t *testing.T) { + testStorage, _ := getRandomStorage() + repo := NewLevelDBRepository(testStorage) + assert.NotNil(t, repo) + newConfig := &NodeConfig{ + NetworkID: 4, + } + repo.Register(&NodeConfig{}) + err := repo.CreateConfig(newConfig) + assert.Nil(t, err) + + // Create config already exist + err = repo.CreateConfig(newConfig) + assert.NotNil(t, err) + + readModel, err := repo.GetConfig() + readDoc := readModel.(*NodeConfig) + assert.Nil(t, err) + assert.Equal(t, reflect.TypeOf(newConfig), readDoc.Type()) + assert.Equal(t, newConfig.NetworkID, readDoc.NetworkID) + + // Update config + newConfig.NetworkID = 42 + err = repo.UpdateConfig(newConfig) + assert.Nil(t, err) + + // Delete config + err = repo.DeleteConfig() + assert.Nil(t, err) + _, err = repo.GetConfig() + assert.NotNil(t, err) + + // Update config does not exist + err = repo.UpdateConfig(newConfig) + assert.NotNil(t, err) +} + +func TestLevelDBRepo_GetAllTenants(t *testing.T) { + testStorage, _ := getRandomStorage() + repo := NewLevelDBRepository(testStorage) + assert.NotNil(t, repo) + repo.Register(&TenantConfig{}) + ids := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32), utils.RandomSlice(32)} + ten1 := &TenantConfig{ + IdentityID: ids[0], + EthereumDefaultAccountName: "main", + } + ten2 := &TenantConfig{ + IdentityID: ids[1], + EthereumDefaultAccountName: "main", + } + ten3 := &TenantConfig{ + IdentityID: ids[2], + EthereumDefaultAccountName: "main", + } + + err := repo.CreateTenant(ids[0], ten1) + assert.Nil(t, err) + err = repo.CreateTenant(ids[1], ten2) + assert.Nil(t, err) + err = repo.CreateTenant(ids[2], ten3) + assert.Nil(t, err) + + tenants, err := repo.GetAllTenants() + assert.Nil(t, err) + assert.Equal(t, 3, len(tenants)) + t0Id, _ := tenants[0].ID() + t1Id, _ := tenants[1].ID() + t2Id, _ := tenants[2].ID() + assert.Contains(t, ids, t0Id) + assert.Contains(t, ids, t1Id) + assert.Contains(t, ids, t2Id) +} diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 2fa6e5ce6..59c9b90da 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -6,6 +6,8 @@ import ( "fmt" "path/filepath" "strings" + + "github.com/centrifuge/go-centrifuge/bootstrap" ) func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { @@ -21,8 +23,9 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { log.Fatal("Current working dir is not in `go-centrifuge`") } } - c := LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) - context[BootstrappedConfig] = c + + context[bootstrap.BootstrappedConfig] = LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) + return nil } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 27496227f..bfccd4045 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) flag.Parse() cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 41ec72820..aa7f4208b 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -1,16 +1,16 @@ package documents import ( - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" ) -// BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context -const BootstrappedRegistry = "BootstrappedRegistry" - -// BootstrappedDocumentRepository is the key to the database repository of documents -const BootstrappedDocumentRepository = "BootstrappedDocumentRepository" +const ( + // BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context + BootstrappedRegistry = "BootstrappedRegistry" + // BootstrappedDocumentRepository is the key to the database repository of documents + BootstrappedDocumentRepository = "BootstrappedDocumentRepository" +) // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} @@ -20,7 +20,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { ctx[BootstrappedRegistry] = NewServiceRegistry() ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) if !ok { - return errors.Error(ErrDocumentBootstrap) + return ErrDocumentBootstrap } repo := NewLevelDBRepository(ldb) ctx[BootstrappedDocumentRepository] = repo diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 7f47d4fc8..30191c79c 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -17,11 +18,11 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[config.BootstrappedConfig]; !ok { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 9b215f853..ad9b59f98 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -35,8 +35,8 @@ type Invoice struct { RecipientStreet string RecipientCity string RecipientZipcode string - RecipientCountry string // country ISO code of the receipient of this invoice - Currency string // country ISO code of the receipient of this invoice + RecipientCountry string // country ISO code of the recipient of this invoice + Currency string // country ISO code of the recipient of this invoice GrossAmount int64 // invoice amount including tax NetAmount int64 // invoice amount excluding tax TaxAmount int64 diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 7593aebd4..fe11037f6 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -53,7 +53,7 @@ func TestMain(m *testing.M) { &queue.Starter{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index e2add12fb..fa50503fd 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -17,10 +18,10 @@ type Bootstrapper struct{} // Bootstrap initialises required services for purchaseorder. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[config.BootstrappedConfig]; !ok { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(config.Configuration) + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) if !ok { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 54f082551..450b2098d 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index 9268b0841..ab33cfa0c 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -27,7 +27,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 496b0b78a..9bff73d54 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -3,7 +3,7 @@ package ethereum import ( "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" ) // BootstrappedEthereumClient is a key to mapped client in bootstrap context. @@ -14,10 +14,10 @@ type Bootstrapper struct{} // Bootstrap initialises ethereum client. func (Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[config.BootstrappedConfig]; !ok { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[config.BootstrappedConfig].(Config) + cfg := context[bootstrap.BootstrappedConfig].(Config) client, err := NewGethClient(cfg) if err != nil { return err diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 8fb70caad..27adca307 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -6,6 +6,7 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/ethereum" @@ -16,7 +17,7 @@ var cfg config.Configuration func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index 57f6f0acc..c7c41edef 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -30,7 +30,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("ethereum.txPoolAccessEnabled", false) cfg.Set("ethereum.intervalRetry", time.Millisecond*100) result := m.Run() diff --git a/healthcheck/handler_test.go b/healthcheck/handler_test.go index fae97a9b0..b7592fcc9 100644 --- a/healthcheck/handler_test.go +++ b/healthcheck/handler_test.go @@ -22,7 +22,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index 243f4d531..b511d56e4 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -4,7 +4,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -20,10 +19,10 @@ type Bootstrapper struct{} // Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. // the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[config.BootstrappedConfig]; !ok { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[config.BootstrappedConfig].(Config) + cfg := context[bootstrap.BootstrappedConfig].(Config) if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 1014bd146..688792879 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/identity" @@ -24,7 +25,7 @@ func TestMain(m *testing.M) { time.Sleep(time.Second + 2) ctx := cc.TestFunctionalEthereumBootstrap() - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/identity/identity_test.go b/identity/identity_test.go index b68318e76..a0b0f0a7d 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -25,7 +25,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/keytools/ed25519/ed25519_test.go b/keytools/ed25519/ed25519_test.go index 851b5ea19..7f333cc55 100644 --- a/keytools/ed25519/ed25519_test.go +++ b/keytools/ed25519/ed25519_test.go @@ -19,7 +19,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() os.Exit(result) } diff --git a/keytools/secp256k1/secp256k1_test.go b/keytools/secp256k1/secp256k1_test.go index 9b34b8502..43458b380 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/keytools/secp256k1/secp256k1_test.go @@ -25,7 +25,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() os.Exit(result) } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index e3e108df9..dba1ecf93 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -4,7 +4,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" @@ -19,10 +18,10 @@ type Bootstrapper struct{} // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[config.BootstrappedConfig]; !ok { + if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := ctx[config.BootstrappedConfig].(Config) + cfg := ctx[bootstrap.BootstrappedConfig].(Config) if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 71fe4ac0f..1ec5cca2c 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -34,7 +35,7 @@ func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) idService = ctx[identity.BootstrappedIDService].(identity.Service) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) prevSignPubkey := cfg.Get("keys.signing.publicKey") prevSignPrivkey := cfg.Get("keys.signing.privateKey") diff --git a/notification/notification_test.go b/notification/notification_test.go index 3bc3d3e8e..7b8d55012 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -13,7 +13,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/jsonpb" @@ -25,7 +24,6 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, nil) result := m.Run() diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index bd7dcca02..e1813b0f5 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -17,7 +17,7 @@ type Bootstrapper struct{} // Bootstrap initiates p2p server and client into context func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[config.BootstrappedConfig].(config.Configuration) + cfg, ok := ctx[bootstrap.BootstrappedConfig].(config.Configuration) if !ok { return errors.New("config not initialised") } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 7dfd4b829..7a9ed22d4 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -22,7 +21,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { assert.Error(t, err) // config - m[config.BootstrappedConfig] = new(testingconfig.MockConfig) + m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 026e13bc0..6f6c2bc1f 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/coredocument" @@ -42,7 +43,7 @@ func TestMain(m *testing.M) { registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/p2p/handler_test.go b/p2p/handler_test.go index 00fe2d4df..ce204e8ee 100644 --- a/p2p/handler_test.go +++ b/p2p/handler_test.go @@ -44,7 +44,7 @@ func TestMain(m *testing.M) { } ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[config.BootstrappedConfig].(config.Configuration) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index cff475b75..b2acc20de 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -14,10 +14,10 @@ type Bootstrapper struct { // Bootstrap initiates the queue. func (b *Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[config.BootstrappedConfig]; !ok { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config hasn't been initialized") } - cfg := context[config.BootstrappedConfig].(config.Configuration) + cfg := context[bootstrap.BootstrappedConfig].(config.Configuration) srv := &Server{config: cfg, taskTypes: []TaskType{}} context[bootstrap.BootstrappedQueueServer] = srv b.context = context diff --git a/resources/data.go b/resources/data.go index 739a5df0a..f3f7d5b5f 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x5b\x6f\xdb\x3a\xd6\x7d\xf7\xaf\xd8\x70\x5e\xbe\x0f\x18\x39\xba\x5f\x0c\x1c\x0c\xec\x5c\xda\x9e\xa6\x19\x27\x71\x4e\x4e\xf3\x32\xa5\xc8\x2d\x8b\x8d\x4c\xaa\x24\xe5\x4b\x7f\xfd\x80\x94\x9c\x26\x4d\x93\x33\x83\xc1\xf4\xa5\x32\xc9\xbd\xb9\x2f\x6b\x2d\x92\x39\x82\x53\xac\x48\xd7\x18\x60\xb8\xc1\x46\xb6\x6b\x14\x06\x0c\x6a\x23\xd0\x00\x59\x11\x2e\xb4\x01\xc5\xc5\x03\x96\xfb\x11\x45\x61\x14\xaf\xba\x15\x5e\xa2\xd9\x4a\xf5\x30\x05\xd5\x69\xcd\x89\xa8\x79\xd3\x8c\x9c\x33\x2e\x10\x4c\x8d\xc0\x06\xbf\xa2\x5f\xa9\xc1\xd4\xc4\xc0\xc9\xa3\x07\x58\x13\x2e\x8c\xf5\x3f\x3a\x2c\x99\x8e\x00\x8e\xe0\x42\x52\xd2\xb8\x10\xb8\x58\x01\x95\xc2\x28\x42\x0d\x10\xc6\x14\x6a\x8d\x1a\x04\x22\x03\x23\xa1\x44\xd0\x68\x60\xcb\x4d\x0d\x28\x36\xb0\x21\x8a\x93\xb2\x41\x3d\x19\xc1\xc1\xde\xba\x04\xe0\x6c\x0a\x51\x14\xb9\x6f\x34\x35\x2a\xec\xd6\x43\x06\x1f\xd8\x14\xf2\x28\xef\xe7\x4a\x29\x8d\x36\x8a\xb4\x0b\x44\xa5\x7b\x5b\x0f\xc6\xc7\xbc\x8d\x8f\x83\x30\x9b\xf8\x13\x7f\x12\x1c\x1b\xda\x1e\x47\x79\xe8\x87\xc7\xbc\xad\xf4\xf1\xd5\x7a\x79\xb5\x2b\xb7\x0f\xdd\xfd\xe7\xcf\xa7\x55\xf7\x7d\x59\xee\xce\x66\xd7\xb8\xbc\x3c\xb9\x90\xdf\xf7\xfb\x24\xc9\x37\x57\x62\xf5\xc7\x66\xf1\xe9\xeb\xc5\xe7\x87\xf1\x5f\x38\x8d\x0e\x4e\xff\xa8\xd2\xb3\xcb\x74\xfd\xf0\xed\x0e\xbf\xde\x7d\xbc\x0b\xbf\x2d\xba\x20\xfd\xb3\x65\xef\xa2\x87\xdf\x65\xb0\x8c\xd6\x35\xa9\x17\xf3\xe4\x06\x13\x11\xf4\x4e\x0f\xa5\x9a\x1d\x2a\xd5\x27\x60\xd3\x47\x61\xb8\xd9\x9f\x13\x6a\xa4\xda\x4f\x61\x3c\xfe\x69\xe6\x1a\x57\x5c\x9b\x67\x53\x44\xd0\x5a\xaa\x6b\x6c\xa5\xe6\x3f\x59\xb5\x64\x6f\x61\xf2\x8f\xb2\xe1\x2b\x62\xb8\x14\x6e\xce\x35\xef\x13\xe1\xe2\x97\x50\x1a\x7a\x3c\x82\xa7\x88\xe9\x03\x3c\x82\xcb\x6e\x8d\x8a\x53\xf8\x70\x0a\xb2\x72\xe8\x79\x82\x93\x1f\x96\x7d\x23\x93\x60\xb0\x9a\x1f\xba\x05\x0d\xd7\xc6\x5a\x0a\xc9\xf0\x25\xd0\x5a\x25\x37\xdc\x4d\x48\xe7\xfb\x49\x00\x87\xf0\xfe\xb2\xfb\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x46\x40\x10\x9e\x46\x1f\xa5\xbc\xbb\xe0\x9c\x5e\xfd\xb1\x5d\xd6\xcb\xf9\xe7\x74\xf7\x91\x2e\xe4\x45\x95\x5e\x5f\x7d\xfe\xfd\xbc\xdd\x56\x81\xca\x92\xed\xc5\x2e\xbc\xbf\x8e\xda\x13\x16\x8c\x7f\xe5\x3e\x4f\x27\x61\xe0\xbf\xe6\xfe\xea\xfe\xd3\x2c\x7f\xb7\x78\xaf\x36\x67\xf7\xf3\x62\xcb\x1e\xe4\x2d\x9d\xcd\xd6\x27\xf7\xef\xdb\x02\xf7\xfb\xfb\xf8\xe6\x2c\x5f\x9d\xab\xa8\x5e\x5e\xfe\x39\x1e\x6a\x74\x36\xa0\xfd\x50\x45\x5b\x62\x0f\xae\x07\x3e\xbf\xc2\x87\x78\x30\xbe\x20\xb6\x3c\xc0\xb0\x6d\xe4\x1e\x19\xdc\xac\x89\x32\x70\x32\xc0\x4c\x43\x25\x95\x2b\xe8\x8a\x6f\x50\x3c\x2b\xe5\x4b\x28\xc2\xab\x58\xf4\x77\x85\xcf\xc2\x22\x4e\xb2\x00\xb3\x28\x8f\xc3\xb4\xc8\x48\x9a\x96\x19\x29\x0a\xe2\x17\x8c\xa5\x34\x8b\x58\x94\xa4\xec\x0d\xd4\xfa\xbb\x22\x4d\x7d\xea\x47\x05\x8b\x82\x20\x4e\x22\x52\xf9\x2c\xc9\x69\x92\xa6\x69\x16\x46\xac\xa0\x61\x45\x32\x96\x22\x7d\x03\xdf\xfe\x2e\xab\xf2\x24\x66\x15\x29\x72\x3f\x08\x59\x56\x91\x24\xa1\xb9\x1f\x95\x25\x09\xc3\xd4\x2f\x29\x43\x8c\xcb\x04\xd9\x5b\x4c\xf0\x77\xac\xf4\x93\x3c\x98\x15\x51\x98\xa7\x69\x9c\x27\x49\x14\xe6\x33\x76\x5a\xfa\x67\x61\x12\x04\x79\x9c\xc6\x7e\x55\x60\x72\xea\x38\x53\xa2\x12\xa4\xa9\x91\xaf\x6a\x33\x80\xee\xe8\xe8\x68\xe8\xc0\x47\xb9\x21\x02\xce\x67\x57\xc3\x6f\x0f\xee\xac\xda\x71\x51\x75\x8a\xc0\x5e\x76\xb0\xb2\x32\x2d\x00\x95\x92\xca\xc2\x69\x59\x73\x0d\x0a\xbf\x75\xb6\x73\x5c\x83\x90\x06\x74\xd7\xb6\x52\x19\x64\x50\x22\x25\x9d\x46\x6b\xa9\x1c\x5b\xec\x12\xd5\x09\x61\xa5\xd6\x09\xa9\x36\xc4\x58\xca\x74\x76\x68\x02\xd7\x9d\xe8\xc7\x3d\x6f\x18\xfb\x8d\x28\x5a\xf3\x0d\x4e\xc6\x7f\x1b\x82\x02\xd8\x5a\xc6\x19\x09\x4c\xfe\xdd\x59\x10\x68\x9c\x88\xb7\x44\x71\xb3\xef\x37\x72\x5e\x1e\x5c\x3e\xb8\x9a\xf6\x3f\xbf\x0c\x0b\x3c\x8f\xd6\x84\x8b\xdf\xfa\x69\xcf\xb3\xd1\xfe\x16\xf9\x91\x1f\x83\xe7\x6d\x89\x6a\x87\xff\xbc\x92\x28\xc5\x51\x41\x92\xe6\xbe\xef\xfb\xe0\x79\x42\x7a\x44\x50\x8e\xc2\x78\x65\x23\xe9\x83\xee\xc7\x34\xaa\x0d\x7a\x8d\x2d\x2a\x78\xde\x9a\xec\xbc\xd6\x92\x1a\xc2\xc4\x1a\x69\x41\x5a\x5d\x4b\x33\x0c\xba\xb1\x35\x17\xcf\x7e\xda\x98\x09\x35\x7c\x83\xe0\x79\x16\xcc\xb6\x44\xb2\xaa\x5e\x56\x02\x3c\x8f\x95\x1e\x95\xeb\xd6\xae\x97\x02\xb4\x66\x36\x25\x42\x6b\xf4\x34\xff\x8e\x10\xfb\x45\x0a\x9e\xf7\x55\x4b\xa1\x5a\xea\xd5\x52\x1b\x0d\xa4\x69\x9e\x8c\x71\x61\x50\x55\x84\xa2\x1d\xff\xf2\xbc\xdd\x2f\x8b\xf9\xab\xce\xcf\x6d\xfa\xc8\x2c\xf7\x04\xf6\x81\x18\x09\x77\x58\xde\xd8\x71\xa3\xc1\xd5\x44\x41\xa5\xe4\x1a\x3a\x61\x54\xa7\x2d\x24\xa4\xe2\x2b\x2e\xa6\x30\x99\x8c\x5f\xed\xa7\x25\xf9\x8b\x5e\x7e\xf1\xbc\x4e\x68\x52\xa1\x87\xbb\x56\x6a\xfc\x02\x55\x43\x56\x3f\x01\xf8\x3f\x53\xf6\xf0\xbf\x54\xf6\x67\x5c\xfa\xb7\xb5\x3d\xf0\xe3\x49\x90\xc4\x93\x20\x9f\x24\x2f\x4e\xf7\x83\xf8\x2e\x74\xca\x09\xde\x76\xe7\xf7\x97\x5d\xf0\x6e\xb7\xd1\xfb\xf9\xf2\x46\x2d\x75\xb1\x31\xf3\xb4\x34\x9f\x66\xe2\xfd\xb9\xbc\xf8\x5a\x3e\x7c\x3f\x21\xe3\x5f\xb8\x4f\x26\x41\x9e\x4c\xc2\x28\x7b\x75\x83\x93\x77\x74\xcb\x97\x5f\xe5\xc7\xbb\xf7\xd5\x9c\xc4\x79\x78\xbb\x30\x04\x6f\x77\x97\x17\x5b\x96\x7f\x2f\xc5\x3c\xb8\xc9\xb6\x38\xbb\xbf\xdd\xdd\xbf\xad\xee\x4e\x34\x5e\xd5\xf6\xf0\x7f\x20\xee\x6f\x68\x7b\x9e\x94\x51\x58\x65\x24\xaa\x62\x3f\xce\x83\x2a\x08\xa3\x28\xf6\xe3\x20\xcd\x7c\x9a\xd3\x12\xfd\xac\xca\x58\x56\xd0\x37\xb5\x3d\x89\x09\x46\x59\x54\xf9\x45\x5a\x91\x2a\x64\x65\x5a\xe6\x24\x4e\xb3\x20\xa3\x7e\x59\xe4\x48\x2b\xe2\x67\x09\x63\x6f\x6a\x7b\x1c\xc7\x55\x1a\x17\x18\xf9\x59\x1c\x87\x98\xa5\x94\x56\x59\x94\xc5\x69\x8a\x49\x58\x05\xa9\x5f\x94\x45\x1e\xa6\xfe\xdb\xda\xee\xc7\x41\x86\x65\x94\x15\x71\x10\xa4\x71\x94\xe6\xb1\x1f\x9c\xa6\x69\x5a\xe4\x31\x3d\x3b\xcd\xd2\x22\x9e\xcd\xe9\xbc\x0c\xc6\xa3\xd1\xe1\x2a\x7b\x63\xa4\x22\x2b\xb4\x75\xab\xf8\xaa\x53\xce\xd9\x48\xf7\xa3\xfd\x9d\x77\x41\x4c\xed\x2a\xde\xd8\xab\xd3\xe9\x1c\x2a\xde\xe0\xc8\xc6\x60\xea\x29\x1c\x9b\x75\x7b\xfc\xe3\xee\xfd\x4f\x46\x0c\x99\xb8\x95\xac\xb4\xdb\x7c\x78\xd4\x8e\xad\xed\xb7\x6b\xdb\x6c\xf1\x01\x88\x60\xb0\x08\x17\x70\xd3\x13\xdf\x72\x09\x85\x25\xcb\xc8\xd2\xe9\xbd\xd4\x46\x90\x35\x4e\xc1\x77\x77\x50\x7f\x74\x04\x0b\xa9\xcc\xe0\xc4\x3a\xf8\xb5\xa1\x5d\x34\x85\xdc\xcf\x43\xbb\xb9\x25\x94\x67\xa4\xd3\xce\xe7\x29\xea\x51\x1b\xb6\x7d\x7e\x37\x2d\x52\x5e\xed\xe1\x6c\x67\x1c\x45\xe1\xc3\xe2\x49\xac\x4e\x53\x28\x11\xf6\x46\xaf\xd0\xca\x26\x03\x62\x80\x57\x50\x62\xcd\x05\x83\xcb\xd9\xd2\xba\xc1\xc1\xfa\xc3\x62\x0a\xdb\xc9\x6e\xb2\x9f\x7c\xef\xab\x67\xa3\xee\x34\xb2\x47\xd0\xda\xac\x1b\xb2\x47\x65\x6b\xe8\xc2\x75\x8c\x73\xab\x97\x7c\x8d\xb2\x73\x69\x0a\x90\x2d\x8a\xe1\x99\x31\x88\xa6\x13\x13\x77\x10\x8c\xe0\x30\x3c\x98\x4c\x61\x1c\xf9\xda\x75\xf6\xaa\xc3\xee\xa7\x8e\xf6\x94\x21\x7a\x2f\x68\xad\xa4\x90\x9d\xb6\xfa\x44\x51\x6b\x2e\x56\xa3\x6f\xd6\xa0\x2f\x46\xff\x48\xd2\x7d\xea\xdd\xba\x44\x65\x15\xce\x12\x14\x95\x3e\xa6\x52\x68\x2b\x9a\x83\xda\x6d\xed\x2d\xb5\x74\xa7\x82\xa4\xc4\xf4\x95\xd1\x86\x28\xd3\xb5\x23\xb0\xf6\x77\xbd\xe1\x14\xfa\xf4\xce\x15\xa2\x86\xae\x85\x93\xc5\x2d\xd0\x3d\x6d\x50\xf7\xa9\xf6\x1b\xd8\x03\x7f\x4b\xb8\x7b\x5b\xd9\x78\x71\x83\xc2\xd8\x54\xfb\xe9\x3b\xc2\x5d\xb6\x9f\x6e\xa6\x10\xd8\x44\x1f\x25\x46\xbb\x16\x72\xfa\x13\x8c\x0f\x12\x33\xf4\x19\x1b\xb4\xe2\xb1\xad\x39\xad\x1f\xe5\x07\x08\xa5\xb2\x13\xee\x48\xb1\xb7\x8f\xe1\x24\x90\xb6\x08\x83\x84\x33\xe0\xfd\x31\x43\x3b\x6d\xe4\x7a\xd8\xe4\x40\x83\xe1\x2d\x39\xeb\xdd\x5c\x3a\xd0\x8e\xed\xfb\x71\xfc\xf8\x62\x74\xe7\xdd\xe0\xf8\x71\x5f\xda\xd8\x8b\x41\x8f\xaf\xff\xdb\xa2\xbb\x17\x71\x85\xb0\xd5\x20\x15\xf0\x96\x0e\xcf\x48\xfb\x6a\xb4\x9f\x94\x18\x1b\xb6\x2b\xc9\xff\xdb\xea\x4a\x86\xb7\xd7\x17\x53\xa8\x8d\x69\xa7\xc7\xc7\xee\x20\xb6\xa7\xf7\xb4\x48\xe2\xe4\xd0\x4c\xf7\xcc\x5d\x11\x9b\x0b\xa7\x36\xdc\x15\xd1\x0b\xfb\x39\x85\xc0\x3f\xfc\x7b\xb1\xb8\xe1\x6b\x6e\xfa\xc5\x17\xf6\x73\x0a\x71\x16\x84\x51\x9e\x3f\x03\xa9\x91\xae\x5b\x3d\xb4\xc4\x8f\xcc\x8c\x22\x42\x93\xc7\x53\xde\xe6\xc0\x58\xff\x2c\x26\xe0\x2e\x42\x8e\xfd\x7d\x2a\x60\x14\x5f\xad\x50\x21\xeb\x21\x6d\x70\x67\x0e\x8d\xee\x61\x9d\xfa\x16\xd7\xaf\x6d\xac\x90\x30\x90\xa2\xd9\x5b\xba\x1c\xc0\x7e\xf8\xdb\xc0\x21\xa4\x1f\xae\xaf\x91\xb0\xe7\xee\x83\x64\xf0\x7e\x69\x3b\xf1\x34\xf6\x56\xca\x06\xd6\x64\x07\x0a\x8d\xe2\xfd\x49\xae\x51\x30\x20\xcf\x96\xc9\x8d\xa3\xf2\x9a\xec\xae\xfb\x75\x53\x08\x87\x9a\xfe\xda\xa5\xbb\x4e\x6d\x48\xe3\xfc\xee\x7b\x02\x10\x1b\x20\xed\x94\x72\xef\xd2\x27\x16\x35\xd1\x50\x22\xda\x87\xab\x41\x6a\x5c\x99\x0e\x0e\xec\x7e\xf6\xfc\x08\x87\x0c\x4e\xb9\x76\x68\x71\x1e\xb5\x5c\xbf\x40\x9b\x06\x26\x9f\xde\xba\xc1\xec\x5c\x44\xa4\xe5\x23\x00\xb3\x5b\x48\xd9\xcc\xa8\x95\x85\x33\x61\x3d\xb1\x29\x18\xd5\xa1\xe5\x1a\x11\x7b\x60\x58\x76\xab\xd5\x20\x49\x96\x02\x4e\x00\x56\x12\xec\x26\x23\x37\xdb\x53\xad\x6d\x95\xac\x5c\x7b\x1e\x4d\xac\xd8\xd9\xd1\x29\x54\xa4\xd1\x38\xfa\x57\x00\x00\x00\xff\xff\x54\xdb\x3a\xcf\xdd\x11\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xb9\x71\x5c\xd9\x96\xe3\x1b\xbf\x34\x20\x70\x28\x22\xa6\x00\x06\x00\xb5\xe4\xd7\x77\x00\x52\x8e\x1d\x2f\xb7\xcb\x34\x2f\xa6\x00\x9c\xfd\x3b\x1f\x0e\x72\x00\x27\x58\x91\xae\x31\xc0\x70\x8d\x8d\x6c\x57\x28\x0c\x18\xd4\x46\xa0\x01\xb2\x24\x5c\x68\x03\x8a\x8b\x7b\x2c\x77\x23\x8a\xc2\x28\x5e\x75\x4b\xbc\x40\xb3\x91\xea\x7e\x0a\xaa\xd3\x9a\x13\x51\xf3\xa6\x19\x39\x65\x5c\x20\x98\x1a\x81\x0d\x7a\x45\x7f\x52\x83\xa9\x89\x81\xe3\x07\x0d\xb0\x22\x5c\x18\xab\x7f\xb4\x3f\x32\x1d\x01\x1c\xc0\xb9\xa4\xa4\x71\x2e\x70\xb1\x04\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x89\xa0\xd1\xc0\x86\x9b\x1a\x50\xac\x61\x4d\x14\x27\x65\x83\x7a\x32\x82\xbd\xbc\x55\x09\xc0\xd9\x14\xa2\x28\x72\xdf\x68\x6a\x54\xd8\xad\x86\x08\x3e\xb0\x29\xe4\x51\xde\xef\x95\x52\x1a\x6d\x14\x69\xe7\x88\x4a\xf7\xb2\x1e\x8c\x0f\x79\x1b\x1f\x06\x61\x36\xf1\x27\xfe\x24\x38\x34\xb4\x3d\x8c\xf2\xd0\x0f\x0f\x79\x5b\xe9\xc3\xcb\xd5\xe2\x72\x5b\x6e\xee\xbb\xbb\x2f\x5f\x4e\xaa\xee\xc7\xa2\xdc\x9e\xce\xae\x70\x71\x71\x7c\x2e\x7f\xec\x76\x49\x92\xaf\x2f\xc5\xf2\xf3\x7a\xfe\xe9\xdb\xf9\x97\xfb\xf1\x9f\x28\x8d\xf6\x4a\x3f\x57\xe9\xe9\x45\xba\xba\xff\x7e\x8b\xdf\x6e\x3f\xde\x86\xdf\xe7\x5d\x90\xfe\xd1\xb2\x77\xd1\xfd\xef\x32\x58\x44\xab\x9a\xd4\xf3\xa3\xe4\x1a\x13\x11\xf4\x4a\xf7\xa9\x9a\xed\x33\xd5\x07\x60\xc3\x47\x61\xb8\xd9\x9d\x11\x6a\xa4\xda\x4d\x61\x3c\xfe\x65\xe7\x0a\x97\x5c\x9b\x27\x5b\x44\xd0\x5a\xaa\x2b\x6c\xa5\xe6\xbf\x48\xb5\x64\x67\x61\xf2\x8f\xb2\xe1\x4b\x62\xb8\x14\x6e\xcf\x15\xef\x13\xe1\xe2\x45\x28\x0d\x35\x1e\xc1\x63\xc4\xf4\x0e\x1e\xc0\x45\xb7\x42\xc5\x29\x7c\x38\x01\x59\x39\xf4\x3c\xc2\xc9\x4f\xc9\xbe\x90\x49\x30\x48\x1d\xed\xab\x05\x0d\xd7\xc6\x4a\x0a\xc9\xf0\x39\xd0\x5a\x25\xd7\xdc\x6d\x48\xa7\xfb\x91\x03\x7b\xf7\xfe\xb4\xfa\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x45\x40\x10\x9e\x44\x1f\xa5\xbc\x3d\xe7\x9c\x5e\x7e\xde\x2c\xea\xc5\xd1\x97\x74\xfb\x91\xce\xe5\x79\x95\x5e\x5d\x7e\xf9\xfd\xac\xdd\x54\x81\xca\x92\xcd\xf9\x36\xbc\xbb\x8a\xda\x63\x16\x8c\x5f\x52\x9f\xa7\x93\x30\xf0\x5f\x53\x7f\x79\xf7\x69\x96\xbf\x9b\xbf\x57\xeb\xd3\xbb\xa3\x62\xc3\xee\xe5\x0d\x9d\xcd\x56\xc7\x77\xef\xdb\x02\x77\xbb\xbb\xf8\xfa\x34\x5f\x9e\xa9\xa8\x5e\x5c\xfc\x31\x1e\x72\x74\x3a\xa0\x7d\x9f\x45\x9b\x62\x0f\xae\x86\x7e\x7e\xa5\x1f\xe2\x41\xf8\x9c\xd8\xf4\x00\xc3\xb6\x91\x3b\x64\x70\xbd\x22\xca\xc0\xf1\x00\x33\x0d\x95\x54\x2e\xa1\x4b\xbe\x46\xf1\x24\x95\xcf\xa1\x08\xaf\x62\xd1\xdf\x16\x3e\x0b\x8b\x38\xc9\x02\xcc\xa2\x3c\x0e\xd3\x22\x23\x69\x5a\x66\xa4\x28\x88\x5f\x30\x96\xd2\x2c\x62\x51\x92\xb2\x37\x50\xeb\x6f\x8b\x34\xf5\xa9\x1f\x15\x2c\x0a\x82\x38\x89\x48\xe5\xb3\x24\xa7\x49\x9a\xa6\x59\x18\xb1\x82\x86\x15\xc9\x58\x8a\xf4\x0d\x7c\xfb\xdb\xac\xca\x93\x98\x55\xa4\xc8\xfd\x20\x64\x59\x45\x92\x84\xe6\x7e\x54\x96\x24\x0c\x53\xbf\xa4\x0c\x31\x2e\x13\x64\x6f\x75\x82\xbf\x65\xa5\x9f\xe4\xc1\xac\x88\xc2\x3c\x4d\xe3\x3c\x49\xa2\x30\x9f\xb1\x93\xd2\x3f\x0d\x93\x20\xc8\xe3\x34\xf6\xab\x02\x93\x13\xd7\x33\x25\x2a\x41\x9a\x1a\xf9\xb2\x36\x03\xe8\x0e\x0e\x0e\x86\x0a\x7c\x94\x6b\x22\xe0\x6c\x76\x39\xfc\xf6\xe0\xd6\xb2\x1d\x17\x55\xa7\x08\xec\x64\x07\x4b\x4b\xd3\x02\x50\x29\xa9\x2c\x9c\x16\x35\xd7\xa0\xf0\x7b\x67\x2b\xc7\x35\x08\x69\x40\x77\x6d\x2b\x95\x41\x06\x25\x52\xd2\x69\xb4\x92\xca\x75\x8b\x3d\xa2\x3a\x21\x2c\xd5\x3a\x22\xd5\x86\x18\xdb\x32\x9d\x5d\x9a\xc0\x55\x27\xfa\x75\xcf\x1b\xd6\x7e\x23\x8a\xd6\x7c\x8d\x93\xf1\xdf\x06\xa7\x00\x36\xb6\xe3\x8c\x04\x26\xff\xee\x24\x08\x34\x8e\xc4\x5b\xa2\xb8\xd9\xf5\x86\x9c\x96\x7b\x17\x0f\x2e\xa7\xfd\xcf\xaf\xc3\x01\xcf\xa3\x35\xe1\xe2\xb7\x7e\xdb\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xda\xe1\x8f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x24\xbd\xd7\xfd\x9a\x46\xb5\x46\xaf\xb1\x49\x05\xcf\x5b\x91\xad\xd7\xda\xa6\x86\x30\xb1\x42\x5a\x90\x56\xd7\xd2\x0c\x8b\x6e\x6d\xc5\xc5\x93\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x05\xb3\x4d\x91\xac\xaa\xe7\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb5\xe7\xa5\x00\xad\x99\x0d\x89\xd0\x1a\x3d\xcd\x7f\x20\xc4\x7e\x91\x82\xe7\x7d\xd3\x52\xa8\x96\x7a\xb5\xd4\x46\x03\x69\x9a\x47\x6b\x5c\x18\x54\x15\xa1\x68\xd7\xbf\x3e\x2d\xf7\xf3\x64\xbe\x54\xf9\x23\x1b\x3e\x32\xdb\x7b\x02\x7b\x47\x8c\x84\x5b\x2c\xaf\xed\xba\xd1\xe0\x72\xa2\xa0\x52\x72\x05\x9d\x30\xaa\xd3\x16\x12\x52\xf1\x25\x17\x53\x98\x4c\xc6\xaf\xd6\xd3\x36\xf9\xb3\x5a\x7e\xf5\xbc\x4e\x68\x52\xa1\x87\xdb\x56\x6a\xfc\x0a\x55\x43\x96\xbf\x00\xf8\x3f\x63\xf6\xf0\x7f\x64\xf6\x27\xbd\xf4\x6f\x73\x7b\xe0\xc7\x93\x20\x89\x27\x41\x3e\x49\x9e\xdd\xee\x7b\xf2\x9d\xeb\x94\x13\xbc\xe9\xce\xee\x2e\xba\xe0\xdd\x76\xad\x77\x47\x8b\x6b\xb5\xd0\xc5\xda\x1c\xa5\xa5\xf9\x34\x13\xef\xcf\xe4\xf9\xb7\xf2\xfe\xc7\x31\x19\xbf\xa0\x3e\x99\x04\x79\x32\x09\xa3\xec\x55\x03\xc7\xef\xe8\x86\x2f\xbe\xc9\x8f\xb7\xef\xab\x23\x12\xe7\xe1\xcd\xdc\x10\xbc\xd9\x5e\x9c\x6f\x58\xfe\xa3\x14\x47\xc1\x75\xb6\xc1\xd9\xdd\xcd\xf6\xee\x6d\x76\x77\xa4\xf1\x2a\xb7\x87\xff\x07\x72\x7f\x83\xdb\xf3\xa4\x8c\xc2\x2a\x23\x51\x15\xfb\x71\x1e\x54\x41\x18\x45\xb1\x1f\x07\x69\xe6\xd3\x9c\x96\xe8\x67\x55\xc6\xb2\x82\xbe\xc9\xed\x49\x4c\x30\xca\xa2\xca\x2f\xd2\x8a\x54\x21\x2b\xd3\x32\x27\x71\x9a\x05\x19\xf5\xcb\x22\x47\x5a\x11\x3f\x4b\x18\x7b\x93\xdb\xe3\x38\xae\xd2\xb8\xc0\xc8\xcf\xe2\x38\xc4\x2c\xa5\xb4\xca\xa2\x2c\x4e\x53\x4c\xc2\x2a\x48\xfd\xa2\x2c\xf2\x30\xf5\xdf\xe6\x76\x3f\x0e\x32\x2c\xa3\xac\x88\x83\x20\x8d\xa3\x34\x8f\xfd\xe0\x24\x4d\xd3\x22\x8f\xe9\xe9\x49\x96\x16\xf1\xec\x88\x1e\x95\xc1\x78\x64\xc7\x61\x62\x08\x5c\x1b\xa9\xc8\x12\x47\xba\xff\xdb\x0f\xb9\x73\x62\x6a\x97\xe2\xc6\xce\x4a\x27\x47\x50\xf1\x06\x47\xd6\xa8\xa9\xa7\x70\x68\x56\xed\xe1\xcf\x61\xfb\x9f\x8c\x18\x32\x71\x27\x59\x69\xf5\x1e\x4b\x51\xf1\x65\xa7\x9c\x5b\x0f\x06\xa8\x5b\xbd\xfe\xef\xcd\xf4\x0a\x9e\x59\xfb\xf0\x40\x4d\x1b\x0b\x27\x87\x8a\xd9\xfc\x03\x10\xc1\x60\x1e\xce\xe1\xba\xe7\x15\xdb\xaa\x28\x6c\x2f\x8e\x6c\xb7\xbe\x97\xda\x08\xb2\xc2\x29\xf8\x6e\xc4\xf5\x47\x07\x30\x97\xca\x0c\x4a\xac\x82\x97\x05\xed\xa1\x29\xe4\x7e\x1e\x5a\xe3\xb6\x5f\x3d\x23\x1d\x35\x03\x7d\x1c\xb7\x1e\xb5\x61\xdb\x87\x79\xdd\x22\xe5\xd5\x0e\x4e\xb7\xc6\x31\x00\x7c\x98\x3f\xf2\xd5\x51\x16\x25\xc2\x3e\x18\x14\x5a\x56\x66\x40\x0c\xf0\x0a\x4a\xac\xb9\x60\x70\x31\x5b\x58\x35\x38\x48\x7f\x98\x4f\x61\x33\xd9\x4e\x76\x93\x1f\x7d\x12\xad\xd7\x9d\x46\xf6\xd0\x13\x36\xea\x86\xec\x50\xd9\x54\x3a\x77\x5d\x43\xbb\xd3\x0b\xbe\x42\xd9\xb9\x30\x05\xc8\x16\xc5\xf0\x8a\x19\x38\xd9\x71\x95\xbb\x67\x46\xb0\x5f\x1e\x44\xa6\x30\x8e\x7c\xed\x80\x73\xd9\x61\x87\xbf\x84\xeb\xac\x13\xbd\x13\xb4\x56\x52\xc8\x4e\x5b\xfa\xa3\xa8\x35\x17\xcb\xd1\x77\x2b\xd0\x27\xa3\x7f\x83\xe9\x3e\xf4\x6e\x55\xa2\xb2\x04\x6a\xfb\x1f\x95\x3e\xa4\x52\x68\xcb\xc9\x03\x99\x6e\xec\x10\x5c\xba\x4b\x47\x52\x62\xfa\xcc\x68\x43\x94\xe9\xda\x11\x58\xf9\xdb\x5e\x70\x0a\x7d\x78\x67\x0a\x51\x43\xd7\xc2\xf1\xfc\x06\xe8\x8e\x36\xa8\xfb\x50\x7b\x03\x76\x9e\xd8\x10\xee\x9e\x6e\xd6\x5f\x5c\xa3\x30\x36\xd4\x7e\xfb\x96\x70\x17\xed\xa7\xeb\x29\x04\x36\xd0\x07\x06\xd3\xae\x84\x9c\x3e\x0d\x7a\xb4\x67\xb0\xa1\xce\xd8\xa0\xe5\xa6\x4d\xcd\x69\xfd\xc0\x6e\x40\x28\x95\x9d\x70\x37\x96\x1d\x6e\x86\x8b\x46\xda\x24\x0c\x37\x04\x03\xde\xdf\x62\xb4\xd3\x46\xae\x06\x23\xfb\x6e\x18\x9e\xaa\xb3\x5e\xcd\x85\x03\xed\xd8\x3e\x4f\xc7\x0f\x0f\x52\xd7\x68\x83\xe2\x07\xbb\xb4\xb1\x73\x47\x8f\xaf\xbf\x6c\xd0\x8d\x5d\x5c\x21\x6c\x34\x48\x05\xbc\xa5\xc3\x2b\xd5\x3e\x4a\xed\x27\x25\xc6\xba\xed\x52\xf2\x57\x9b\x5d\xc9\xf0\xe6\xea\x7c\x0a\xb5\x31\xed\xf4\xf0\xd0\xdd\xf3\x76\x38\x98\x16\x49\x9c\xec\x8b\xe9\x5e\xd1\x4b\x62\x63\xe1\xd4\xba\xbb\x24\x7a\x6e\x3f\xa7\x10\xf8\xfb\x7f\xcf\x0e\x37\x7c\xc5\x4d\x7f\xf8\xdc\x7e\x4e\x21\xce\x82\x30\xca\xf3\x27\x20\x35\xd2\x55\xab\x87\x96\xf8\x19\x99\x51\x44\x68\xf2\x30\x44\xd8\x18\x18\xeb\x5f\xdd\x04\xdc\x9c\xe5\xba\xbf\x0f\x05\x8c\xe2\xcb\x25\x2a\x64\x3d\xa4\x0d\x6e\xcd\xbe\xd0\x3d\xac\x53\xdf\xe2\xfa\x35\xc3\x0a\x09\x03\x29\x9a\x9d\x6d\x97\x3d\xd8\xf7\xff\xf5\xb0\x77\xe9\xa7\xea\x2b\x24\xec\xa9\xfa\x20\x19\xb4\x5f\xd8\x4a\x3c\xf6\xbd\x95\xb2\x81\x15\xd9\x82\x42\xa3\x78\x3f\x28\x68\x14\x0c\xc8\x93\x63\x72\xed\x5a\x79\x45\xb6\x57\xfd\xb9\x29\x84\x43\x4e\x5f\x56\xe9\xa6\xb5\x35\x69\x9c\xde\x5d\xdf\x00\xc4\x3a\x48\x3b\xa5\xdc\xb3\xf7\x91\x44\x4d\x34\x94\x88\xf6\x5d\x6c\x90\x1a\x97\xa6\xbd\x02\x6b\xcf\x5e\x4f\xe1\x10\xc1\x09\xd7\x0e\x2d\x4e\xa3\x96\xab\x67\x68\xd3\xc0\xe4\xe3\xa1\x1e\xcc\xd6\x79\x44\x5a\x3e\x02\x30\xdb\xb9\x94\xcd\x8c\x5a\x5a\x38\x15\x56\x13\x9b\x82\x51\x1d\xda\x5e\x23\x62\x07\x0c\xcb\x6e\xb9\x1c\x28\xc9\xb6\x80\x23\x80\xa5\x04\x6b\x64\xe4\x76\xfb\x56\x6b\x5b\x25\x2b\x57\x9e\x07\x11\x4b\x76\x76\x75\x0a\x15\x69\x34\x8e\xfe\x15\x00\x00\xff\xff\x54\x43\x46\xfe\x3c\x12\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4573, mode: os.FileMode(420), modTime: time.Unix(1544105977, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4668, mode: os.FileMode(420), modTime: time.Unix(1544540466, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index fb7452851..601282035 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -1,29 +1,44 @@ package storage import ( + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/errors" +) - "github.com/centrifuge/go-centrifuge/config" +const ( + // BootstrappedLevelDB is a key mapped to levelDB at boot + BootstrappedLevelDB string = "BootstrappedLevelDB" + // BootstrappedConfigLevelDB is a key mapped to levelDB for configs at boot + BootstrappedConfigLevelDB string = "BootstrappedConfigLevelDB" ) -// BootstrappedLevelDB is a key mapped to levelDB in the boot -const BootstrappedLevelDB string = "BootstrappedLevelDB" +// Config holds configuration data for storage package +type Config interface { + GetStoragePath() string + GetConfigStoragePath() string + SetDefault(key string, value interface{}) +} // Bootstrapper implements bootstrapper.Bootstrapper. type Bootstrapper struct{} // Bootstrap initialises the levelDB. func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[config.BootstrappedConfig]; !ok { + if _, ok := context[bootstrap.BootstrappedConfig]; !ok { return errors.New("config not initialised") } - cfg := context[config.BootstrappedConfig].(config.Configuration) + cfg := context[bootstrap.BootstrappedConfig].(Config) + + configLevelDB, err := NewLevelDBStorage(cfg.GetConfigStoragePath()) + if err != nil { + return errors.New("failed to init config level db: %v", err) + } + context[BootstrappedConfigLevelDB] = configLevelDB levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return errors.New("failed to init level db: %v", err) } - context[BootstrappedLevelDB] = levelDB return nil } diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index c006d8608..575f61fa7 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -3,39 +3,49 @@ package storage import ( - "fmt" - - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/utils" "github.com/syndtr/goleveldb/leveldb" ) -const testStoragePath = "/tmp/centrifuge_data.leveldb_TESTING" - var db *leveldb.DB +var configdb *leveldb.DB func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { + cfg := context[bootstrap.BootstrappedConfig].(Config) + + crs := GetRandomTestStoragePath() + cfg.SetDefault("configStorage.path", crs) + log.Info("Set configStorage.path to:", cfg.GetConfigStoragePath()) + configdb, err = NewLevelDBStorage(cfg.GetConfigStoragePath()) + if err != nil { + return errors.New("failed to init config level db: %v", err) + } + context[BootstrappedConfigLevelDB] = configdb + rs := GetRandomTestStoragePath() - cfg := context[config.BootstrappedConfig].(config.Configuration) cfg.SetDefault("storage.Path", rs) log.Info("Set storage.Path to:", cfg.GetStoragePath()) db, err = NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return errors.New("failed to init level db: %v", err) } - log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) context[BootstrappedLevelDB] = db return nil } -func (*Bootstrapper) TestTearDown() error { - db.Close() - // os.RemoveAll(config.Config.GetStoragePath()) - return nil -} - -func GetRandomTestStoragePath() string { - return fmt.Sprintf("%s_%x", testStoragePath, utils.RandomByte32()) +func (b *Bootstrapper) TestTearDown() error { + var err error + dbs := []*leveldb.DB{db, configdb} + for _, idb := range dbs { + if ierr := idb.Close(); ierr != nil { + if err == nil { + err = errors.New("%s", ierr) + } else { + err = errors.AppendError(err, ierr) + } + } + } + return err } diff --git a/storage/util.go b/storage/util.go new file mode 100644 index 000000000..369cbc350 --- /dev/null +++ b/storage/util.go @@ -0,0 +1,14 @@ +package storage + +import ( + "fmt" + + "github.com/centrifuge/go-centrifuge/utils" +) + +const testStoragePath = "/tmp/centrifuge_data.leveldb_TESTING" + +// GetRandomTestStoragePath generates a random path for DB storage +func GetRandomTestStoragePath() string { + return fmt.Sprintf("%s_%x", testStoragePath, utils.RandomByte32()) +} diff --git a/testworld/park.go b/testworld/park.go index 11e5e4c7a..59d41e534 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -37,7 +37,7 @@ var hostConfig = []struct { {"Kenny", 8087, 38207}, } -const defaultP2PTimeout = "10s" +const defaultP2PTimeout = "20s" // hostTestSuite encapsulates test utilities on top of each host type hostTestSuite struct { @@ -244,7 +244,7 @@ func (h *host) init() error { if err != nil { return err } - h.config = h.bootstrappedCtx[config.BootstrappedConfig].(config.Configuration) + h.config = h.bootstrappedCtx[bootstrap.BootstrappedConfig].(config.Configuration) idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) idBytes, err := h.config.GetIdentityID() if err != nil { From d4df0c3673b68135468b0ce4eace4045c943fc6f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 13 Dec 2018 19:19:44 +0100 Subject: [PATCH 085/220] Skip timeout tests on CI to avoid resource problems (#570) --- build/scripts/tests/run_testworld.sh | 2 +- testworld/document_consensus_test.go | 2 ++ testworld/park.go | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index dbbdf04e2..0f4a4f54a 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -4,7 +4,7 @@ echo "Running Testworld" status=$? -output="go test -race -parallel 4 -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" +output="go test -race -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done if [ ${PIPESTATUS[0]} -ne 0 ]; then status=1 diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index efb6b42da..dc3175bce 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -64,6 +64,8 @@ func addExternalCollaborator(t *testing.T, documentType string) { } func TestHost_CollaboratorTimeOut(t *testing.T) { + // Run only locally since this creates resource issues for the entire test suite + t.SkipNow() t.Parallel() //currently can't be run in parallel (because of node kill) diff --git a/testworld/park.go b/testworld/park.go index 59d41e534..93e4d2557 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -37,7 +37,7 @@ var hostConfig = []struct { {"Kenny", 8087, 38207}, } -const defaultP2PTimeout = "20s" +const defaultP2PTimeout = "10s" // hostTestSuite encapsulates test utilities on top of each host type hostTestSuite struct { @@ -280,7 +280,7 @@ func (h *host) live(c context.Context) error { signal.Notify(controlC, os.Interrupt) select { case err := <-feedback: - log.Error(h.name+" encountered error ", err) + log.Info(h.name+" encountered error ", err) return err case sig := <-controlC: log.Info(h.name+" shutting down because of ", sig) From 5d91b9b9965339bcefd0017bcefd4eac7ddc174c Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Fri, 14 Dec 2018 10:01:23 +0100 Subject: [PATCH 086/220] go version 1.11.3 bug, lock to 1.11.2 (#571) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2a9791273..b454c7aac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.11.x + - 1.11.2 # Maybe this helps with building branches in a fork go_import_path: github.com/centrifuge/go-centrifuge From a601f01c0c03f34189795a9746e52a6a33be79b6 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 17 Dec 2018 13:11:10 +0100 Subject: [PATCH 087/220] move to 1.11.4 (#573) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b454c7aac..c44c398d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - 1.11.2 + - 1.11.4 # Maybe this helps with building branches in a fork go_import_path: github.com/centrifuge/go-centrifuge From dec9a9c1926730b49fa85e61e44ba2cf0a630290 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 17 Dec 2018 17:39:57 +0100 Subject: [PATCH 088/220] Consolidate DB Repository (#574) * encapsulated DB interface * lint * added typed errors * fix integration test * fix integration test * remove ID from storage.Repository --- cmd/common.go | 5 +- config/model.go | 15 -- config/repository.go | 250 +++++++----------------- config/repository_test.go | 40 ++-- documents/bootstrapper.go | 6 +- documents/bootstrapper_test.go | 8 +- documents/invoice/bootstrapper_test.go | 2 +- documents/invoice/service_test.go | 4 +- documents/purchaseorder/service_test.go | 4 +- documents/repository.go | 156 +++------------ documents/repository_test.go | 14 +- documents/test_bootstrapper.go | 5 +- node/bootstrapper.go | 3 +- p2p/handler_integration_test.go | 5 +- storage/bootstrapper.go | 12 +- storage/error.go | 23 +++ storage/leveldb.go | 168 ++++++++++++++++ storage/leveldb_test.go | 177 ++++++++++++++++- storage/repository.go | 29 +++ storage/test_bootstrapper.go | 4 +- 20 files changed, 540 insertions(+), 390 deletions(-) create mode 100644 storage/error.go create mode 100644 storage/repository.go diff --git a/cmd/common.go b/cmd/common.go index ca7d7314f..7152d9b5b 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/keytools" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/queue" - "github.com/syndtr/goleveldb/leveldb" ) var log = logging.Logger("centrifuge-cmd") @@ -104,8 +103,8 @@ func CreateConfig( return err } canc() - db := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) - dbCfg := ctx[storage.BootstrappedConfigLevelDB].(*leveldb.DB) + db := ctx[storage.BootstrappedDB].(storage.Repository) + dbCfg := ctx[storage.BootstrappedConfigDB].(storage.Repository) db.Close() dbCfg.Close() return nil diff --git a/config/model.go b/config/model.go index 528b84f9f..89a94e0bb 100644 --- a/config/model.go +++ b/config/model.go @@ -7,21 +7,6 @@ import ( "time" ) -// Model is an interface for both tenant and node config models -type Model interface { - // Get the ID of the document represented by this model - ID() ([]byte, error) - - //Returns the underlying type of the Model - Type() reflect.Type - - // JSON return the json representation of the model - JSON() ([]byte, error) - - // FromJSON initialize the model with a json - FromJSON(json []byte) error -} - // KeyPair represents a key pair config type KeyPair struct { Pub, Priv string diff --git a/config/repository.go b/config/repository.go index ca32baabc..6f31c026f 100644 --- a/config/repository.go +++ b/config/repository.go @@ -1,13 +1,7 @@ package config import ( - "encoding/json" - "fmt" - "reflect" - "sync" - - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/util" + "github.com/centrifuge/go-centrifuge/storage" ) const ( @@ -17,30 +11,36 @@ const ( // Repository defines the required methods for the config repository. type Repository interface { - // Get returns the tenant config Model associated with tenant ID - GetTenant(id []byte) (Model, error) + // RegisterTenant registers tenant config in DB + RegisterTenant(config *TenantConfig) + + // RegisterConfig registers node config in DB + RegisterConfig(config *NodeConfig) + + // GetTenant returns the tenant config Model associated with tenant ID + GetTenant(id []byte) (*TenantConfig, error) // GetConfig returns the node config model - GetConfig() (Model, error) + GetConfig() (*NodeConfig, error) // GetAllTenants returns a list of all tenant models in the config DB - GetAllTenants() ([]Model, error) + GetAllTenants() ([]*TenantConfig, error) // Create creates the tenant config model if not present in the DB. // should error out if the config exists. - CreateTenant(id []byte, model Model) error + CreateTenant(id []byte, tenant *TenantConfig) error // Create creates the node config model if not present in the DB. // should error out if the config exists. - CreateConfig(model Model) error + CreateConfig(nodeConfig *NodeConfig) error // Update strictly updates the tenant config model. // Will error out when the config model doesn't exist in the DB. - UpdateTenant(id []byte, model Model) error + UpdateTenant(id []byte, tenant *TenantConfig) error // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. - UpdateConfig(model Model) error + UpdateConfig(nodeConfig *NodeConfig) error // Delete deletes tenant config // Will not error out when config model doesn't exists in DB @@ -49,223 +49,107 @@ type Repository interface { // Delete deletes node config // Will not error out when config model doesn't exists in DB DeleteConfig() error - - // Register registers the model so that the DB can return the config without knowing the type - Register(model Model) } -// levelDBRepo implements Repository using LevelDB as storage layer -type levelDBRepo struct { - db *leveldb.DB - models map[string]reflect.Type - mu sync.RWMutex // to protect the models +type repo struct { + db storage.Repository } -// value is an internal representation of how levelDb stores the model. -type value struct { - Type string `json:"type"` - Data json.RawMessage `json:"data"` -} - -// NewLevelDBRepository returns levelDb implementation of Repository -func NewLevelDBRepository(db *leveldb.DB) Repository { - return &levelDBRepo{ - db: db, - models: make(map[string]reflect.Type), - } -} - -func (l *levelDBRepo) getTenantKey(id []byte) []byte { +func (r *repo) getTenantKey(id []byte) []byte { return append([]byte(tenantPrefix), id...) } -func (l *levelDBRepo) getConfigKey() []byte { +func (r *repo) getConfigKey() []byte { return []byte(configPrefix) } -// getModel returns a new instance of the type mt. -func (l *levelDBRepo) getModel(mt string) (Model, error) { - tp, ok := l.models[mt] - if !ok { - return nil, fmt.Errorf("type %s not registered", mt) - } - - return reflect.New(tp).Interface().(Model), nil +// NewDBRepository creates instance of Config Repository +func NewDBRepository(db storage.Repository) Repository { + return &repo{db: db} } -func (l *levelDBRepo) GetTenant(id []byte) (Model, error) { - key := l.getTenantKey(id) - return l.get(key) +// RegisterTenant registers tenant config in DB +func (r *repo) RegisterTenant(config *TenantConfig) { + r.db.Register(config) } -func (l *levelDBRepo) GetConfig() (Model, error) { - key := l.getConfigKey() - return l.get(key) +// RegisterConfig registers node config in DB +func (r *repo) RegisterConfig(config *NodeConfig) { + r.db.Register(config) } -func (l *levelDBRepo) parseModel(data []byte) (Model, error) { - v := new(value) - err := json.Unmarshal(data, v) +// GetTenant returns the tenant config Model associated with tenant ID +func (r *repo) GetTenant(id []byte) (*TenantConfig, error) { + key := r.getTenantKey(id) + model, err := r.db.Get(key) if err != nil { - return nil, fmt.Errorf("failed to unmarshal value: %v", err) + return nil, err } - - nm, err := l.getModel(v.Type) - if err != nil { - return nil, fmt.Errorf("failed to get model type: %v", err) - } - - err = nm.FromJSON([]byte(v.Data)) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal to model: %v", err) - } - - return nm, nil + return model.(*TenantConfig), nil } -// Get returns the model associated with ID -func (l *levelDBRepo) get(id []byte) (Model, error) { - l.mu.RLock() - defer l.mu.RUnlock() - data, err := l.db.Get(id, nil) +// GetConfig returns the node config model +func (r *repo) GetConfig() (*NodeConfig, error) { + key := r.getConfigKey() + model, err := r.db.Get(key) if err != nil { - return nil, fmt.Errorf("config missing: %v", err) + return nil, err } - - return l.parseModel(data) + return model.(*NodeConfig), nil } // GetAllTenants iterates over all tenant entries in DB and returns a list of Models // If an error occur reading a tenant, throws a warning and continue -func (l *levelDBRepo) GetAllTenants() ([]Model, error) { - var models []Model - l.mu.RLock() - defer l.mu.RUnlock() - iter := l.db.NewIterator(util.BytesPrefix([]byte(tenantPrefix)), nil) - for iter.Next() { - data := iter.Value() - model, err := l.parseModel(data) - if err != nil { - log.Warningf("Error parsing tenant: %v", err) - continue - } - models = append(models, model) - } - iter.Release() - return models, iter.Error() -} - -// save stores the model. -func (l *levelDBRepo) save(id []byte, model Model) error { - data, err := model.JSON() - if err != nil { - return fmt.Errorf("failed to marshall model: %v", err) - } - - tp := getTypeIndirect(model.Type()) - v := value{ - Type: tp.String(), - Data: json.RawMessage(data), - } - - data, err = json.Marshal(v) +func (r *repo) GetAllTenants() ([]*TenantConfig, error) { + var tenantConfigs []*TenantConfig + models, err := r.db.GetAllByPrefix(tenantPrefix) if err != nil { - return fmt.Errorf("failed to marshall value: %v", err) + return nil, err } - - err = l.db.Put(id, data, nil) - if err != nil { - return fmt.Errorf("failed to save model to DB: %v", err) + for _, tc := range models { + tenantConfigs = append(tenantConfigs, tc.(*TenantConfig)) } - - return nil -} - -// Exists returns true if the id exists. -func (l *levelDBRepo) exists(id []byte) bool { - res, err := l.db.Has(id, nil) - // TODO check this - if err != nil { - return false - } - - return res + return tenantConfigs, nil } // Create creates the tenant config model if not present in the DB. // should error out if the config exists. -func (l *levelDBRepo) CreateTenant(id []byte, model Model) error { - key := l.getTenantKey(id) - return l.create(key, model) +func (r *repo) CreateTenant(id []byte, tenant *TenantConfig) error { + key := r.getTenantKey(id) + return r.db.Create(key, tenant) } // Create creates the node config model if not present in the DB. // should error out if the config exists. -func (l *levelDBRepo) CreateConfig(model Model) error { - key := l.getConfigKey() - return l.create(key, model) -} - -// Create stores the model to the DB. -// Errors out if the model already exists. -func (l *levelDBRepo) create(id []byte, model Model) error { - if l.exists(id) { - return fmt.Errorf("model already exists") - } - - return l.save(id, model) +func (r *repo) CreateConfig(nodeConfig *NodeConfig) error { + key := r.getConfigKey() + return r.db.Create(key, nodeConfig) } // Update strictly updates the tenant config model. // Will error out when the config model doesn't exist in the DB. -func (l *levelDBRepo) UpdateTenant(id []byte, model Model) error { - key := l.getTenantKey(id) - return l.update(key, model) +func (r *repo) UpdateTenant(id []byte, tenant *TenantConfig) error { + key := r.getTenantKey(id) + return r.db.Update(key, tenant) } // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. -func (l *levelDBRepo) UpdateConfig(model Model) error { - key := l.getConfigKey() - return l.update(key, model) -} - -// Update overwrites the value at tenantID+id. -// Errors out if model doesn't exist -func (l *levelDBRepo) update(id []byte, model Model) error { - if !l.exists(id) { - return fmt.Errorf("model doesn't exist") - } - - return l.save(id, model) +func (r *repo) UpdateConfig(nodeConfig *NodeConfig) error { + key := r.getConfigKey() + return r.db.Update(key, nodeConfig) } // Delete deletes tenant config // Will not error out when config model doesn't exists in DB -func (l *levelDBRepo) DeleteTenant(id []byte) error { - key := l.getTenantKey(id) - return l.db.Delete(key, nil) -} - -func (l *levelDBRepo) DeleteConfig() error { - key := l.getConfigKey() - return l.db.Delete(key, nil) -} - -// Register registers the model for type less operations. -// Same type names will be overwritten. -func (l *levelDBRepo) Register(model Model) { - l.mu.Lock() - defer l.mu.Unlock() - tp := getTypeIndirect(model.Type()) - l.models[tp.String()] = tp +func (r *repo) DeleteTenant(id []byte) error { + key := r.getTenantKey(id) + return r.db.Delete(key) } -// getTypeIndirect returns the type of the model without pointers. -func getTypeIndirect(tp reflect.Type) reflect.Type { - if tp.Kind() == reflect.Ptr { - return getTypeIndirect(tp.Elem()) - } - - return tp +// Delete deletes node config +// Will not error out when config model doesn't exists in DB +func (r *repo) DeleteConfig() error { + key := r.getConfigKey() + return r.db.Delete(key) } diff --git a/config/repository_test.go b/config/repository_test.go index c5244ee83..f54ba00ee 100644 --- a/config/repository_test.go +++ b/config/repository_test.go @@ -7,15 +7,18 @@ import ( "reflect" "testing" - "github.com/syndtr/goleveldb/leveldb" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) -func getRandomStorage() (*leveldb.DB, error) { - return storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) +func getRandomStorage() (Repository, string, error) { + randomPath := storage.GetRandomTestStoragePath() + db, err := storage.NewLevelDBStorage(randomPath) + if err != nil { + return nil, "", err + } + return NewDBRepository(storage.NewLevelDBRepository(db)), randomPath, nil } func TestMain(m *testing.M) { @@ -24,14 +27,12 @@ func TestMain(m *testing.M) { } func TestNewLevelDBRepository(t *testing.T) { - testStorage, _ := getRandomStorage() - repo := NewLevelDBRepository(testStorage) + repo, _, _ := getRandomStorage() assert.NotNil(t, repo) } func TestUnregisteredModel(t *testing.T) { - testStorage, _ := getRandomStorage() - repo := NewLevelDBRepository(testStorage) + repo, _, _ := getRandomStorage() assert.NotNil(t, repo) id := utils.RandomSlice(32) newTenant := &TenantConfig{ @@ -45,22 +46,21 @@ func TestUnregisteredModel(t *testing.T) { _, err = repo.GetTenant(id) assert.NotNil(t, err) - repo.Register(&TenantConfig{}) + repo.RegisterTenant(&TenantConfig{}) _, err = repo.GetTenant(id) assert.Nil(t, err) } func TestTenantOperations(t *testing.T) { - testStorage, _ := getRandomStorage() - repo := NewLevelDBRepository(testStorage) + repo, _, _ := getRandomStorage() assert.NotNil(t, repo) id := utils.RandomSlice(32) newTenant := &TenantConfig{ IdentityID: id, EthereumDefaultAccountName: "main", } - repo.Register(&TenantConfig{}) + repo.RegisterTenant(&TenantConfig{}) err := repo.CreateTenant(id, newTenant) assert.Nil(t, err) @@ -68,9 +68,8 @@ func TestTenantOperations(t *testing.T) { err = repo.CreateTenant(id, newTenant) assert.NotNil(t, err) - readModel, err := repo.GetTenant(id) + readTenant, err := repo.GetTenant(id) assert.Nil(t, err) - readTenant := readModel.(*TenantConfig) assert.Equal(t, reflect.TypeOf(newTenant), readTenant.Type()) assert.Equal(t, newTenant.IdentityID, readTenant.IdentityID) @@ -92,13 +91,12 @@ func TestTenantOperations(t *testing.T) { } func TestConfigOperations(t *testing.T) { - testStorage, _ := getRandomStorage() - repo := NewLevelDBRepository(testStorage) + repo, _, _ := getRandomStorage() assert.NotNil(t, repo) newConfig := &NodeConfig{ NetworkID: 4, } - repo.Register(&NodeConfig{}) + repo.RegisterConfig(&NodeConfig{}) err := repo.CreateConfig(newConfig) assert.Nil(t, err) @@ -106,8 +104,7 @@ func TestConfigOperations(t *testing.T) { err = repo.CreateConfig(newConfig) assert.NotNil(t, err) - readModel, err := repo.GetConfig() - readDoc := readModel.(*NodeConfig) + readDoc, err := repo.GetConfig() assert.Nil(t, err) assert.Equal(t, reflect.TypeOf(newConfig), readDoc.Type()) assert.Equal(t, newConfig.NetworkID, readDoc.NetworkID) @@ -129,10 +126,9 @@ func TestConfigOperations(t *testing.T) { } func TestLevelDBRepo_GetAllTenants(t *testing.T) { - testStorage, _ := getRandomStorage() - repo := NewLevelDBRepository(testStorage) + repo, _, _ := getRandomStorage() assert.NotNil(t, repo) - repo.Register(&TenantConfig{}) + repo.RegisterTenant(&TenantConfig{}) ids := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32), utils.RandomSlice(32)} ten1 := &TenantConfig{ IdentityID: ids[0], diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index aa7f4208b..229c8d675 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -2,7 +2,6 @@ package documents import ( "github.com/centrifuge/go-centrifuge/storage" - "github.com/syndtr/goleveldb/leveldb" ) const ( @@ -18,11 +17,10 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { ctx[BootstrappedRegistry] = NewServiceRegistry() - ldb, ok := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) + ldb, ok := ctx[storage.BootstrappedDB].(storage.Repository) if !ok { return ErrDocumentBootstrap } - repo := NewLevelDBRepository(ldb) - ctx[BootstrappedDocumentRepository] = repo + ctx[BootstrappedDocumentRepository] = NewDBRepository(ldb) return nil } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index dea6e5383..05ad7ddfd 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -7,13 +7,15 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/stretchr/testify/assert" - "github.com/syndtr/goleveldb/leveldb" ) func TestBootstrapper_Bootstrap(t *testing.T) { ctx := make(map[string]interface{}) - ctx[storage.BootstrappedLevelDB] = &leveldb.DB{} - err := Bootstrapper{}.Bootstrap(ctx) + randomPath := storage.GetRandomTestStoragePath() + db, err := storage.NewLevelDBStorage(randomPath) + assert.Nil(t, err) + ctx[storage.BootstrappedDB] = storage.NewLevelDBRepository(db) + err = Bootstrapper{}.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRegistry]) _, ok := ctx[BootstrappedRegistry].(*ServiceRegistry) diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index e299b8ead..0719bb9c5 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -13,7 +13,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { func TestBootstrapper_registerInvoiceService(t *testing.T) { //context := map[string]interface{}{} - //context[bootstrap.BootstrappedLevelDb] = true + //context[bootstrap.BootstrappedDb] = true //err := (&Bootstrapper{}).Bootstrap(context) //assert.Nil(t, err, "Should throw because context is passed") // diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 705f4b1ed..ed426dcb7 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -681,7 +681,7 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) assert.Nil(t, inv) assert.Error(t, err) - assert.Contains(t, err.Error(), "document repository found an already existing model when saving") + assert.Contains(t, err.Error(), "db repository could not create the given model, key already exists") // success inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) @@ -701,7 +701,7 @@ func testRepo() documents.Repository { if err != nil { panic(err) } - testRepoGlobal = documents.NewLevelDBRepository(ldb) + testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) testRepoGlobal.Register(&Invoice{}) } return testRepoGlobal diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index f561bcc88..cf2ed76b4 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -730,7 +730,7 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) assert.Nil(t, po) assert.Error(t, err) - assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelAllReadyExists) + assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists) // success po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) @@ -750,7 +750,7 @@ func testRepo() documents.Repository { if err != nil { panic(err) } - testRepoGlobal = documents.NewLevelDBRepository(ldb) + testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) testRepoGlobal.Register(&PurchaseOrder{}) } return testRepoGlobal diff --git a/documents/repository.go b/documents/repository.go index 5e7a3d254..fc156cc01 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -1,12 +1,7 @@ package documents import ( - "encoding/json" - "reflect" - "sync" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/syndtr/goleveldb/leveldb" + "github.com/centrifuge/go-centrifuge/storage" ) // Repository defines the required methods for a document repository. @@ -30,144 +25,51 @@ type Repository interface { Register(model Model) } -// levelDBRepo implements Repository using LevelDB as storage layer -type levelDBRepo struct { - db *leveldb.DB - models map[string]reflect.Type - mu sync.RWMutex // to protect the models -} - -// value is an internal representation of how levelDb stores the model. -type value struct { - Type string `json:"type"` - Data json.RawMessage `json:"data"` +// NewDBRepository creates an instance of the documents Repository +func NewDBRepository(db storage.Repository) Repository { + return &repo{db: db} } -// NewLevelDBRepository returns levelDb implementation of Repository -func NewLevelDBRepository(db *leveldb.DB) Repository { - return &levelDBRepo{ - db: db, - models: make(map[string]reflect.Type), - } +type repo struct { + db storage.Repository } // getKey returns tenantID+id -func getKey(tenantID, id []byte) []byte { +func (r *repo) getKey(tenantID, id []byte) []byte { return append(tenantID, id...) } -// Exists returns true if the id, owned by tenantID, exists. -func (l *levelDBRepo) Exists(tenantID, id []byte) bool { - key := getKey(tenantID, id) - res, err := l.db.Has(key, nil) - // TODO check this - if err != nil { - return false - } - - return res +// Register registers the model so that the DB can return the document without knowing the type +func (r *repo) Register(model Model) { + r.db.Register(model) } -// getModel returns a new instance of the type mt. -func (l *levelDBRepo) getModel(mt string) (Model, error) { - tp, ok := l.models[mt] - if !ok { - return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotRegistered, errors.New("type %s not registered", mt)) - } - - return reflect.New(tp).Interface().(Model), nil +// Exists checks if the id, owned by tenantID, exists in DB +func (r *repo) Exists(tenantID, id []byte) bool { + key := r.getKey(tenantID, id) + return r.db.Exists(key) } -// Get returns the model associated with ID, owned by tenantID. -func (l *levelDBRepo) Get(tenantID, id []byte) (Model, error) { - key := getKey(tenantID, id) - data, err := l.db.Get(key, nil) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositoryModelNotFound, errors.New("document missing: %v", err)) - } - - v := new(value) - err = json.Unmarshal(data, v) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to unmarshal value: %v", err)) - } - - l.mu.RLock() - defer l.mu.RUnlock() - nm, err := l.getModel(v.Type) +// Get returns the Model associated with ID, owned by tenantID +func (r *repo) Get(tenantID, id []byte) (Model, error) { + key := r.getKey(tenantID, id) + model, err := r.db.Get(key) if err != nil { return nil, err } - - err = nm.FromJSON([]byte(v.Data)) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to unmarshal to model: %v", err)) - } - - return nm, nil -} - -// getTypeIndirect returns the type of the model without pointers. -func getTypeIndirect(tp reflect.Type) reflect.Type { - if tp.Kind() == reflect.Ptr { - return getTypeIndirect(tp.Elem()) - } - - return tp + return model.(Model), nil } -// save stores the model. -func (l *levelDBRepo) save(tenantID, id []byte, model Model) error { - data, err := model.JSON() - if err != nil { - return errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to marshall model: %v", err)) - } - - tp := getTypeIndirect(model.Type()) - v := value{ - Type: tp.String(), - Data: json.RawMessage(data), - } - - data, err = json.Marshal(v) - if err != nil { - return errors.NewTypedError(ErrDocumentRepositorySerialisation, errors.New("failed to marshall value: %v", err)) - } - - key := getKey(tenantID, id) - err = l.db.Put(key, data, nil) - if err != nil { - return errors.NewTypedError(ErrDocumentRepositoryModelSave, errors.New("%v", err)) - } - - return nil -} - -// Create stores the model to the DB. -// Errors out if the model already exists. -func (l *levelDBRepo) Create(tenantID, id []byte, model Model) error { - if l.Exists(tenantID, id) { - return ErrDocumentRepositoryModelAllReadyExists - } - - return l.save(tenantID, id, model) -} - -// Update overwrites the value at tenantID+id. -// Errors out if model doesn't exist -func (l *levelDBRepo) Update(tenantID, id []byte, model Model) error { - if !l.Exists(tenantID, id) { - return ErrDocumentRepositoryModelDoesntExist - } - - return l.save(tenantID, id, model) +// Create creates the model if not present in the DB. +// should error out if the document exists. +func (r *repo) Create(tenantID, id []byte, model Model) error { + key := r.getKey(tenantID, id) + return r.db.Create(key, model) } -// Register registers the model for type less operations. -// Same type names will be overwritten. -func (l *levelDBRepo) Register(model Model) { - l.mu.Lock() - defer l.mu.Unlock() - tp := getTypeIndirect(model.Type()) - l.models[tp.String()] = tp +// Update strictly updates the model. +// Will error out when the model doesn't exist in the DB. +func (r *repo) Update(tenantID, id []byte, model Model) error { + key := r.getKey(tenantID, id) + return r.db.Update(key, model) } diff --git a/documents/repository_test.go b/documents/repository_test.go index b6da2d616..ee07ae17a 100644 --- a/documents/repository_test.go +++ b/documents/repository_test.go @@ -10,12 +10,11 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" - "github.com/syndtr/goleveldb/leveldb" ) func getRepository(ctx map[string]interface{}) Repository { - db := ctx[storage.BootstrappedLevelDB].(*leveldb.DB) - return NewLevelDBRepository(db) + db := ctx[storage.BootstrappedDB].(storage.Repository) + return NewDBRepository(db) } type doc struct { @@ -67,15 +66,6 @@ func TestLevelDBRepo_Update_Exists(t *testing.T) { assert.True(t, repo.Exists(tenantID, id), "doc must be [resent") } -func TestLevelDBRepo_Register(t *testing.T) { - repo := getRepository(ctx) - assert.Len(t, repo.(*levelDBRepo).models, 0, "should be empty") - d := &doc{SomeString: "Hello, Repo!"} - repo.Register(d) - assert.Len(t, repo.(*levelDBRepo).models, 1, "should be not empty") - assert.Contains(t, repo.(*levelDBRepo).models, "documents.doc") -} - func TestLevelDBRepo_Get_Create_Update(t *testing.T) { repo := getRepository(ctx) diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index d0c4a71aa..52eaf998f 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -6,17 +6,16 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" - "github.com/syndtr/goleveldb/leveldb" ) // initialized ONLY for tests var testLevelDB Repository func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - if _, ok := context[storage.BootstrappedLevelDB]; !ok { + if _, ok := context[storage.BootstrappedDB]; !ok { return errors.New("initializing LevelDB repository failed") } - testLevelDB = NewLevelDBRepository(context[storage.BootstrappedLevelDB].(*leveldb.DB)) + testLevelDB = NewDBRepository(context[storage.BootstrappedDB].(storage.Repository)) return b.Bootstrap(context) } diff --git a/node/bootstrapper.go b/node/bootstrapper.go index 719890db7..dd3098df5 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" - "github.com/syndtr/goleveldb/leveldb" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -46,7 +45,7 @@ func (*Bootstrapper) Bootstrap(c map[string]interface{}) error { func cleanUp(c map[string]interface{}) { // close the node db - db := c[storage.BootstrappedLevelDB].(*leveldb.DB) + db := c[storage.BootstrappedDB].(storage.Repository) db.Close() } diff --git a/p2p/handler_integration_test.go b/p2p/handler_integration_test.go index 6f6c2bc1f..0853da204 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/handler_integration_test.go @@ -20,6 +20,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" @@ -75,7 +76,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { req = getSignatureRequest(doc) resp, err = handler.RequestDocumentSignature(context.Background(), req) assert.NotNil(t, err, "must not be nil") - assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelAllReadyExists.Error()) + assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists.Error()) } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { @@ -148,7 +149,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { anchorReq := getAnchoredRequest(doc) anchorResp, err := handler.SendAnchoredDocument(context.Background(), anchorReq) assert.Error(t, err) - assert.Contains(t, err.Error(), documents.ErrDocumentRepositoryModelDoesntExist.Error()) + assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) assert.Nil(t, anchorResp) } diff --git a/storage/bootstrapper.go b/storage/bootstrapper.go index 601282035..082dbb300 100644 --- a/storage/bootstrapper.go +++ b/storage/bootstrapper.go @@ -6,10 +6,10 @@ import ( ) const ( - // BootstrappedLevelDB is a key mapped to levelDB at boot - BootstrappedLevelDB string = "BootstrappedLevelDB" - // BootstrappedConfigLevelDB is a key mapped to levelDB for configs at boot - BootstrappedConfigLevelDB string = "BootstrappedConfigLevelDB" + // BootstrappedDB is a key mapped to DB at boot + BootstrappedDB string = "BootstrappedDB" + // BootstrappedConfigDB is a key mapped to DB for configs at boot + BootstrappedConfigDB string = "BootstrappedConfigDB" ) // Config holds configuration data for storage package @@ -33,12 +33,12 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return errors.New("failed to init config level db: %v", err) } - context[BootstrappedConfigLevelDB] = configLevelDB + context[BootstrappedConfigDB] = NewLevelDBRepository(configLevelDB) levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return errors.New("failed to init level db: %v", err) } - context[BootstrappedLevelDB] = levelDB + context[BootstrappedDB] = NewLevelDBRepository(levelDB) return nil } diff --git a/storage/error.go b/storage/error.go new file mode 100644 index 000000000..2ab397b08 --- /dev/null +++ b/storage/error.go @@ -0,0 +1,23 @@ +package storage + +import "github.com/centrifuge/go-centrifuge/errors" + +const ( + // ErrModelRepositorySerialisation must be used when document repository encounters a marshalling error + ErrModelRepositorySerialisation = errors.Error("model repository encountered a marshalling error") + + // ErrModelRepositoryNotFound must be used when model is not found in db + ErrModelRepositoryNotFound = errors.Error("model not found in db") + + // ErrRepositoryModelSave must be used when db repository can not save the given model + ErrRepositoryModelSave = errors.Error("db repository could not save the given model") + + // ErrRepositoryModelUpdateKeyNotFound must be used when db repository can not update the given model + ErrRepositoryModelUpdateKeyNotFound = errors.Error("db repository could not update the given model, key not found") + + // ErrRepositoryModelCreateKeyExists must be used when db repository can not create the given model + ErrRepositoryModelCreateKeyExists = errors.Error("db repository could not create the given model, key already exists") + + // ErrModelTypeNotRegistered must be used when model hasn't been registered in db + ErrModelTypeNotRegistered = errors.Error("type not registered") +) diff --git a/storage/leveldb.go b/storage/leveldb.go index 05b100406..e54b80c1f 100644 --- a/storage/leveldb.go +++ b/storage/leveldb.go @@ -1,8 +1,14 @@ package storage import ( + "encoding/json" + "reflect" + "sync" + + "github.com/centrifuge/go-centrifuge/errors" logging "github.com/ipfs/go-log" "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" ) var log = logging.Logger("storage") @@ -15,3 +21,165 @@ func NewLevelDBStorage(path string) (*leveldb.DB, error) { } return i, nil } + +// levelDBRepo implements Repository using LevelDB as storage layer +type levelDBRepo struct { + db *leveldb.DB + models map[string]reflect.Type + mu sync.RWMutex // to protect the models +} + +// value is an internal representation of how levelDb stores the model. +type value struct { + Type string `json:"type"` + Data json.RawMessage `json:"data"` +} + +// NewLevelDBRepository returns levelDb implementation of Repository +func NewLevelDBRepository(db *leveldb.DB) Repository { + return &levelDBRepo{ + db: db, + models: make(map[string]reflect.Type), + } +} + +// Register registers the model so that the DB can return the model without knowing the type +func (l *levelDBRepo) Register(model Model) { + l.mu.Lock() + defer l.mu.Unlock() + tp := getTypeIndirect(model.Type()) + l.models[tp.String()] = tp +} + +// Exists checks whether the key exists in db +func (l *levelDBRepo) Exists(key []byte) bool { + res, err := l.db.Has(key, nil) + if err != nil { + return false + } + return res +} + +// getModel returns a new instance of the type mt. +func (l *levelDBRepo) getModel(mt string) (Model, error) { + tp, ok := l.models[mt] + if !ok { + return nil, errors.NewTypedError(ErrModelTypeNotRegistered, errors.New("%s", mt)) + } + + return reflect.New(tp).Interface().(Model), nil +} + +func (l *levelDBRepo) parseModel(data []byte) (Model, error) { + v := new(value) + err := json.Unmarshal(data, v) + if err != nil { + return nil, errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to unmarshal to value: %v", err)) + } + + nm, err := l.getModel(v.Type) + if err != nil { + return nil, err + } + + err = nm.FromJSON([]byte(v.Data)) + if err != nil { + return nil, errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to unmarshal to model: %v", err)) + } + + return nm, nil +} + +// Get retrieves model by key, otherwise returns error +func (l *levelDBRepo) Get(key []byte) (Model, error) { + l.mu.RLock() + defer l.mu.RUnlock() + data, err := l.db.Get(key, nil) + if err != nil { + return nil, errors.NewTypedError(ErrModelRepositoryNotFound, err) + } + + return l.parseModel(data) +} + +// GetAllByPrefix returns all models which keys match the provided prefix +// If an error is found parsing one of the matched models, logs warning and continues +func (l *levelDBRepo) GetAllByPrefix(prefix string) ([]Model, error) { + var models []Model + l.mu.RLock() + defer l.mu.RUnlock() + iter := l.db.NewIterator(util.BytesPrefix([]byte(prefix)), nil) + for iter.Next() { + data := iter.Value() + model, err := l.parseModel(data) + if err != nil { + log.Warningf("Error parsing model: %v", err) + continue + } + models = append(models, model) + } + iter.Release() + return models, iter.Error() +} + +func (l *levelDBRepo) save(key []byte, model Model) error { + data, err := model.JSON() + if err != nil { + return errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to marshall model: %v", err)) + } + + tp := getTypeIndirect(model.Type()) + v := value{ + Type: tp.String(), + Data: json.RawMessage(data), + } + + data, err = json.Marshal(v) + if err != nil { + return errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to marshall value: %v", err)) + } + + err = l.db.Put(key, data, nil) + if err != nil { + return errors.NewTypedError(ErrRepositoryModelSave, errors.New("%v", err)) + } + + return nil +} + +// Create creates a model indexed by the key provided +// errors out if key already exists +func (l *levelDBRepo) Create(key []byte, model Model) error { + if l.Exists(key) { + return ErrRepositoryModelCreateKeyExists + } + return l.save(key, model) +} + +// Update updates a model indexed by the key provided +// errors out if key doesn't exists +func (l *levelDBRepo) Update(key []byte, model Model) error { + if !l.Exists(key) { + return ErrRepositoryModelUpdateKeyNotFound + } + return l.save(key, model) +} + +// Delete deletes a model by the key provided +func (l *levelDBRepo) Delete(key []byte) error { + return l.db.Delete(key, nil) +} + +// Close closes the database +func (l *levelDBRepo) Close() error { + return l.db.Close() +} + +// getTypeIndirect returns the type of the model without pointers. +func getTypeIndirect(tp reflect.Type) reflect.Type { + if tp.Kind() == reflect.Ptr { + return getTypeIndirect(tp.Elem()) + } + + return tp +} diff --git a/storage/leveldb_test.go b/storage/leveldb_test.go index 66831495e..22a0a7786 100644 --- a/storage/leveldb_test.go +++ b/storage/leveldb_test.go @@ -3,14 +3,189 @@ package storage import ( + "encoding/json" + "reflect" "testing" + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/centrifuge/go-centrifuge/utils" + "github.com/stretchr/testify/assert" ) -func TestNewLevelDBStorage(t *testing.T) { +type doc struct { + Id []byte `json:"id"` + SomeString string `json:"some_string"` +} + +func (m *doc) ID() ([]byte, error) { + return m.Id, nil +} + +func (m *doc) JSON() ([]byte, error) { + return json.Marshal(m) +} + +func (m *doc) FromJSON(data []byte) error { + return json.Unmarshal(data, m) +} + +func (m *doc) Type() reflect.Type { + return reflect.TypeOf(m) +} + +func getRandomRepository() (Repository, string, error) { + randomPath := GetRandomTestStoragePath() + db, err := NewLevelDBStorage(randomPath) + if err != nil { + return nil, "", err + } + return NewLevelDBRepository(db), randomPath, nil +} + +func TestNewLevelDBRepository(t *testing.T) { path := GetRandomTestStoragePath() db, err := NewLevelDBStorage(path) assert.Nil(t, err) assert.NotNil(t, db) + + repo := NewLevelDBRepository(db) + assert.NotNil(t, repo) +} + +func TestLevelDBRepo_Register(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + assert.Len(t, repo.(*levelDBRepo).models, 0, "should be empty") + d := &doc{SomeString: "Hello, Repo!"} + repo.Register(d) + assert.Len(t, repo.(*levelDBRepo).models, 1, "should be not empty") + assert.Contains(t, repo.(*levelDBRepo).models, "storage.doc") +} + +func TestLevelDBRepo_Exists(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + id := utils.RandomSlice(32) + + // Key doesnt exist + assert.False(t, repo.Exists(id)) + + d := &doc{SomeString: "Hello, Repo!"} + err = repo.Create(id, d) + assert.Nil(t, err) + + // Key exists + assert.True(t, repo.Exists(id)) +} + +func TestLevelDBRepo_Get(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + id := utils.RandomSlice(32) + + // Key doesnt exist + _, err = repo.Get(id) + assert.True(t, errors.IsOfType(ErrModelRepositoryNotFound, err)) + + d := &doc{SomeString: "Hello, Repo!"} + err = repo.Create(id, d) + assert.Nil(t, err) + + // Model not registered + _, err = repo.Get(id) + assert.True(t, errors.IsOfType(ErrModelTypeNotRegistered, err)) + + // Success + repo.Register(&doc{}) + m, err := repo.Get(id) + assert.Nil(t, err) + assert.Equal(t, d.SomeString, m.(*doc).SomeString) +} + +func TestLevelDBRepo_GetAllByPrefix(t *testing.T) { + prefix := "prefix-" + repo, _, err := getRandomRepository() + assert.Nil(t, err) + repo.Register(&doc{}) + + // No match + models, err := repo.GetAllByPrefix(prefix) + assert.Nil(t, err) + assert.Equal(t, 0, len(models)) + + id1 := append([]byte(prefix), utils.RandomSlice(32)...) + id2 := append([]byte(prefix), utils.RandomSlice(32)...) + d1 := &doc{SomeString: "Hello, Repo1!"} + d2 := &doc{SomeString: "Hello, Repo2!"} + err = repo.Create(id1, d1) + assert.Nil(t, err) + err = repo.Create(id2, d2) + assert.Nil(t, err) + + models, err = repo.GetAllByPrefix(prefix) + assert.Nil(t, err) + assert.Equal(t, 2, len(models)) +} + +func TestLevelDBRepo_Create(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + id := utils.RandomSlice(32) + + d := &doc{SomeString: "Hello, Repo!"} + err = repo.Create(id, d) + assert.Nil(t, err) + + //Already exists + err = repo.Create(id, d) + assert.True(t, errors.IsOfType(ErrRepositoryModelCreateKeyExists, err)) +} + +func TestLevelDBRepo_Update(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + id := utils.RandomSlice(32) + + d := &doc{SomeString: "Hello, Repo!"} + + // Doesn't exist + err = repo.Update(id, d) + assert.True(t, errors.IsOfType(ErrRepositoryModelUpdateKeyNotFound, err)) + + err = repo.Create(id, d) + assert.Nil(t, err) + + // Exists + err = repo.Update(id, d) + assert.Nil(t, err) +} + +func TestLevelDBRepo_Delete(t *testing.T) { + repo, _, err := getRandomRepository() + assert.Nil(t, err) + id := utils.RandomSlice(32) + + d := &doc{SomeString: "Hello, Repo!"} + repo.Register(d) + + //Doesnt fail on key that doesnt exist + err = repo.Delete(id) + assert.Nil(t, err) + + err = repo.Create(id, d) + assert.Nil(t, err) + + // Entry exists + m, err := repo.Get(id) + assert.Nil(t, err) + assert.Equal(t, d.SomeString, m.(*doc).SomeString) + + err = repo.Delete(id) + assert.Nil(t, err) + + // Entry doesnt exist + _, err = repo.Get(id) + assert.True(t, errors.IsOfType(ErrModelRepositoryNotFound, err)) } diff --git a/storage/repository.go b/storage/repository.go new file mode 100644 index 000000000..159bef7c9 --- /dev/null +++ b/storage/repository.go @@ -0,0 +1,29 @@ +package storage + +import ( + "reflect" +) + +// Model is an interface to abstract away storage model specificness +type Model interface { + //Returns the underlying type of the Model + Type() reflect.Type + + // JSON return the json representation of the model + JSON() ([]byte, error) + + // FromJSON initialize the model with a json + FromJSON(json []byte) error +} + +// Repository defines the required methods for standard storage repository. +type Repository interface { + Register(model Model) + Exists(key []byte) bool + Get(key []byte) (Model, error) + GetAllByPrefix(prefix string) ([]Model, error) + Create(key []byte, model Model) error + Update(key []byte, model Model) error + Delete(key []byte) error + Close() error +} diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index 575f61fa7..db7efd984 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -21,7 +21,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { if err != nil { return errors.New("failed to init config level db: %v", err) } - context[BootstrappedConfigLevelDB] = configdb + context[BootstrappedConfigDB] = NewLevelDBRepository(configdb) rs := GetRandomTestStoragePath() cfg.SetDefault("storage.Path", rs) @@ -31,7 +31,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { return errors.New("failed to init level db: %v", err) } log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) - context[BootstrappedLevelDB] = db + context[BootstrappedDB] = NewLevelDBRepository(db) return nil } From 6496f25f1c3960fad23d6688ecac05f6e6660711 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 17 Dec 2018 19:28:11 +0100 Subject: [PATCH 089/220] ISSUE and PR templates proposal (#551) * ISSUE and PR templates proposal * Updates * Update ISSUE_TEMPLATE.md * Update PULL_REQUEST_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 22 ++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 2 ++ 2 files changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..c2016831c --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,22 @@ + + + +#### Testing + + +#### Acceptance Criteria + + +#### Dependencies and affected external components + + +### Bug reports + +#### Expected behaviour + + +#### Actual behaviour + + +#### Steps to reproduce the behaviour + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..ebc47f4d2 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ + +Issue Link: From 8e42d53b2cbe8fd5cdbd7f3672a73b2fdd507bcc Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 17 Dec 2018 19:31:21 +0100 Subject: [PATCH 090/220] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ebc47f4d2..90f36babf 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,2 +1,2 @@ - + Issue Link: From 66357d3f11afabc6d9f402457ea597322e7faf4f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 17 Dec 2018 19:32:49 +0100 Subject: [PATCH 091/220] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c2016831c..17296b9fe 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,4 @@ - + #### Testing From 758cfe5657c5c7a703f0ff1e3832c5aa1adced3e Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 18 Dec 2018 13:27:33 +0100 Subject: [PATCH 092/220] Cleanup testworld generated files (#578) * Cleanup testworld generated files * Force delete --- build/scripts/tests/run_testworld.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index 0f4a4f54a..8a5c99cfb 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -2,6 +2,10 @@ echo "Running Testworld" +cleanup="ls testworld/peerconfigs/* | grep testworld | grep -v README.md | tr -d : | xargs rm -rf" + +eval "$cleanup" + status=$? output="go test -race -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" @@ -15,5 +19,6 @@ if [ -f profile.out ]; then rm profile.out fi +eval "$cleanup" exit $status From cf3da8f33ee7b7d6a33a44779eb1939d4cfb6308 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Tue, 18 Dec 2018 16:35:28 +0100 Subject: [PATCH 093/220] HTTP header for tenantID (#575) Fixes #488 1. Add interceptor that require header 'authorization' which holds tenantID 2. Add basic version if HTTPError and http Error response interceptor since we ned it for point 1 --- api/server.go | 92 ++++++++++++++++++++++++++++++++++++++++--- api/server_test.go | 48 +++++++++++++++++++++- errors/errors.go | 35 ++++++++++++++++ errors/errors_test.go | 25 ++++++++++++ testworld/nft_test.go | 2 +- utils/strings.go | 11 ++++++ utils/strings_test.go | 39 ++++++++++++++++++ 7 files changed, 243 insertions(+), 9 deletions(-) diff --git a/api/server.go b/api/server.go index b0e77cc65..23f9aef88 100644 --- a/api/server.go +++ b/api/server.go @@ -3,6 +3,7 @@ package api import ( "crypto/tls" "crypto/x509" + "io" "net" "net/http" _ "net/http/pprof" // we need this side effect that loads the pprof endpoints to defaultServerMux @@ -11,16 +12,27 @@ import ( "time" "github.com/centrifuge/go-centrifuge/errors" - - "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/utils" "github.com/grpc-ecosystem/grpc-gateway/runtime" logging "github.com/ipfs/go-log" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" ) -var log = logging.Logger("api-server") +// ErrNoAuthHeader used for requests when header is not passed. +const ErrNoAuthHeader = errors.Error("'authorization' header missing") + +var ( + log = logging.Logger("api-server") + + // noAuthPaths holds the paths that doesn't require header to be passed. + noAuthPaths = [...]string{"/health.HealthCheckService/Ping"} + + // TenantKey represents the key used to fetch the tenant id from context + TenantKey struct{} +) // Config defines methods required for the package api type Config interface { @@ -59,10 +71,15 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha InsecureSkipVerify: true, }) - opts := []grpc.ServerOption{grpc.Creds(creds)} + // set http error interceptor + runtime.HTTPError = httpResponseInterceptor - grpcServer := grpc.NewServer(opts...) + opts := []grpc.ServerOption{ + grpc.Creds(creds), + // grpcInterceptor(), // enable this once we start requiring the tenant id to passed as header + } + grpcServer := grpc.NewServer(opts...) dcreds := credentials.NewTLS(&tls.Config{ ServerName: addr, RootCAs: certPool, @@ -153,7 +170,7 @@ func loadCertPool() (certPool *x509.CertPool, err error) { certPool = x509.NewCertPool() ok := certPool.AppendCertsFromPEM([]byte(insecureCert)) if !ok { - return nil, centerrors.Wrap(errors.New("could not load certpool"), "") + return nil, errors.New("could not load certpool") } return certPool, nil } @@ -165,3 +182,66 @@ func loadKeyPair() (keyPair tls.Certificate, err error) { } return pair, nil } + +// grpcInterceptor returns a GRPC UnaryInterceptor for all grpc/http requests. +func grpcInterceptor() grpc.ServerOption { + return grpc.UnaryInterceptor(auth) +} + +// auth is the grpc unary interceptor to to check if the tenant ID is passed in the header. +// interceptor will check "authorisation" header. If not set, we return an error. +// +// at this point we are going with one interceptor. Once we have more than one interceptor, +// we can write a wrapper interceptor that will call the chain of interceptor +// +// Note: each handler can access tenantID from the context: ctx.Value(api.TenantKey) +func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + // if this request is for ping + if utils.ContainsString(noAuthPaths[:], info.FullMethod) { + return handler(ctx, req) + } + + err = errors.NewHTTPError(http.StatusBadRequest, ErrNoAuthHeader) + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, err + } + + auth := md.Get("authorization") + if len(auth) < 1 { + return nil, err + } + + ctx = context.WithValue(ctx, TenantKey, auth[0]) + return handler(ctx, req) +} + +// httpResponseInterceptor will intercept if the we return an error from the grpc handler. +// we fetch the http code from the error using errors.GetHTTPDetails. +// +// copied some stuff from the DefaultHTTPError interceptor. +// Note: this is where we marshal the error. +func httpResponseInterceptor(_ context.Context, _ *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) { + const fallback = `{"error": "failed to marshal error message"}` + + w.Header().Set("Content-Type", marshaler.ContentType()) + var errBody struct { + Error string `protobuf:"bytes,1,name=error" json:"error"` + } + + code, msg := errors.GetHTTPDetails(err) + errBody.Error = msg + buf, merr := marshaler.Marshal(errBody) + if merr != nil { + w.WriteHeader(http.StatusInternalServerError) + if _, err := io.WriteString(w, fallback); err != nil { + log.Infof("Failed to write response: %v", err) + } + return + } + + w.WriteHeader(code) + if _, err := w.Write(buf); err != nil { + log.Infof("Failed to write response: %v", err) + } +} diff --git a/api/server_test.go b/api/server_test.go index ac03a101e..a35ebba66 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,8 +9,6 @@ import ( "sync" "testing" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -19,13 +17,17 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/assert" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) var ctx = map[string]interface{}{} @@ -110,3 +112,45 @@ func TestCentAPIServer_FailedToGetRegistry(t *testing.T) { assert.NotNil(t, err, "Error should be not nil") assert.Equal(t, "failed to get NodeObjRegistry", err.Error()) } + +func Test_auth(t *testing.T) { + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return ctx.Value(TenantKey), nil + } + + // send ping path + resp, err := auth( + context.Background(), + nil, + &grpc.UnaryServerInfo{FullMethod: noAuthPaths[0]}, + handler, + ) + assert.Nil(t, resp) + assert.Nil(t, err) + + // send no auth + resp, err = auth( + context.Background(), + nil, + &grpc.UnaryServerInfo{FullMethod: "some method"}, + handler, + ) + + assert.Nil(t, resp) + assert.True(t, errors.IsOfType(ErrNoAuthHeader, err)) + + // send Auth + ctx := metadata.NewIncomingContext( + context.Background(), + map[string][]string{"authorization": {"1234567890"}}) + + resp, err = auth( + ctx, + nil, + &grpc.UnaryServerInfo{FullMethod: "some method"}, + handler, + ) + + assert.Nil(t, err) + assert.Equal(t, "1234567890", resp) +} diff --git a/errors/errors.go b/errors/errors.go index f4afa817b..ea8e5c8a5 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -2,7 +2,12 @@ package errors import ( "fmt" + "net/http" "strings" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // ErrUnknown is an unknown error type @@ -137,5 +142,35 @@ func IsOfType(terr, err error) bool { return errt.IsOfType(terr) } + if serr, ok := status.FromError(err); ok { + return serr.Message() == terr.Error() + } + return err.Error() == terr.Error() } + +// NewHTTPError returns an HTTPError. +func NewHTTPError(c int, err error) error { + // there is a limitation with how err is handled by grpc library. + // we will come to this once we have format for error types + return status.Error(codes.Code(c), err.Error()) +} + +// GetHTTPDetails returns a http code and message +// default http code is 500. +func GetHTTPDetails(err error) (code int, msg string) { + serr, ok := status.FromError(err) + if !ok { + return http.StatusInternalServerError, err.Error() + } + + code = int(serr.Code()) + + // if this is a grpc code, then convert it + if code < http.StatusContinue { + code = runtime.HTTPStatusFromCode(serr.Code()) + } + + return code, serr.Message() + +} diff --git a/errors/errors_test.go b/errors/errors_test.go index 811b5c450..16306ef16 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -3,9 +3,13 @@ package errors import ( + "net/http" "testing" + "google.golang.org/grpc/status" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/codes" ) func TestNew(t *testing.T) { @@ -109,4 +113,25 @@ func TestIsOfType(t *testing.T) { assert.False(t, IsOfType(errBadErr, lerr)) terr = NewTypedError(errBadErr, lerr) assert.True(t, IsOfType(errBadErr, terr)) + + // status err + serr = status.Error(codes.Unknown, errBadErr.Error()) + assert.True(t, IsOfType(errBadErr, serr)) +} + +func TestGetHTTPCode(t *testing.T) { + err := New("some error") + code, msg := GetHTTPDetails(err) + assert.Equal(t, http.StatusInternalServerError, code) + assert.Equal(t, "some error", msg) + + err = NewHTTPError(http.StatusBadRequest, err) + code, msg = GetHTTPDetails(err) + assert.Equal(t, http.StatusBadRequest, code) + assert.Equal(t, "some error", msg) + + err = NewHTTPError(int(codes.AlreadyExists), New("some error")) + code, msg = GetHTTPDetails(err) + assert.Equal(t, http.StatusConflict, code) + assert.Equal(t, "some error", msg) } diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 46a80363e..bd125c3f5 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -113,7 +113,7 @@ func TestPaymentObligationMint_errors(t *testing.T) { t.Parallel() response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) assert.Nil(t, err, "it should be possible to call the API endpoint") - response.Value("message").String().Contains(test.errorMsg) + response.Value("error").String().Contains(test.errorMsg) }) } } diff --git a/utils/strings.go b/utils/strings.go index 494f5f102..96a666783 100644 --- a/utils/strings.go +++ b/utils/strings.go @@ -13,3 +13,14 @@ func IsStringOfLength(msg string, n int) bool { func IsStringEmpty(msg string) bool { return IsStringOfLength(msg, 0) } + +// ContainsString returns true if the slice contains str. +func ContainsString(slice []string, str string) bool { + for _, s := range slice { + if s == str { + return true + } + } + + return false +} diff --git a/utils/strings_test.go b/utils/strings_test.go index f75f86033..62ff07967 100644 --- a/utils/strings_test.go +++ b/utils/strings_test.go @@ -59,3 +59,42 @@ func TestStringEmpty(t *testing.T) { assert.Equal(t, c.result, got, "result must match") } } + +func TestContainsString(t *testing.T) { + tests := []struct { + str string + slice []string + result bool + }{ + // empty everything + {}, + // empty string + { + slice: []string{"abc"}, + }, + + // empty slice + { + str: "abc", + }, + + // missing str + { + str: "test", + slice: []string{"abc", "bcd", "cde"}, + }, + + // success + { + str: "abc", + slice: []string{"bcd", "cde", "abc"}, + result: true, + }, + } + + for _, c := range tests { + if ok := ContainsString(c.slice, c.str); ok != c.result { + t.Fatalf("ContainsString(%v, %s)=%v; expected %v", c.slice, c.str, c.result, ok) + } + } +} From 3f18a572423406f62966ada21460cf3070f7c387 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 19 Dec 2018 13:32:56 +0100 Subject: [PATCH 094/220] added a generic document service (#579) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests --- documents/service.go | 110 +++++++++++++++++++++++++ documents/service_test.go | 168 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 documents/service_test.go diff --git a/documents/service.go b/documents/service.go index cbe126990..0369c7f1e 100644 --- a/documents/service.go +++ b/documents/service.go @@ -1,8 +1,12 @@ package documents import ( + "bytes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -49,3 +53,109 @@ type Service interface { // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error } + +// service implements Service +type service struct { + config Config + repo Repository +} + +// DefaultService returns the default implementation of the service +func DefaultService(config config.Configuration, repo Repository) Service { + return service{repo: repo, config: config} +} + +func getIDs(model Model) ([]byte, []byte, error) { + cd, err := model.PackCoreDocument() + + if err != nil { + return nil, nil, err + } + + return cd.DocumentIdentifier, cd.NextVersion, nil +} + +func (s service) searchVersion(m Model) (Model, error) { + + id, next, err := getIDs(m) + + if err != nil { + return nil, err + } + + if s.Exists(next) { + nm, err := s.getVersion(id, next) + if err != nil { + + return nil, err + } + return s.searchVersion(nm) + } + + return m, nil + +} + +func (s service) GetCurrentVersion(documentID []byte) (Model, error) { + model, err := s.getVersion(documentID, documentID) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentNotFound, err) + } + return s.searchVersion(model) + +} + +func (s service) GetVersion(documentID []byte, version []byte) (Model, error) { + return s.getVersion(documentID, version) +} + +func (s service) CreateProofs(documentID []byte, fields []string) (*DocumentProof, error) { + return nil, nil +} + +func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) { + return nil, nil +} + +func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) { + return nil, nil +} + +func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model Model) (*coredocumentpb.Signature, error) { + return nil, nil +} + +func (s service) ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error { + return nil +} + +func (s service) Exists(documentID []byte) bool { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return false + } + return s.repo.Exists(tenantID, documentID) +} + +func (s service) getVersion(documentID, version []byte) (Model, error) { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(ErrDocumentConfigTenantID, err) + } + model, err := s.repo.Get(tenantID, version) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + if !bytes.Equal(cd.DocumentIdentifier, documentID) { + return nil, errors.NewTypedError(ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) + } + return model, nil +} diff --git a/documents/service_test.go b/documents/service_test.go new file mode 100644 index 000000000..d6a692ece --- /dev/null +++ b/documents/service_test.go @@ -0,0 +1,168 @@ +// +build unit + +package documents_test + +import ( + "testing" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/stretchr/testify/assert" +) + +var testRepoGlobal documents.Repository + +var centIDBytes = utils.RandomSlice(identity.CentIDLength) + +func getServiceWithMockedLayers() documents.Service { + + c := &testingconfig.MockConfig{} + c.On("GetIdentityID").Return(centIDBytes, nil) + repo := testRepo() + return documents.DefaultService(c, repo) +} + +func TestService_GetCurrentVersion_successful(t *testing.T) { + + service := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + const amountVersions = 10 + + version := documentIdentifier + var currentVersion []byte + + nonExistingVersion := utils.RandomSlice(32) + + for i := 0; i < amountVersions; i++ { + + var next []byte + if i != amountVersions-1 { + next = utils.RandomSlice(32) + } else { + next = nonExistingVersion + } + + inv := &invoice.Invoice{ + GrossAmount: int64(i + 1), + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: version, + NextVersion: next, + }, + } + + err := testRepo().Create(centIDBytes, version, inv) + currentVersion = version + version = next + assert.Nil(t, err) + + } + + model, err := service.GetCurrentVersion(documentIdentifier) + assert.Nil(t, err) + + cd, err := model.PackCoreDocument() + assert.Nil(t, err) + + assert.Equal(t, cd.CurrentVersion, currentVersion, "should return latest version") + assert.Equal(t, cd.NextVersion, nonExistingVersion, "latest version should have a non existing id as nextVersion ") + +} + +func TestService_GetVersion_successful(t *testing.T) { + + service := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + currentVersion := utils.RandomSlice(32) + inv := &invoice.Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + }, + } + + err := testRepo().Create(centIDBytes, currentVersion, inv) + assert.Nil(t, err) + + mod, err := service.GetVersion(documentIdentifier, currentVersion) + assert.Nil(t, err) + + cd, err := mod.PackCoreDocument() + assert.Nil(t, err) + + assert.Equal(t, documentIdentifier, cd.DocumentIdentifier, "should be same document Identifier") + assert.Equal(t, currentVersion, cd.CurrentVersion, "should be same version") +} + +func TestService_GetCurrentVersion_error(t *testing.T) { + service := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + + //document is not existing + _, err := service.GetCurrentVersion(documentIdentifier) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + + inv := &invoice.Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + }, + } + + err = testRepo().Create(centIDBytes, documentIdentifier, inv) + assert.Nil(t, err) + + _, err = service.GetCurrentVersion(documentIdentifier) + assert.Nil(t, err) + +} + +func TestService_GetVersion_error(t *testing.T) { + + service := getServiceWithMockedLayers() + + documentIdentifier := utils.RandomSlice(32) + currentVersion := utils.RandomSlice(32) + + //document is not existing + _, err := service.GetVersion(documentIdentifier, currentVersion) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + + inv := &invoice.Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + }, + } + err = testRepo().Create(centIDBytes, currentVersion, inv) + assert.Nil(t, err) + + //random version + _, err = service.GetVersion(documentIdentifier, utils.RandomSlice(32)) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + + //random document id + _, err = service.GetVersion(utils.RandomSlice(32), documentIdentifier) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) +} + +func testRepo() documents.Repository { + if testRepoGlobal == nil { + ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + if err != nil { + panic(err) + } + testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) + testRepoGlobal.Register(&invoice.Invoice{}) + } + return testRepoGlobal +} From 91ace1fc14aca489b0e3833fe071471a08931a80 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 20 Dec 2018 14:17:49 +0100 Subject: [PATCH 095/220] document service: added CreateProof to model (#581) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests * generated genericdoc package * moved service_test * added CreateProof to model * changed to correct create proofs * formatting * correct flags * moved service_test.go --- documents/genericdoc/service.go | 143 +++++++++++++++++++++ documents/{ => genericdoc}/service_test.go | 4 +- documents/invoice/model.go | 2 +- documents/invoice/model_test.go | 4 +- documents/invoice/service.go | 2 +- documents/model.go | 5 + documents/purchaseorder/model.go | 2 +- documents/purchaseorder/model_test.go | 4 +- documents/purchaseorder/service.go | 2 +- documents/service.go | 110 ---------------- 10 files changed, 158 insertions(+), 120 deletions(-) create mode 100644 documents/genericdoc/service.go rename documents/{ => genericdoc}/service_test.go (98%) diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go new file mode 100644 index 000000000..1ca195144 --- /dev/null +++ b/documents/genericdoc/service.go @@ -0,0 +1,143 @@ +package genericdoc + +import ( + "bytes" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/header" + "github.com/centrifuge/go-centrifuge/identity" +) + +// service implements Service +type service struct { + config documents.Config + repo documents.Repository + identityService identity.Service + anchorRepository anchors.AnchorRepository +} + +// DefaultService returns the default implementation of the service +func DefaultService(config config.Configuration, repo documents.Repository, + anchorRepo anchors.AnchorRepository, idService identity.Service) documents.Service { + return service{repo: repo, + config: config, + anchorRepository: anchorRepo, + identityService: idService} +} + +func getIDs(model documents.Model) ([]byte, []byte, error) { + cd, err := model.PackCoreDocument() + + if err != nil { + return nil, nil, err + } + + return cd.DocumentIdentifier, cd.NextVersion, nil +} + +func (s service) searchVersion(m documents.Model) (documents.Model, error) { + + id, next, err := getIDs(m) + + if err != nil { + return nil, err + } + + if s.Exists(next) { + nm, err := s.getVersion(id, next) + if err != nil { + + return nil, err + } + return s.searchVersion(nm) + } + + return m, nil + +} + +func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { + model, err := s.getVersion(documentID, documentID) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + } + return s.searchVersion(model) + +} + +func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, error) { + return s.getVersion(documentID, version) +} + +func (s service) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { + /*model, err := s.GetCurrentVersion(documentID) + if err != nil { + return nil, err + } + + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) + } + //coreDoc, proofs, err := model.CreateProofs(fields) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentProof, err) + } + /*return &DocumentProof{ + DocumentID: coreDoc.DocumentIdentifier, + VersionID: coreDoc.CurrentVersion, + FieldProofs: proofs, + }, nil*/ + return nil, nil +} + +func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { + return nil, nil +} + +func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { + return nil, nil +} + +func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { + return nil, nil +} + +func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { + return nil +} + +func (s service) Exists(documentID []byte) bool { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return false + } + return s.repo.Exists(tenantID, documentID) +} + +func (s service) getVersion(documentID, version []byte) (documents.Model, error) { + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + model, err := s.repo.Get(tenantID, version) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + if !bytes.Equal(cd.DocumentIdentifier, documentID) { + return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) + } + return model, nil +} diff --git a/documents/service_test.go b/documents/genericdoc/service_test.go similarity index 98% rename from documents/service_test.go rename to documents/genericdoc/service_test.go index d6a692ece..72419c558 100644 --- a/documents/service_test.go +++ b/documents/genericdoc/service_test.go @@ -1,6 +1,6 @@ // +build unit -package documents_test +package genericdoc import ( "testing" @@ -25,7 +25,7 @@ func getServiceWithMockedLayers() documents.Service { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) repo := testRepo() - return documents.DefaultService(c, repo) + return DefaultService(c, repo, nil, nil) } func TestService_GetCurrentVersion_successful(t *testing.T) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index ad9b59f98..3000e1fda 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -378,7 +378,7 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { } // CreateProofs generates proofs for given fields -func (i *Invoice) createProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { +func (i *Invoice) CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { // There can be failure scenarios where the core doc for the particular document // is still not saved with roots in db due to failures during getting signatures. coreDoc, err = i.PackCoreDocument() diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index fe11037f6..f4b934bb3 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -260,7 +260,7 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { func TestInvoiceModel_createProofs(t *testing.T) { i, corDoc, err := createMockInvoice(t) assert.Nil(t, err) - corDoc, proof, err := i.createProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) + corDoc, proof, err := i.CreateProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) assert.NotNil(t, corDoc) @@ -288,7 +288,7 @@ func TestInvoiceModel_createProofs(t *testing.T) { func TestInvoiceModel_createProofsFieldDoesNotExist(t *testing.T) { i, _, err := createMockInvoice(t) assert.Nil(t, err) - _, _, err = i.createProofs([]string{"nonexisting"}) + _, _, err = i.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 14958155e..3e16dd422 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -94,7 +94,7 @@ func (s service) invoiceProof(model documents.Model, fields []string) (*document if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, inv); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - coreDoc, proofs, err := inv.createProofs(fields) + coreDoc, proofs, err := inv.CreateProofs(fields) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentProof, err) } diff --git a/documents/model.go b/documents/model.go index 22e9146f1..0dd50bf28 100644 --- a/documents/model.go +++ b/documents/model.go @@ -3,6 +3,8 @@ package documents import ( "reflect" + "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" ) @@ -29,4 +31,7 @@ type Model interface { // FromJSON initialize the model with a json FromJSON(json []byte) error + + // CreateProofs creates precise-proofs for given fields + CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 6d0977724..69d544a60 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -364,7 +364,7 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er } // CreateProofs generates proofs for given fields -func (p *PurchaseOrder) createProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { +func (p *PurchaseOrder) CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { // There can be failure scenarios where the core doc for the particular document // is still not saved with roots in db due to failures during getting signatures. coreDoc, err = p.PackCoreDocument() diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 450b2098d..0bbd865bb 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -232,7 +232,7 @@ func TestPOModel_calculateDataRoot(t *testing.T) { func TestPOModel_createProofs(t *testing.T) { poModel, corDoc, err := createMockPurchaseOrder(t) assert.Nil(t, err) - corDoc, proof, err := poModel.createProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) + corDoc, proof, err := poModel.CreateProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) assert.NotNil(t, corDoc) @@ -260,7 +260,7 @@ func TestPOModel_createProofs(t *testing.T) { func TestPOModel_createProofsFieldDoesNotExist(t *testing.T) { poModel, _, err := createMockPurchaseOrder(t) assert.Nil(t, err) - _, _, err = poModel.createProofs([]string{"nonexisting"}) + _, _, err = poModel.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index b6a8cf4fc..f9973e04b 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -316,7 +316,7 @@ func (s service) purchaseOrderProof(model documents.Model, fields []string) (*do if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, po); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - coreDoc, proofs, err := po.createProofs(fields) + coreDoc, proofs, err := po.CreateProofs(fields) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentProof, err) } diff --git a/documents/service.go b/documents/service.go index 0369c7f1e..cbe126990 100644 --- a/documents/service.go +++ b/documents/service.go @@ -1,12 +1,8 @@ package documents import ( - "bytes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -53,109 +49,3 @@ type Service interface { // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error } - -// service implements Service -type service struct { - config Config - repo Repository -} - -// DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo Repository) Service { - return service{repo: repo, config: config} -} - -func getIDs(model Model) ([]byte, []byte, error) { - cd, err := model.PackCoreDocument() - - if err != nil { - return nil, nil, err - } - - return cd.DocumentIdentifier, cd.NextVersion, nil -} - -func (s service) searchVersion(m Model) (Model, error) { - - id, next, err := getIDs(m) - - if err != nil { - return nil, err - } - - if s.Exists(next) { - nm, err := s.getVersion(id, next) - if err != nil { - - return nil, err - } - return s.searchVersion(nm) - } - - return m, nil - -} - -func (s service) GetCurrentVersion(documentID []byte) (Model, error) { - model, err := s.getVersion(documentID, documentID) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentNotFound, err) - } - return s.searchVersion(model) - -} - -func (s service) GetVersion(documentID []byte, version []byte) (Model, error) { - return s.getVersion(documentID, version) -} - -func (s service) CreateProofs(documentID []byte, fields []string) (*DocumentProof, error) { - return nil, nil -} - -func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) { - return nil, nil -} - -func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) { - return nil, nil -} - -func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model Model) (*coredocumentpb.Signature, error) { - return nil, nil -} - -func (s service) ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error { - return nil -} - -func (s service) Exists(documentID []byte) bool { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return false - } - return s.repo.Exists(tenantID, documentID) -} - -func (s service) getVersion(documentID, version []byte) (Model, error) { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(ErrDocumentConfigTenantID, err) - } - model, err := s.repo.Get(tenantID, version) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - - if !bytes.Equal(cd.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) - } - return model, nil -} From c886979b3157ca15962a2cb5ebe90f1632477315 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 20 Dec 2018 16:16:26 +0100 Subject: [PATCH 096/220] document service: createProof and CreateProofForVersion (#584) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests * generated genericdoc package * moved service_test * added CreateProof to model * changed to correct create proofs * formatting * correct flags * added proof methods * moved service_test.go * added tests for createProof in service * fixed broken createProofVersion test case * formatting --- documents/genericdoc/service.go | 23 ++- documents/genericdoc/service_test.go | 246 +++++++++++++++++++++++++-- documents/invoice/model.go | 4 +- documents/invoice/model_test.go | 4 +- documents/invoice/service.go | 2 +- documents/invoice/service_test.go | 4 +- documents/invoice/validator.go | 2 +- documents/invoice/validator_test.go | 2 +- 8 files changed, 259 insertions(+), 28 deletions(-) diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 1ca195144..fbd8cda09 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -3,6 +3,8 @@ package genericdoc import ( "bytes" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" @@ -41,7 +43,6 @@ func getIDs(model documents.Model) ([]byte, []byte, error) { } func (s service) searchVersion(m documents.Model) (documents.Model, error) { - id, next, err := getIDs(m) if err != nil { @@ -75,28 +76,36 @@ func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, } func (s service) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { - /*model, err := s.GetCurrentVersion(documentID) + model, err := s.GetCurrentVersion(documentID) if err != nil { return nil, err } + return s.createProofs(model, fields) +} + +func (s service) createProofs(model documents.Model, fields []string) (*documents.DocumentProof, error) { if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - //coreDoc, proofs, err := model.CreateProofs(fields) + coreDoc, proofs, err := model.CreateProofs(fields) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentProof, err) } - /*return &DocumentProof{ + return &documents.DocumentProof{ DocumentID: coreDoc.DocumentIdentifier, VersionID: coreDoc.CurrentVersion, FieldProofs: proofs, - }, nil*/ - return nil, nil + }, nil + } func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - return nil, nil + model, err := s.getVersion(documentID, version) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + } + return s.createProofs(model, fields) } func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index 72419c558..e58d3dcae 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -3,8 +3,14 @@ package genericdoc import ( + "math/big" "testing" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/stretchr/testify/mock" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -17,20 +23,212 @@ import ( ) var testRepoGlobal documents.Repository +var ( + centIDBytes = utils.RandomSlice(identity.CentIDLength) + key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} +) -var centIDBytes = utils.RandomSlice(identity.CentIDLength) - -func getServiceWithMockedLayers() documents.Service { - +func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) repo := testRepo() - return DefaultService(c, repo, nil, nil) + idService := testingcommons.MockIDService{} + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + return DefaultService(c, repo, &mockAnchorRepo{}, &idService), idService } -func TestService_GetCurrentVersion_successful(t *testing.T) { +type mockAnchorRepo struct { + mock.Mock + anchors.AnchorRepository +} + +func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { + args := r.Called(anchorID) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) + return docRoot, args.Error(1) +} + +func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, error) { + i := &invoice.Invoice{ + InvoiceNumber: "test_invoice", + GrossAmount: 60, + CoreDocument: coredocument.New(), + } + err := i.CalculateDataRoot() + if err != nil { + return nil, err + } + // get the coreDoc for the invoice + corDoc, err := i.PackCoreDocument() + if err != nil { + return nil, err + } + assert.Nil(t, coredocument.FillSalts(corDoc)) + err = coredocument.CalculateSigningRoot(corDoc) + if err != nil { + return nil, err + } - service := getServiceWithMockedLayers() + centID, err := identity.ToCentID(centIDBytes) + assert.Nil(t, err) + signKey := identity.IDKey{ + PublicKey: key1Pub[:], + PrivateKey: key1, + } + idConfig := &identity.IDConfig{ + ID: centID, + Keys: map[int]identity.IDKey{ + identity.KeyPurposeSigning: signKey, + }, + } + + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) + + corDoc.Signatures = append(corDoc.Signatures, sig) + + err = coredocument.CalculateDocumentRoot(corDoc) + if err != nil { + return nil, err + } + err = i.UnpackCoreDocument(corDoc) + if err != nil { + return nil, err + } + + if !skipSave { + err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + if err != nil { + return nil, err + } + } + + return i, nil +} + +func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Invoice, error) { + i.GrossAmount = 50 + err := i.CalculateDataRoot() + if err != nil { + return nil, err + } + // get the coreDoc for the invoice + corDoc, err := i.PackCoreDocument() + if err != nil { + return nil, err + } + // hacky update to version + corDoc.CurrentVersion = corDoc.NextVersion + corDoc.NextVersion = utils.RandomSlice(32) + if err != nil { + return nil, err + } + err = coredocument.CalculateSigningRoot(corDoc) + if err != nil { + return nil, err + } + err = coredocument.CalculateDocumentRoot(corDoc) + if err != nil { + return nil, err + } + err = i.UnpackCoreDocument(corDoc) + if err != nil { + return nil, err + } + err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + if err != nil { + return nil, err + } + return i, nil +} + +// Functions returns service mocks +func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s documents.Service) testingcommons.MockIDService { + idkey := &identity.EthereumIdentityKey{ + Key: key1Pub, + Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, + RevokedAt: big.NewInt(0), + } + anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) + docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) + mockRepo := s.(service).anchorRepository.(*mockAnchorRepo) + mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() + id := &testingcommons.MockID{} + centID, _ := identity.ToCentID(centIDBytes) + idService.On("LookupIdentityForID", centID).Return(id, nil).Once() + id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() + return idService +} + +func TestService_CreateProofs(t *testing.T) { + service, idService := getServiceWithMockedLayers() + i, err := createAnchoredMockDocument(t, false) + assert.Nil(t, err) + idService = mockSignatureCheck(i, idService, service) + proof, err := service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + assert.Nil(t, err) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) + assert.Equal(t, len(proof.FieldProofs), 1) + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") +} +func TestService_CreateProofsValidationFails(t *testing.T) { + service, idService := getServiceWithMockedLayers() + i, err := createAnchoredMockDocument(t, false) + assert.Nil(t, err) + i.CoreDocument.SigningRoot = nil + err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) + assert.Nil(t, err) + idService = mockSignatureCheck(i, idService, service) + _, err = service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "signing root missing") +} + +func TestService_CreateProofsInvalidField(t *testing.T) { + service, idService := getServiceWithMockedLayers() + i, err := createAnchoredMockDocument(t, false) + assert.Nil(t, err) + idService = mockSignatureCheck(i, idService, service) + _, err = service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) + assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) +} + +func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { + service, _ := getServiceWithMockedLayers() + _, err := service.CreateProofs(utils.RandomSlice(32), []string{"invoice.invoice_number"}) + assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) +} + +func TestService_CreateProofsForVersion(t *testing.T) { + service, idService := getServiceWithMockedLayers() + i, err := createAnchoredMockDocument(t, false) + assert.Nil(t, err) + idService = mockSignatureCheck(i, idService, service) + olderVersion := i.CoreDocument.CurrentVersion + i, err = updatedAnchoredMockDocument(t, i) + assert.Nil(t, err) + proof, err := service.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) + assert.Nil(t, err) + assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, olderVersion, proof.VersionID) + assert.Equal(t, len(proof.FieldProofs), 1) + assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") +} + +func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { + i, err := createAnchoredMockDocument(t, false) + s, _ := getServiceWithMockedLayers() + assert.Nil(t, err) + _, err = s.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) + assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) +} + +func TestService_GetCurrentVersion_successful(t *testing.T) { + service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) const amountVersions = 10 @@ -76,8 +274,7 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { } func TestService_GetVersion_successful(t *testing.T) { - - service := getServiceWithMockedLayers() + service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) inv := &invoice.Invoice{ @@ -102,7 +299,7 @@ func TestService_GetVersion_successful(t *testing.T) { } func TestService_GetCurrentVersion_error(t *testing.T) { - service := getServiceWithMockedLayers() + service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) //document is not existing @@ -126,8 +323,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { } func TestService_GetVersion_error(t *testing.T) { - - service := getServiceWithMockedLayers() + service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) @@ -166,3 +362,29 @@ func testRepo() documents.Repository { } return testRepoGlobal } + +func TestService_Exists(t *testing.T) { + service, _ := getServiceWithMockedLayers() + documentIdentifier := utils.RandomSlice(32) + + //document is not existing + _, err := service.GetCurrentVersion(documentIdentifier) + assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + + inv := &invoice.Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + }, + } + + err = testRepo().Create(centIDBytes, documentIdentifier, inv) + + exists := service.Exists(documentIdentifier) + assert.True(t, exists, "document should exist") + + exists = service.Exists(utils.RandomSlice(32)) + assert.False(t, exists, "document should not exist") + +} diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 3000e1fda..58ddb4d75 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -351,8 +351,8 @@ func (i *Invoice) Type() reflect.Type { return reflect.TypeOf(i) } -// calculateDataRoot calculates the data root and sets the root to core document -func (i *Invoice) calculateDataRoot() error { +// CalculateDataRoot calculates the data root and sets the root to core document +func (i *Invoice) CalculateDataRoot() error { t, err := i.getDocumentDataTree() if err != nil { return errors.New("calculateDataRoot error %v", err) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index f4b934bb3..c7a455cc0 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -250,7 +250,7 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { assert.Nil(t, err, "Init must pass") assert.Nil(t, m.InvoiceSalts, "salts must be nil") - err = m.calculateDataRoot() + err = m.CalculateDataRoot() assert.Nil(t, err, "calculate must pass") assert.NotNil(t, m.CoreDocument, "coredoc must be created") assert.NotNil(t, m.InvoiceSalts, "salts must be created") @@ -311,7 +311,7 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, error) { i := &Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2, Currency: "USD", CoreDocument: coredocument.New()} i.CoreDocument.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} - err := i.calculateDataRoot() + err := i.CalculateDataRoot() if err != nil { return nil, nil, err } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 3e16dd422..7e9f48ccf 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -139,7 +139,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // create data root, has to be done at the model level to access fields - err := inv.calculateDataRoot() + err := inv.CalculateDataRoot() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index ed426dcb7..12e12d55f 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -399,7 +399,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { GrossAmount: 60, CoreDocument: coredocument.New(), } - err := i.calculateDataRoot() + err := i.CalculateDataRoot() if err != nil { return nil, err } @@ -452,7 +452,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { i.GrossAmount = 50 - err := i.calculateDataRoot() + err := i.CalculateDataRoot() if err != nil { return nil, err } diff --git a/documents/invoice/validator.go b/documents/invoice/validator.go index 9dd89a909..37622f602 100644 --- a/documents/invoice/validator.go +++ b/documents/invoice/validator.go @@ -55,7 +55,7 @@ func dataRootValidator() documents.Validator { return errors.New("unknown document type: %T", model) } - if err = inv.calculateDataRoot(); err != nil { + if err = inv.CalculateDataRoot(); err != nil { return errors.New("failed to calculate data root: %v", err) } diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 4ecc74d0c..3f3dc9fd3 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -95,7 +95,7 @@ func TestDataRootValidation_Validate(t *testing.T) { inv = new(Invoice) err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) assert.Nil(t, err) - err = inv.calculateDataRoot() + err = inv.CalculateDataRoot() assert.Nil(t, err) err = drv.Validate(nil, inv) assert.Nil(t, err) From 4a2b67d1d1315397015b726d81c33d1c1a79e937 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 20 Dec 2018 17:44:17 +0100 Subject: [PATCH 097/220] Transactions (#582) * initial tx repo * lint fixes --- Gopkg.lock | 2 + context/bootstrapper.go | 2 + transactions/bootstrapper.go | 29 +++++++++++ transactions/bootstrapper_test.go | 26 ++++++++++ transactions/repository.go | 78 ++++++++++++++++++++++++++++ transactions/repository_test.go | 84 +++++++++++++++++++++++++++++++ transactions/test_bootstrapper.go | 11 ++++ transactions/transaction.go | 72 ++++++++++++++++++++++++++ 8 files changed, 304 insertions(+) create mode 100644 transactions/bootstrapper.go create mode 100644 transactions/bootstrapper_test.go create mode 100644 transactions/repository.go create mode 100644 transactions/repository_test.go create mode 100644 transactions/test_bootstrapper.go create mode 100644 transactions/transaction.go diff --git a/Gopkg.lock b/Gopkg.lock index 4686ade13..81c3cf42e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1553,6 +1553,7 @@ "github.com/multiformats/go-multihash", "github.com/paralin/go-libp2p-grpc", "github.com/roboll/go-vendorinstall", + "github.com/satori/go.uuid", "github.com/savaki/jq", "github.com/spf13/cast", "github.com/spf13/cobra", @@ -1570,6 +1571,7 @@ "google.golang.org/grpc/codes", "google.golang.org/grpc/credentials", "google.golang.org/grpc/grpclog", + "google.golang.org/grpc/metadata", "google.golang.org/grpc/status", "gopkg.in/resty.v1", ] diff --git a/context/bootstrapper.go b/context/bootstrapper.go index a0274691c..2442ad1ff 100644 --- a/context/bootstrapper.go +++ b/context/bootstrapper.go @@ -15,6 +15,7 @@ import ( "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/version" logging "github.com/ipfs/go-log" ) @@ -32,6 +33,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + transactions.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, &anchors.Bootstrapper{}, diff --git a/transactions/bootstrapper.go b/transactions/bootstrapper.go new file mode 100644 index 000000000..f791cb08a --- /dev/null +++ b/transactions/bootstrapper.go @@ -0,0 +1,29 @@ +package transactions + +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" +) + +const ( + // ErrTransactionBootstrap error when bootstrap fails. + ErrTransactionBootstrap = errors.Error("failed to bootstrap transactions") + + // BootstrappedRepo is the key mapped to transactions.Repository. + BootstrappedRepo = "BootstrappedRepo" +) + +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} + +// Bootstrap adds transaction.Repository into context. +func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + repo, ok := ctx[storage.BootstrappedDB].(storage.Repository) + if !ok { + return ErrTransactionBootstrap + } + + txRepo := NewRepository(repo) + ctx[BootstrappedRepo] = txRepo + return nil +} diff --git a/transactions/bootstrapper_test.go b/transactions/bootstrapper_test.go new file mode 100644 index 000000000..c0c0eccfd --- /dev/null +++ b/transactions/bootstrapper_test.go @@ -0,0 +1,26 @@ +// +build unit + +package transactions + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + b := Bootstrapper{} + ctx := make(map[string]interface{}) + err := b.Bootstrap(ctx) + assert.True(t, errors.IsOfType(ErrTransactionBootstrap, err)) + + randomPath := storage.GetRandomTestStoragePath() + db, err := storage.NewLevelDBStorage(randomPath) + assert.Nil(t, err) + ctx[storage.BootstrappedDB] = storage.NewLevelDBRepository(db) + err = b.Bootstrap(ctx) + assert.Nil(t, err) + assert.NotNil(t, ctx[BootstrappedRepo]) +} diff --git a/transactions/repository.go b/transactions/repository.go new file mode 100644 index 000000000..d66f5d293 --- /dev/null +++ b/transactions/repository.go @@ -0,0 +1,78 @@ +package transactions + +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" +) + +const ( + // ErrTransactionMissing error when transaction doesn't exist in Repository. + ErrTransactionMissing = errors.Error("transaction doesn't exist") + + // ErrKeyConstructionFailed error when the key construction failed. + ErrKeyConstructionFailed = errors.Error("failed to construct transaction key") +) + +// Repository can be implemented by a type that handles storage for transactions. +type Repository interface { + Get(identity common.Address, id uuid.UUID) (*Transaction, error) + Save(transaction *Transaction) error +} + +// txRepository implements Repository. +type txRepository struct { + repo storage.Repository +} + +// NewRepository registers the the transaction model and returns the an implementation +// of the Repository. +func NewRepository(repo storage.Repository) Repository { + repo.Register(&Transaction{}) + return &txRepository{repo: repo} +} + +// getKey appends identity with id. +// With identity coming at first, we can even fetch transactions belonging to specific identity through prefix. +func getKey(identity common.Address, id uuid.UUID) ([]byte, error) { + if utils.IsEmptyAddress(identity) { + return nil, errors.New("identity cannot be empty") + } + + if uuid.Equal(uuid.Nil, id) { + return nil, errors.New("transaction ID is not valid") + } + + return append(identity[:], id.Bytes()...), nil +} + +// Get returns the transaction associated with identity and id. +func (r *txRepository) Get(identity common.Address, id uuid.UUID) (*Transaction, error) { + key, err := getKey(identity, id) + if err != nil { + return nil, errors.NewTypedError(ErrKeyConstructionFailed, err) + } + + m, err := r.repo.Get(key) + if err != nil { + return nil, errors.NewTypedError(ErrTransactionMissing, err) + } + + return m.(*Transaction), nil +} + +// Save saves the transaction to the repository. +func (r *txRepository) Save(tx *Transaction) error { + key, err := getKey(tx.Identity, tx.ID) + if err != nil { + return errors.NewTypedError(ErrKeyConstructionFailed, err) + } + + if r.repo.Exists(key) { + return r.repo.Update(key, tx) + } + + return r.repo.Create(key, tx) +} diff --git a/transactions/repository_test.go b/transactions/repository_test.go new file mode 100644 index 000000000..14fb35ef6 --- /dev/null +++ b/transactions/repository_test.go @@ -0,0 +1,84 @@ +// +build unit + +package transactions + +import ( + "os" + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/assert" +) + +var ctx = map[string]interface{}{} + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + +func Test_getKey(t *testing.T) { + identity := common.Address([20]byte{}) + id := uuid.UUID([16]byte{}) + + // zero address + key, err := getKey(identity, id) + assert.Nil(t, key) + assert.Equal(t, "identity cannot be empty", err.Error()) + + bytes := utils.RandomSlice(common.AddressLength) + assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) + + // empty id + key, err = getKey(identity, id) + assert.Nil(t, key) + assert.Equal(t, "transaction ID is not valid", err.Error()) + + id = uuid.Must(uuid.NewV4()) + key, err = getKey(identity, id) + assert.Nil(t, err) + assert.Equal(t, append(identity[:], id.Bytes()...), key) +} + +func TestRepository(t *testing.T) { + identity := common.Address([20]byte{}) + bytes := utils.RandomSlice(common.AddressLength) + assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) + + repo := ctx[BootstrappedRepo].(Repository) + tx := NewTransaction(identity, "Some transaction") + assert.NotNil(t, tx.ID) + assert.NotNil(t, tx.Identity) + assert.Equal(t, Pending, tx.Status) + + // get tx from repo + _, err := repo.Get(identity, tx.ID) + assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + + // save tx into repo + tx.Status = Success + err = repo.Save(tx) + assert.Nil(t, err) + + // get tx back + tx, err = repo.Get(identity, tx.ID) + assert.Nil(t, err) + assert.NotNil(t, tx) + assert.Equal(t, identity, tx.Identity) + assert.Equal(t, Success, tx.Status) +} diff --git a/transactions/test_bootstrapper.go b/transactions/test_bootstrapper.go new file mode 100644 index 000000000..cab5a3704 --- /dev/null +++ b/transactions/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build unit integration + +package transactions + +func (b Bootstrapper) TestBootstrap(ctx map[string]interface{}) error { + return b.Bootstrap(ctx) +} + +func (b Bootstrapper) TestTearDown() error { + return nil +} diff --git a/transactions/transaction.go b/transactions/transaction.go new file mode 100644 index 000000000..cb573c310 --- /dev/null +++ b/transactions/transaction.go @@ -0,0 +1,72 @@ +package transactions + +import ( + "encoding/json" + "reflect" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" +) + +// Status represents the status of the transaction +type Status uint8 + +// Status constants +const ( + Success Status = iota + Failed + Pending +) + +// Log represents a single task in a transaction. +type Log struct { + Action string + Message string + Time time.Time +} + +// NewLog constructs a new log with action and message +func NewLog(action, message string) Log { + return Log{ + Action: action, + Message: message, + Time: time.Now().UTC(), + } +} + +// Transaction contains details of transaction. +type Transaction struct { + ID uuid.UUID + Identity common.Address + Description string + Status Status + Logs []Log + Metadata map[string]string +} + +// JSON returns json marshaled transaction. +func (t *Transaction) JSON() ([]byte, error) { + return json.Marshal(t) +} + +// FromJSON loads the data into transaction. +func (t *Transaction) FromJSON(data []byte) error { + return json.Unmarshal(data, t) +} + +// Type returns the reflect.Type of the transaction. +func (t *Transaction) Type() reflect.Type { + return reflect.TypeOf(t) +} + +// NewTransaction returns a new transaction with a pending state +func NewTransaction(identity common.Address, description string) *Transaction { + return &Transaction{ + ID: uuid.Must(uuid.NewV4()), + Identity: identity, + Description: description, + Status: Pending, + Metadata: make(map[string]string), + } +} From 7359c2015731d6f0a23e33b04d673f8547d0c825 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 20 Dec 2018 20:26:27 +0100 Subject: [PATCH 098/220] document service: added RequestDocumentSignature and ReceiveAnchoredDocument (#586) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests * generated genericdoc package * moved service_test * added CreateProof to model * changed to correct create proofs * formatting * correct flags * added proof methods * moved service_test.go * added tests for createProof in service * implemented remaining methods for document service * fixed broken createProofVersion test case * formatting * added tests for requestSignature * formatting --- documents/genericdoc/service.go | 90 +++++++++++++++++++++++++++- documents/genericdoc/service_test.go | 45 ++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index fbd8cda09..25741ce37 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -2,6 +2,14 @@ package genericdoc import ( "bytes" + "time" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" + "github.com/centrifuge/go-centrifuge/notification" + "github.com/centrifuge/go-centrifuge/signatures" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/ptypes" "github.com/centrifuge/go-centrifuge/coredocument" @@ -13,6 +21,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" + logging "github.com/ipfs/go-log" ) // service implements Service @@ -20,15 +29,19 @@ type service struct { config documents.Config repo documents.Repository identityService identity.Service + notifier notification.Sender anchorRepository anchors.AnchorRepository } +var srvLog = logging.Logger("document-service") + // DefaultService returns the default implementation of the service func DefaultService(config config.Configuration, repo documents.Repository, anchorRepo anchors.AnchorRepository, idService identity.Service) documents.Service { return service{repo: repo, config: config, anchorRepository: anchorRepo, + notifier: notification.NewWebhookSender(config), identityService: idService} } @@ -109,14 +122,89 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str } func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { + return nil, nil } func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { - return nil, nil + if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) + } + + doc, err := model.PackCoreDocument() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + } + + srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) + + idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + if !ok { + return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) + } + sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + doc.Signatures = append(doc.Signatures, sig) + err = model.UnpackCoreDocument(doc) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) + } + + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + // Logic for receiving version n (n > 1) of the document for the first time + if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) + } + } + + err = s.repo.Create(tenantID, doc.CurrentVersion, model) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) + } + + srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) + return sig, nil } func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + return errors.NewTypedError(documents.ErrDocumentInvalid, err) + } + + doc, err := model.PackCoreDocument() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + } + + // get tenant ID + tenantID, err := s.config.GetIdentityID() + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + err = s.repo.Update(tenantID, doc.CurrentVersion, model) + if err != nil { + return errors.NewTypedError(documents.ErrDocumentPersistence, err) + } + + ts, _ := ptypes.TimestampProto(time.Now().UTC()) + notificationMsg := ¬ificationpb.NotificationMessage{ + EventType: uint32(notification.ReceivedPayload), + CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), + Recorded: ts, + DocumentType: doc.EmbeddedData.TypeUrl, + DocumentId: hexutil.Encode(doc.DocumentIdentifier), + } + + // Async until we add queuing + go s.notifier.Send(notificationMsg) + return nil } diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index e58d3dcae..e9cd4b9f5 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -3,9 +3,17 @@ package genericdoc import ( + "context" "math/big" + "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/header" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -29,6 +37,30 @@ var ( key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) +var ctx = map[string]interface{}{} +var cfg config.Configuration + +func TestMain(m *testing.M) { + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + +func TestService_ReceiveAnchoredDocument(t *testing.T) { + poSrv := service{} + err := poSrv.ReceiveAnchoredDocument(nil, nil) + assert.Error(t, err) +} + func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) @@ -218,6 +250,19 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") } +func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { + service, idService := getServiceWithMockedLayers() + i, err := createAnchoredMockDocument(t, true) + assert.Nil(t, err) + idService = mockSignatureCheck(i, idService, service) + i.CoreDocument.SigningRoot = nil + ctxh, err := header.NewContextHeader(context.Background(), cfg) + signature, err := service.RequestDocumentSignature(ctxh, i) + assert.NotNil(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) + assert.Nil(t, signature) +} + func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) s, _ := getServiceWithMockedLayers() From 56d720c274f8e0a27106b503cdc364914d9c8ad1 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 20 Dec 2018 21:14:40 +0100 Subject: [PATCH 099/220] [Config DB] API Admin Endpoints (#583) * Added proto models + service * handler + service * model tests * add tests * delete return * missing tag * proto --- config/handler.go | 116 +++ config/handler_test.go | 205 ++++ config/model.go | 152 ++- config/model_test.go | 81 ++ config/repository_test.go | 24 + config/service.go | 59 ++ config/service_test.go | 172 ++++ protobufs/config/service.proto | 149 +++ protobufs/gen/go/config/service.pb.go | 948 ++++++++++++++++++ protobufs/gen/go/config/service.pb.gw.go | 523 ++++++++++ protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 378 +++++++ 12 files changed, 2806 insertions(+), 3 deletions(-) create mode 100644 config/handler.go create mode 100644 config/handler_test.go create mode 100644 config/service.go create mode 100644 config/service_test.go create mode 100644 protobufs/config/service.proto create mode 100644 protobufs/gen/go/config/service.pb.go create mode 100644 protobufs/gen/go/config/service.pb.gw.go create mode 100644 protobufs/gen/swagger/config/service.swagger.json diff --git a/config/handler.go b/config/handler.go new file mode 100644 index 000000000..b82881b39 --- /dev/null +++ b/config/handler.go @@ -0,0 +1,116 @@ +package config + +import ( + "context" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/golang/protobuf/ptypes/empty" + logging "github.com/ipfs/go-log" +) + +var apiLog = logging.Logger("config-api") + +type grpcHandler struct { + service Service +} + +// GRPCHandler returns an implementation of configpb.ConfigServiceServer +func GRPCHandler(svc Service) configpb.ConfigServiceServer { + return &grpcHandler{service: svc} +} + +func (h grpcHandler) deriveAllTenantResponse(cfgs []*TenantConfig) (*configpb.GetAllTenantResponse, error) { + response := new(configpb.GetAllTenantResponse) + for _, t := range cfgs { + response.Data = append(response.Data, t.createProtobuf()) + } + return response, nil +} + +func (h grpcHandler) GetConfig(ctx context.Context, _ *empty.Empty) (*configpb.ConfigData, error) { + nodeConfig, err := h.service.GetConfig() + if err != nil { + return nil, err + } + return nodeConfig.createProtobuf(), nil +} + +func (h grpcHandler) GetTenant(ctx context.Context, req *configpb.GetTenantRequest) (*configpb.TenantData, error) { + id, err := hexutil.Decode(req.Identifier) + if err != nil { + return nil, err + } + tenantConfig, err := h.service.GetTenant(id) + if err != nil { + return nil, err + } + return tenantConfig.createProtobuf(), nil +} + +func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*configpb.GetAllTenantResponse, error) { + cfgs, err := h.service.GetAllTenants() + if err != nil { + return nil, err + } + return h.deriveAllTenantResponse(cfgs) +} + +func (h grpcHandler) CreateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { + apiLog.Infof("Creating node config: %v", data) + nodeConfig := new(NodeConfig) + nodeConfig.loadFromProtobuf(data) + nodeConfig, err := h.service.CreateConfig(nodeConfig) + if err != nil { + return nil, err + } + return nodeConfig.createProtobuf(), nil +} + +func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData) (*configpb.TenantData, error) { + apiLog.Infof("Creating tenant config: %v", data) + tenantConfig := new(TenantConfig) + tenantConfig.loadFromProtobuf(data) + tenantConfig, err := h.service.CreateTenant(tenantConfig) + if err != nil { + return nil, err + } + return tenantConfig.createProtobuf(), nil +} + +func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { + apiLog.Infof("Updating node config: %v", data) + nodeConfig := new(NodeConfig) + nodeConfig.loadFromProtobuf(data) + nodeConfig, err := h.service.UpdateConfig(nodeConfig) + if err != nil { + return nil, err + } + return nodeConfig.createProtobuf(), nil +} + +func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenantRequest) (*configpb.TenantData, error) { + apiLog.Infof("Updating tenant config: %v", req) + tenantConfig := new(TenantConfig) + tenantConfig.loadFromProtobuf(req.Data) + tenantConfig, err := h.service.UpdateTenant(tenantConfig) + if err != nil { + return nil, err + } + return tenantConfig.createProtobuf(), nil +} + +func (h grpcHandler) DeleteConfig(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) { + apiLog.Infof("Deleting node config") + return nil, h.service.DeleteConfig() +} + +func (h grpcHandler) DeleteTenant(ctx context.Context, req *configpb.GetTenantRequest) (*empty.Empty, error) { + apiLog.Infof("Deleting tenant config: %v", req.Identifier) + id, err := hexutil.Decode(req.Identifier) + if err != nil { + return nil, err + } + return nil, h.service.DeleteTenant(id) +} diff --git a/config/handler_test.go b/config/handler_test.go new file mode 100644 index 000000000..50d327027 --- /dev/null +++ b/config/handler_test.go @@ -0,0 +1,205 @@ +// +build unit + +package config + +import ( + "context" + "testing" + + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" +) + +func TestGrpcHandler_GetConfigNoConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + readCfg, err := h.GetConfig(context.Background(), nil) + assert.NotNil(t, err) + assert.Nil(t, readCfg) +} + +func TestGrpcHandler_GetConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg := NewNodeConfig(cfg) + _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + readCfg, err := h.GetConfig(context.Background(), nil) + assert.Nil(t, err) + assert.NotNil(t, readCfg) +} + +func TestGrpcHandler_GetTenantNoConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: "0x123456789"}) + assert.NotNil(t, err) + assert.Nil(t, readCfg) +} + +func TestGrpcHandler_GetTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + assert.Nil(t, err) + assert.NotNil(t, readCfg) +} + +func TestGrpcHandler_GetAllTenants(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg1, err := NewTenantConfig("main", cfg) + nodeCfg2, err := NewTenantConfig("main", cfg) + nodeCfg2.IdentityID = []byte("0x123456789") + _, err = h.CreateTenant(context.Background(), nodeCfg1.createProtobuf()) + assert.Nil(t, err) + _, err = h.CreateTenant(context.Background(), nodeCfg2.createProtobuf()) + assert.Nil(t, err) + + resp, err := h.GetAllTenants(context.Background(), nil) + assert.Nil(t, err) + assert.Equal(t, 2, len(resp.Data)) +} + +func TestGrpcHandler_CreateConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg := NewNodeConfig(cfg) + _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + + // Already exists + _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.NotNil(t, err) +} + +func TestGrpcHandler_CreateTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + + // Already exists + _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + assert.NotNil(t, err) +} + +func TestGrpcHandler_UpdateConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg := NewNodeConfig(cfg) + + // Config doesn't exist + _, err = h.UpdateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.NotNil(t, err) + + _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + nodeCfg.NetworkString = "other" + _, err = h.UpdateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + + readCfg, err := h.GetConfig(context.Background(), nil) + assert.Nil(t, err) + assert.Equal(t, nodeCfg.NetworkString, readCfg.Network) +} + +func TestGrpcHandler_UpdateTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + nodeCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + + // Config doesn't exist + _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID), Data: nodeCfg.createProtobuf()}) + assert.NotNil(t, err) + + _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + nodeCfg.EthereumDefaultAccountName = "other" + _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID), Data: nodeCfg.createProtobuf()}) + assert.Nil(t, err) + + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + assert.Nil(t, err) + assert.Equal(t, nodeCfg.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) +} + +func TestGrpcHandler_DeleteConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + + //No error when no config + _, err = h.DeleteConfig(context.Background(), nil) + assert.Nil(t, err) + + nodeCfg := NewNodeConfig(cfg) + _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + _, err = h.DeleteConfig(context.Background(), nil) + assert.Nil(t, err) + + readCfg, err := h.GetConfig(context.Background(), nil) + assert.NotNil(t, err) + assert.Nil(t, readCfg) +} + +func TestGrpcHandler_DeleteTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + h := GRPCHandler(svc) + + //No error when no config + _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: "0x12345678"}) + assert.Nil(t, err) + + nodeCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + assert.Nil(t, err) + _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + assert.Nil(t, err) + + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + assert.NotNil(t, err) + assert.Nil(t, readCfg) +} diff --git a/config/model.go b/config/model.go index 89a94e0bb..afd2401f4 100644 --- a/config/model.go +++ b/config/model.go @@ -5,6 +5,11 @@ import ( "math/big" "reflect" "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/golang/protobuf/ptypes/duration" ) // KeyPair represents a key pair config @@ -19,6 +24,7 @@ func NewKeyPair(pub, priv string) KeyPair { // NodeConfig exposes configs specific to the node type NodeConfig struct { + MainIdentity TenantConfig StoragePath string P2PPort int P2PExternalIP string @@ -38,8 +44,6 @@ type NodeConfig struct { NetworkString string BootstrapPeers []string NetworkID uint32 - - // TODO what to do about contract addresses? } // ID Gets the ID of the document represented by this model @@ -62,9 +66,113 @@ func (nc *NodeConfig) FromJSON(data []byte) error { return json.Unmarshal(data, nc) } +func (nc *NodeConfig) createProtobuf() *configpb.ConfigData { + return &configpb.ConfigData{ + MainIdentity: &configpb.TenantData{ + EthAccount: &configpb.EthereumAccount{ + Address: nc.MainIdentity.EthereumAccount.Address, + Key: nc.MainIdentity.EthereumAccount.Key, + Password: nc.MainIdentity.EthereumAccount.Password, + }, + EthDefaultAccountName: nc.MainIdentity.EthereumDefaultAccountName, + IdentityId: hexutil.Encode(nc.MainIdentity.IdentityID), + ReceiveEventNotificationEndpoint: nc.MainIdentity.ReceiveEventNotificationEndpoint, + EthauthKeyPair: &configpb.KeyPair{ + Pub: nc.MainIdentity.EthAuthKeyPair.Pub, + Pvt: nc.MainIdentity.EthAuthKeyPair.Priv, + }, + SigningKeyPair: &configpb.KeyPair{ + Pub: nc.MainIdentity.SigningKeyPair.Pub, + Pvt: nc.MainIdentity.SigningKeyPair.Priv, + }, + }, + StoragePath: nc.StoragePath, + P2PPort: int32(nc.P2PPort), + P2PExternalIp: nc.P2PExternalIP, + P2PConnectionTimeout: &duration.Duration{Seconds: int64(nc.P2PConnectionTimeout.Seconds())}, + ServerPort: int32(nc.ServerPort), + ServerAddress: nc.ServerAddress, + NumWorkers: int32(nc.NumWorkers), + WorkerWaitTimeMs: int32(nc.WorkerWaitTimeMS), + EthContextReadWaitTimeout: &duration.Duration{Seconds: int64(nc.EthereumContextReadWaitTimeout.Seconds())}, + EthContextWaitTimeout: &duration.Duration{Seconds: int64(nc.EthereumContextWaitTimeout.Seconds())}, + EthIntervalRetry: &duration.Duration{Seconds: int64(nc.EthereumIntervalRetry.Seconds())}, + EthGasPrice: nc.EthereumGasPrice.Uint64(), + EthGasLimit: nc.EthereumGasLimit, + TxPoolEnabled: nc.TxPoolAccessEnabled, + Network: nc.NetworkString, + NetworkId: nc.NetworkID, + } +} + +func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) { + identityID, _ := hexutil.Decode(data.MainIdentity.IdentityId) + + nc.MainIdentity = TenantConfig{ + EthereumAccount: &AccountConfig{ + Address: data.MainIdentity.EthAccount.Address, + Key: data.MainIdentity.EthAccount.Key, + Password: data.MainIdentity.EthAccount.Password, + }, + EthereumDefaultAccountName: data.MainIdentity.EthDefaultAccountName, + IdentityID: identityID, + ReceiveEventNotificationEndpoint: data.MainIdentity.ReceiveEventNotificationEndpoint, + SigningKeyPair: KeyPair{ + Pub: data.MainIdentity.SigningKeyPair.Pub, + Priv: data.MainIdentity.SigningKeyPair.Pvt, + }, + EthAuthKeyPair: KeyPair{ + Pub: data.MainIdentity.EthauthKeyPair.Pub, + Priv: data.MainIdentity.EthauthKeyPair.Pvt, + }, + } + nc.StoragePath = data.StoragePath + nc.P2PPort = int(data.P2PPort) + nc.P2PExternalIP = data.P2PExternalIp + nc.P2PConnectionTimeout = time.Duration(data.P2PConnectionTimeout.Seconds) + nc.ServerPort = int(data.ServerPort) + nc.ServerAddress = data.ServerAddress + nc.NumWorkers = int(data.NumWorkers) + nc.WorkerWaitTimeMS = int(data.WorkerWaitTimeMs) + nc.EthereumNodeURL = data.EthNodeUrl + nc.EthereumContextReadWaitTimeout = time.Duration(data.EthContextReadWaitTimeout.Seconds) + nc.EthereumContextWaitTimeout = time.Duration(data.EthContextWaitTimeout.Seconds) + nc.EthereumIntervalRetry = time.Duration(data.EthIntervalRetry.Seconds) + nc.EthereumMaxRetries = int(data.EthMaxRetries) + nc.EthereumGasPrice = big.NewInt(int64(data.EthGasPrice)) + nc.EthereumGasLimit = data.EthGasLimit + nc.TxPoolAccessEnabled = data.TxPoolEnabled + nc.NetworkString = data.Network + nc.BootstrapPeers = data.BootstrapPeers + nc.NetworkID = data.NetworkId +} + // NewNodeConfig creates a new NodeConfig instance with configs func NewNodeConfig(config Configuration) *NodeConfig { + mainAccount, _ := config.GetEthereumAccount(config.GetEthereumDefaultAccountName()) + mainIdentity, _ := config.GetIdentityID() + signPub, signPriv := config.GetSigningKeyPair() + ethAuthPub, ethAuthPriv := config.GetEthAuthKeyPair() + return &NodeConfig{ + MainIdentity: TenantConfig{ + EthereumAccount: &AccountConfig{ + Address: mainAccount.Address, + Key: mainAccount.Key, + Password: mainAccount.Password, + }, + EthereumDefaultAccountName: config.GetEthereumDefaultAccountName(), + IdentityID: mainIdentity, + ReceiveEventNotificationEndpoint: config.GetReceiveEventNotificationEndpoint(), + SigningKeyPair: KeyPair{ + Pub: signPub, + Priv: signPriv, + }, + EthAuthKeyPair: KeyPair{ + Pub: ethAuthPub, + Priv: ethAuthPriv, + }, + }, StoragePath: config.GetStoragePath(), P2PPort: config.GetP2PPort(), P2PExternalIP: config.GetP2PExternalIP(), @@ -117,6 +225,46 @@ func (tc *TenantConfig) FromJSON(data []byte) error { return json.Unmarshal(data, tc) } +func (tc *TenantConfig) createProtobuf() *configpb.TenantData { + return &configpb.TenantData{ + EthAccount: &configpb.EthereumAccount{ + Address: tc.EthereumAccount.Address, + Key: tc.EthereumAccount.Key, + Password: tc.EthereumAccount.Password, + }, + EthDefaultAccountName: tc.EthereumDefaultAccountName, + ReceiveEventNotificationEndpoint: tc.ReceiveEventNotificationEndpoint, + IdentityId: hexutil.Encode(tc.IdentityID), + SigningKeyPair: &configpb.KeyPair{ + Pub: tc.SigningKeyPair.Pub, + Pvt: tc.SigningKeyPair.Priv, + }, + EthauthKeyPair: &configpb.KeyPair{ + Pub: tc.EthAuthKeyPair.Pub, + Pvt: tc.EthAuthKeyPair.Priv, + }, + } +} + +func (tc *TenantConfig) loadFromProtobuf(data *configpb.TenantData) { + tc.EthereumAccount = &AccountConfig{ + Address: data.EthAccount.Address, + Key: data.EthAccount.Key, + Password: data.EthAccount.Password, + } + tc.EthereumDefaultAccountName = data.EthDefaultAccountName + tc.IdentityID, _ = hexutil.Decode(data.IdentityId) + tc.ReceiveEventNotificationEndpoint = data.ReceiveEventNotificationEndpoint + tc.SigningKeyPair = KeyPair{ + Pub: data.SigningKeyPair.Pub, + Priv: data.SigningKeyPair.Pvt, + } + tc.EthAuthKeyPair = KeyPair{ + Pub: data.EthauthKeyPair.Pub, + Priv: data.EthauthKeyPair.Pvt, + } +} + // NewTenantConfig creates a new TenantConfig instance with configs func NewTenantConfig(ethAccountName string, config Configuration) (*TenantConfig, error) { id, err := config.GetIdentityID() diff --git a/config/model_test.go b/config/model_test.go index b7b52a56c..abbbbb87e 100644 --- a/config/model_test.go +++ b/config/model_test.go @@ -5,11 +5,14 @@ package config import ( "testing" + "github.com/ethereum/go-ethereum/common/hexutil" + "math/big" "time" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -176,6 +179,13 @@ func TestNewNodeConfig(t *testing.T) { c.On("GetWorkerWaitTimeMS").Return(1).Once() c.On("GetEthereumNodeURL").Return("dummyNode").Once() + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetSigningKeyPair").Return("pub", "priv").Once() + c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() + c.On("GetEthereumAccount", "dummyAcc").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() + c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() c.On("GetEthereumIntervalRetry").Return(time.Second).Once() @@ -204,3 +214,74 @@ func TestNewTenantConfig(t *testing.T) { NewTenantConfig("name", c) c.AssertExpectations(t) } + +func TestNodeConfigProtobuf(t *testing.T) { + c := &mockConfig{} + c.On("GetStoragePath").Return("dummyStorage").Once() + c.On("GetP2PPort").Return(30000).Once() + c.On("GetP2PExternalIP").Return("ip").Once() + c.On("GetP2PConnectionTimeout").Return(time.Second).Once() + + c.On("GetServerPort").Return(8080).Once() + c.On("GetServerAddress").Return("dummyServer").Once() + c.On("GetNumWorkers").Return(2).Once() + c.On("GetWorkerWaitTimeMS").Return(1).Once() + c.On("GetEthereumNodeURL").Return("dummyNode").Once() + + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetSigningKeyPair").Return("pub", "priv").Once() + c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() + c.On("GetEthereumAccount", "dummyAcc").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() + + c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumIntervalRetry").Return(time.Second).Once() + c.On("GetEthereumMaxRetries").Return(1).Once() + c.On("GetEthereumGasPrice").Return(big.NewInt(1)).Once() + + c.On("GetEthereumGasLimit").Return(uint64(100)).Once() + c.On("GetTxPoolAccessEnabled").Return(true).Once() + c.On("GetNetworkString").Return("somehill").Once() + c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() + + c.On("GetNetworkID").Return(uint32(1)).Once() + nc := NewNodeConfig(c) + c.AssertExpectations(t) + + ncpb := nc.createProtobuf() + assert.Equal(t, nc.StoragePath, ncpb.StoragePath) + assert.Equal(t, nc.ServerPort, int(ncpb.ServerPort)) + assert.Equal(t, hexutil.Encode(nc.MainIdentity.IdentityID), ncpb.MainIdentity.IdentityId) + + ncCopy := new(NodeConfig) + ncCopy.loadFromProtobuf(ncpb) + assert.Equal(t, ncpb.StoragePath, ncCopy.StoragePath) + assert.Equal(t, int(ncpb.ServerPort), ncCopy.ServerPort) + assert.Equal(t, ncpb.MainIdentity.IdentityId, hexutil.Encode(ncCopy.MainIdentity.IdentityID)) +} + +func TestTenantConfigProtobuf(t *testing.T) { + c := &mockConfig{} + c.On("GetEthereumAccount", "name").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetSigningKeyPair").Return("pub", "priv").Once() + c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + tc, err := NewTenantConfig("name", c) + assert.Nil(t, err) + c.AssertExpectations(t) + + tcpb := tc.createProtobuf() + assert.Equal(t, tc.ReceiveEventNotificationEndpoint, tcpb.ReceiveEventNotificationEndpoint) + assert.Equal(t, hexutil.Encode(tc.IdentityID), tcpb.IdentityId) + assert.Equal(t, tc.SigningKeyPair.Priv, tcpb.SigningKeyPair.Pvt) + + tcCopy := new(TenantConfig) + tcCopy.loadFromProtobuf(tcpb) + assert.Equal(t, tcpb.ReceiveEventNotificationEndpoint, tcCopy.ReceiveEventNotificationEndpoint) + assert.Equal(t, tcpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) + assert.Equal(t, tcpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) +} diff --git a/config/repository_test.go b/config/repository_test.go index f54ba00ee..ba0439d29 100644 --- a/config/repository_test.go +++ b/config/repository_test.go @@ -7,22 +7,46 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) +var dbFiles []string +var ctx = map[string]interface{}{} +var cfg Configuration + +func cleanupDBFiles() { + for _, db := range dbFiles { + err := os.RemoveAll(db) + if err != nil { + log.Warningf("Cleanup warn: %v", err) + } + } +} + func getRandomStorage() (Repository, string, error) { randomPath := storage.GetRandomTestStoragePath() db, err := storage.NewLevelDBStorage(randomPath) if err != nil { return nil, "", err } + dbFiles = append(dbFiles, randomPath) return NewDBRepository(storage.NewLevelDBRepository(db)), randomPath, nil } func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(Configuration) result := m.Run() + cleanupDBFiles() os.Exit(result) } diff --git a/config/service.go b/config/service.go new file mode 100644 index 000000000..aa076a61d --- /dev/null +++ b/config/service.go @@ -0,0 +1,59 @@ +package config + +// Service exposes functions over the config objects +type Service interface { + GetConfig() (*NodeConfig, error) + GetTenant(identifier []byte) (*TenantConfig, error) + GetAllTenants() ([]*TenantConfig, error) + CreateConfig(data *NodeConfig) (*NodeConfig, error) + CreateTenant(data *TenantConfig) (*TenantConfig, error) + UpdateConfig(data *NodeConfig) (*NodeConfig, error) + UpdateTenant(data *TenantConfig) (*TenantConfig, error) + DeleteConfig() error + DeleteTenant(identifier []byte) error +} + +type service struct { + repo Repository +} + +// DefaultService returns an implementation of the config.Service +func DefaultService(repository Repository) Service { + return &service{repo: repository} +} + +func (s service) GetConfig() (*NodeConfig, error) { + return s.repo.GetConfig() +} + +func (s service) GetTenant(identifier []byte) (*TenantConfig, error) { + return s.repo.GetTenant(identifier) +} + +func (s service) GetAllTenants() ([]*TenantConfig, error) { + return s.repo.GetAllTenants() +} + +func (s service) CreateConfig(data *NodeConfig) (*NodeConfig, error) { + return data, s.repo.CreateConfig(data) +} + +func (s service) CreateTenant(data *TenantConfig) (*TenantConfig, error) { + return data, s.repo.CreateTenant(data.IdentityID, data) +} + +func (s service) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { + return data, s.repo.UpdateConfig(data) +} + +func (s service) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { + return data, s.repo.UpdateTenant(data.IdentityID, data) +} + +func (s service) DeleteConfig() error { + return s.repo.DeleteConfig() +} + +func (s service) DeleteTenant(identifier []byte) error { + return s.repo.DeleteTenant(identifier) +} diff --git a/config/service_test.go b/config/service_test.go new file mode 100644 index 000000000..ce9338d51 --- /dev/null +++ b/config/service_test.go @@ -0,0 +1,172 @@ +// +build unit + +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestService_GetConfig_NoConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + cfg, err := svc.GetConfig() + assert.NotNil(t, err) + assert.Nil(t, cfg) +} + +func TestService_GetConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + nodeCfg := NewNodeConfig(cfg) + err = repo.CreateConfig(nodeCfg) + assert.Nil(t, err) + cfg, err := svc.GetConfig() + assert.Nil(t, err) + assert.NotNil(t, cfg) +} + +func TestService_GetTenant_NoTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + cfg, err := svc.GetTenant([]byte("0x123456789")) + assert.NotNil(t, err) + assert.Nil(t, cfg) +} + +func TestService_GetTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + tenantCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + err = repo.CreateTenant(tenantCfg.IdentityID, tenantCfg) + assert.Nil(t, err) + cfg, err := svc.GetTenant(tenantCfg.IdentityID) + assert.Nil(t, err) + assert.NotNil(t, cfg) +} + +func TestService_CreateConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + nodeCfg := NewNodeConfig(cfg) + cfgpb, err := svc.CreateConfig(nodeCfg) + assert.Nil(t, err) + assert.Equal(t, nodeCfg.StoragePath, cfgpb.StoragePath) + + //Config already exists + _, err = svc.CreateConfig(nodeCfg) + assert.NotNil(t, err) +} + +func TestService_CreateTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + tenantCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + newCfg, err := svc.CreateTenant(tenantCfg) + assert.Nil(t, err) + assert.Equal(t, tenantCfg.IdentityID, newCfg.IdentityID) + + //Tenant already exists + _, err = svc.CreateTenant(tenantCfg) + assert.NotNil(t, err) +} + +func TestService_UpdateConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + nodeCfg := NewNodeConfig(cfg) + + //Config doesn't exists + _, err = svc.UpdateConfig(nodeCfg) + assert.NotNil(t, err) + + newCfg, err := svc.CreateConfig(nodeCfg) + assert.Nil(t, err) + assert.Equal(t, nodeCfg.StoragePath, newCfg.StoragePath) + + nodeCfg.NetworkString = "something" + newCfg, err = svc.UpdateConfig(nodeCfg) + assert.Nil(t, err) + assert.Equal(t, nodeCfg.NetworkString, newCfg.NetworkString) +} + +func TestService_UpdateTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + tenantCfg, err := NewTenantConfig("main", cfg) + + // Tenant doesn't exist + newCfg, err := svc.UpdateTenant(tenantCfg) + assert.NotNil(t, err) + + newCfg, err = svc.CreateTenant(tenantCfg) + assert.Nil(t, err) + assert.Equal(t, tenantCfg.IdentityID, newCfg.IdentityID) + + tenantCfg.EthereumDefaultAccountName = "other" + newCfg, err = svc.UpdateTenant(tenantCfg) + assert.Nil(t, err) + assert.Equal(t, tenantCfg.EthereumDefaultAccountName, newCfg.EthereumDefaultAccountName) +} + +func TestService_DeleteConfig(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterConfig(&NodeConfig{}) + svc := DefaultService(repo) + + //No config, no error + err = svc.DeleteConfig() + assert.Nil(t, err) + + nodeCfg := NewNodeConfig(cfg) + _, err = svc.CreateConfig(nodeCfg) + assert.Nil(t, err) + + err = svc.DeleteConfig() + assert.Nil(t, err) + + _, err = svc.GetConfig() + assert.NotNil(t, err) +} + +func TestService_DeleteTenant(t *testing.T) { + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo) + tenantCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + + //No config, no error + err = svc.DeleteTenant(tenantCfg.IdentityID) + assert.Nil(t, err) + + _, err = svc.CreateTenant(tenantCfg) + assert.Nil(t, err) + + err = svc.DeleteTenant(tenantCfg.IdentityID) + assert.Nil(t, err) + + _, err = svc.GetTenant(tenantCfg.IdentityID) + assert.NotNil(t, err) +} diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto new file mode 100644 index 000000000..675843b1c --- /dev/null +++ b/protobufs/config/service.proto @@ -0,0 +1,149 @@ +syntax = "proto3"; + +package config; + +option go_package = "configpb"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option java_package = "com.config"; + +import "google/api/annotations.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; +import "protoc-gen-swagger/options/annotations.proto"; + +// ConfigService allows to manage the node and tenant configuration of the node +service ConfigService { + rpc GetConfig(google.protobuf.Empty) returns (ConfigData) { + option (google.api.http) = { + get: "/config/node" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get Node Config" + }; + } + rpc GetTenant(GetTenantRequest) returns (TenantData) { + option (google.api.http) = { + get: "/config/tenant/{identifier}" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get Tenant Config" + }; + } + rpc GetAllTenants(google.protobuf.Empty) returns (GetAllTenantResponse) { + option (google.api.http) = { + get: "/config/tenant/list" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get All Tenant Configs" + }; + } + rpc CreateConfig(ConfigData) returns (ConfigData) { + option (google.api.http) = { + post: "/config/node" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Creates node config data" + }; + } + rpc CreateTenant(TenantData) returns (TenantData) { + option (google.api.http) = { + post: "/config/tenant" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Creates tenant config data" + }; + } + rpc UpdateConfig(ConfigData) returns (ConfigData) { + option (google.api.http) = { + put: "/config/node" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Updates node config" + }; + } + rpc UpdateTenant(UpdateTenantRequest) returns (TenantData) { + option (google.api.http) = { + put: "/config/tenant/{identifier}" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Updates tenant config" + }; + } + rpc DeleteConfig(google.protobuf.Empty) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/config/node" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Deletes node config" + }; + } + rpc DeleteTenant(GetTenantRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/config/tenant/{identifier}" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Deletes tenant config" + }; + } +} + +message GetTenantRequest { + string identifier = 1; +} + +message GetAllTenantResponse { + repeated TenantData data = 1; +} + +message UpdateTenantRequest { + string identifier = 1; + TenantData data = 2; +} + +message EthereumAccount { + string address = 1; + string key = 2; + string password = 3; +} + +message KeyPair { + string pub = 1; + string pvt = 2; +} + +message TenantData { + EthereumAccount eth_account = 1; + string eth_default_account_name = 2; + string receive_event_notification_endpoint = 3; + string identity_id = 4; + KeyPair signing_key_pair = 5; + KeyPair ethauth_key_pair = 6; +} + +message ConfigData { + string storage_path = 1; + int32 p2p_port = 2; + string p2p_external_ip = 3; + google.protobuf.Duration p2p_connection_timeout = 4; + int32 server_port = 5; + string server_address = 6; + int32 num_workers = 7; + int32 worker_wait_time_ms = 8; + string eth_node_url = 9; + google.protobuf.Duration eth_context_read_wait_timeout = 10; + google.protobuf.Duration eth_context_wait_timeout = 11; + google.protobuf.Duration eth_interval_retry = 12; + uint32 eth_max_retries = 13; + uint64 eth_gas_price = 14; + uint64 eth_gas_limit = 15; + bool tx_pool_enabled = 16; + string network = 17; + repeated string bootstrap_peers = 18; + uint32 network_id = 19; + TenantData main_identity = 20; +} diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go new file mode 100644 index 000000000..cd9f37f8c --- /dev/null +++ b/protobufs/gen/go/config/service.pb.go @@ -0,0 +1,948 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: config/service.proto + +package configpb + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import duration "github.com/golang/protobuf/ptypes/duration" +import empty "github.com/golang/protobuf/ptypes/empty" +import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" +import _ "google.golang.org/genproto/googleapis/api/annotations" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type GetTenantRequest struct { + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } +func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } +func (*GetTenantRequest) ProtoMessage() {} +func (*GetTenantRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{0} +} +func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) +} +func (m *GetTenantRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTenantRequest.Marshal(b, m, deterministic) +} +func (dst *GetTenantRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTenantRequest.Merge(dst, src) +} +func (m *GetTenantRequest) XXX_Size() int { + return xxx_messageInfo_GetTenantRequest.Size(m) +} +func (m *GetTenantRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTenantRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTenantRequest proto.InternalMessageInfo + +func (m *GetTenantRequest) GetIdentifier() string { + if m != nil { + return m.Identifier + } + return "" +} + +type GetAllTenantResponse struct { + Data []*TenantData `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } +func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } +func (*GetAllTenantResponse) ProtoMessage() {} +func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{1} +} +func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) +} +func (m *GetAllTenantResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllTenantResponse.Marshal(b, m, deterministic) +} +func (dst *GetAllTenantResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllTenantResponse.Merge(dst, src) +} +func (m *GetAllTenantResponse) XXX_Size() int { + return xxx_messageInfo_GetAllTenantResponse.Size(m) +} +func (m *GetAllTenantResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllTenantResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllTenantResponse proto.InternalMessageInfo + +func (m *GetAllTenantResponse) GetData() []*TenantData { + if m != nil { + return m.Data + } + return nil +} + +type UpdateTenantRequest struct { + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Data *TenantData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } +func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } +func (*UpdateTenantRequest) ProtoMessage() {} +func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{2} +} +func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) +} +func (m *UpdateTenantRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateTenantRequest.Marshal(b, m, deterministic) +} +func (dst *UpdateTenantRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateTenantRequest.Merge(dst, src) +} +func (m *UpdateTenantRequest) XXX_Size() int { + return xxx_messageInfo_UpdateTenantRequest.Size(m) +} +func (m *UpdateTenantRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateTenantRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateTenantRequest proto.InternalMessageInfo + +func (m *UpdateTenantRequest) GetIdentifier() string { + if m != nil { + return m.Identifier + } + return "" +} + +func (m *UpdateTenantRequest) GetData() *TenantData { + if m != nil { + return m.Data + } + return nil +} + +type EthereumAccount struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } +func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } +func (*EthereumAccount) ProtoMessage() {} +func (*EthereumAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{3} +} +func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) +} +func (m *EthereumAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumAccount.Marshal(b, m, deterministic) +} +func (dst *EthereumAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumAccount.Merge(dst, src) +} +func (m *EthereumAccount) XXX_Size() int { + return xxx_messageInfo_EthereumAccount.Size(m) +} +func (m *EthereumAccount) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumAccount proto.InternalMessageInfo + +func (m *EthereumAccount) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *EthereumAccount) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *EthereumAccount) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +type KeyPair struct { + Pub string `protobuf:"bytes,1,opt,name=pub,proto3" json:"pub,omitempty"` + Pvt string `protobuf:"bytes,2,opt,name=pvt,proto3" json:"pvt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KeyPair) Reset() { *m = KeyPair{} } +func (m *KeyPair) String() string { return proto.CompactTextString(m) } +func (*KeyPair) ProtoMessage() {} +func (*KeyPair) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{4} +} +func (m *KeyPair) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KeyPair.Unmarshal(m, b) +} +func (m *KeyPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KeyPair.Marshal(b, m, deterministic) +} +func (dst *KeyPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyPair.Merge(dst, src) +} +func (m *KeyPair) XXX_Size() int { + return xxx_messageInfo_KeyPair.Size(m) +} +func (m *KeyPair) XXX_DiscardUnknown() { + xxx_messageInfo_KeyPair.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyPair proto.InternalMessageInfo + +func (m *KeyPair) GetPub() string { + if m != nil { + return m.Pub + } + return "" +} + +func (m *KeyPair) GetPvt() string { + if m != nil { + return m.Pvt + } + return "" +} + +type TenantData struct { + EthAccount *EthereumAccount `protobuf:"bytes,1,opt,name=eth_account,json=ethAccount,proto3" json:"eth_account,omitempty"` + EthDefaultAccountName string `protobuf:"bytes,2,opt,name=eth_default_account_name,json=ethDefaultAccountName,proto3" json:"eth_default_account_name,omitempty"` + ReceiveEventNotificationEndpoint string `protobuf:"bytes,3,opt,name=receive_event_notification_endpoint,json=receiveEventNotificationEndpoint,proto3" json:"receive_event_notification_endpoint,omitempty"` + IdentityId string `protobuf:"bytes,4,opt,name=identity_id,json=identityId,proto3" json:"identity_id,omitempty"` + SigningKeyPair *KeyPair `protobuf:"bytes,5,opt,name=signing_key_pair,json=signingKeyPair,proto3" json:"signing_key_pair,omitempty"` + EthauthKeyPair *KeyPair `protobuf:"bytes,6,opt,name=ethauth_key_pair,json=ethauthKeyPair,proto3" json:"ethauth_key_pair,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TenantData) Reset() { *m = TenantData{} } +func (m *TenantData) String() string { return proto.CompactTextString(m) } +func (*TenantData) ProtoMessage() {} +func (*TenantData) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{5} +} +func (m *TenantData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TenantData.Unmarshal(m, b) +} +func (m *TenantData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TenantData.Marshal(b, m, deterministic) +} +func (dst *TenantData) XXX_Merge(src proto.Message) { + xxx_messageInfo_TenantData.Merge(dst, src) +} +func (m *TenantData) XXX_Size() int { + return xxx_messageInfo_TenantData.Size(m) +} +func (m *TenantData) XXX_DiscardUnknown() { + xxx_messageInfo_TenantData.DiscardUnknown(m) +} + +var xxx_messageInfo_TenantData proto.InternalMessageInfo + +func (m *TenantData) GetEthAccount() *EthereumAccount { + if m != nil { + return m.EthAccount + } + return nil +} + +func (m *TenantData) GetEthDefaultAccountName() string { + if m != nil { + return m.EthDefaultAccountName + } + return "" +} + +func (m *TenantData) GetReceiveEventNotificationEndpoint() string { + if m != nil { + return m.ReceiveEventNotificationEndpoint + } + return "" +} + +func (m *TenantData) GetIdentityId() string { + if m != nil { + return m.IdentityId + } + return "" +} + +func (m *TenantData) GetSigningKeyPair() *KeyPair { + if m != nil { + return m.SigningKeyPair + } + return nil +} + +func (m *TenantData) GetEthauthKeyPair() *KeyPair { + if m != nil { + return m.EthauthKeyPair + } + return nil +} + +type ConfigData struct { + StoragePath string `protobuf:"bytes,1,opt,name=storage_path,json=storagePath,proto3" json:"storage_path,omitempty"` + P2PPort int32 `protobuf:"varint,2,opt,name=p2p_port,json=p2pPort,proto3" json:"p2p_port,omitempty"` + P2PExternalIp string `protobuf:"bytes,3,opt,name=p2p_external_ip,json=p2pExternalIp,proto3" json:"p2p_external_ip,omitempty"` + P2PConnectionTimeout *duration.Duration `protobuf:"bytes,4,opt,name=p2p_connection_timeout,json=p2pConnectionTimeout,proto3" json:"p2p_connection_timeout,omitempty"` + ServerPort int32 `protobuf:"varint,5,opt,name=server_port,json=serverPort,proto3" json:"server_port,omitempty"` + ServerAddress string `protobuf:"bytes,6,opt,name=server_address,json=serverAddress,proto3" json:"server_address,omitempty"` + NumWorkers int32 `protobuf:"varint,7,opt,name=num_workers,json=numWorkers,proto3" json:"num_workers,omitempty"` + WorkerWaitTimeMs int32 `protobuf:"varint,8,opt,name=worker_wait_time_ms,json=workerWaitTimeMs,proto3" json:"worker_wait_time_ms,omitempty"` + EthNodeUrl string `protobuf:"bytes,9,opt,name=eth_node_url,json=ethNodeUrl,proto3" json:"eth_node_url,omitempty"` + EthContextReadWaitTimeout *duration.Duration `protobuf:"bytes,10,opt,name=eth_context_read_wait_timeout,json=ethContextReadWaitTimeout,proto3" json:"eth_context_read_wait_timeout,omitempty"` + EthContextWaitTimeout *duration.Duration `protobuf:"bytes,11,opt,name=eth_context_wait_timeout,json=ethContextWaitTimeout,proto3" json:"eth_context_wait_timeout,omitempty"` + EthIntervalRetry *duration.Duration `protobuf:"bytes,12,opt,name=eth_interval_retry,json=ethIntervalRetry,proto3" json:"eth_interval_retry,omitempty"` + EthMaxRetries uint32 `protobuf:"varint,13,opt,name=eth_max_retries,json=ethMaxRetries,proto3" json:"eth_max_retries,omitempty"` + EthGasPrice uint64 `protobuf:"varint,14,opt,name=eth_gas_price,json=ethGasPrice,proto3" json:"eth_gas_price,omitempty"` + EthGasLimit uint64 `protobuf:"varint,15,opt,name=eth_gas_limit,json=ethGasLimit,proto3" json:"eth_gas_limit,omitempty"` + TxPoolEnabled bool `protobuf:"varint,16,opt,name=tx_pool_enabled,json=txPoolEnabled,proto3" json:"tx_pool_enabled,omitempty"` + Network string `protobuf:"bytes,17,opt,name=network,proto3" json:"network,omitempty"` + BootstrapPeers []string `protobuf:"bytes,18,rep,name=bootstrap_peers,json=bootstrapPeers,proto3" json:"bootstrap_peers,omitempty"` + NetworkId uint32 `protobuf:"varint,19,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` + MainIdentity *TenantData `protobuf:"bytes,20,opt,name=main_identity,json=mainIdentity,proto3" json:"main_identity,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConfigData) Reset() { *m = ConfigData{} } +func (m *ConfigData) String() string { return proto.CompactTextString(m) } +func (*ConfigData) ProtoMessage() {} +func (*ConfigData) Descriptor() ([]byte, []int) { + return fileDescriptor_service_5680e2fa0c56bd70, []int{6} +} +func (m *ConfigData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ConfigData.Unmarshal(m, b) +} +func (m *ConfigData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ConfigData.Marshal(b, m, deterministic) +} +func (dst *ConfigData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConfigData.Merge(dst, src) +} +func (m *ConfigData) XXX_Size() int { + return xxx_messageInfo_ConfigData.Size(m) +} +func (m *ConfigData) XXX_DiscardUnknown() { + xxx_messageInfo_ConfigData.DiscardUnknown(m) +} + +var xxx_messageInfo_ConfigData proto.InternalMessageInfo + +func (m *ConfigData) GetStoragePath() string { + if m != nil { + return m.StoragePath + } + return "" +} + +func (m *ConfigData) GetP2PPort() int32 { + if m != nil { + return m.P2PPort + } + return 0 +} + +func (m *ConfigData) GetP2PExternalIp() string { + if m != nil { + return m.P2PExternalIp + } + return "" +} + +func (m *ConfigData) GetP2PConnectionTimeout() *duration.Duration { + if m != nil { + return m.P2PConnectionTimeout + } + return nil +} + +func (m *ConfigData) GetServerPort() int32 { + if m != nil { + return m.ServerPort + } + return 0 +} + +func (m *ConfigData) GetServerAddress() string { + if m != nil { + return m.ServerAddress + } + return "" +} + +func (m *ConfigData) GetNumWorkers() int32 { + if m != nil { + return m.NumWorkers + } + return 0 +} + +func (m *ConfigData) GetWorkerWaitTimeMs() int32 { + if m != nil { + return m.WorkerWaitTimeMs + } + return 0 +} + +func (m *ConfigData) GetEthNodeUrl() string { + if m != nil { + return m.EthNodeUrl + } + return "" +} + +func (m *ConfigData) GetEthContextReadWaitTimeout() *duration.Duration { + if m != nil { + return m.EthContextReadWaitTimeout + } + return nil +} + +func (m *ConfigData) GetEthContextWaitTimeout() *duration.Duration { + if m != nil { + return m.EthContextWaitTimeout + } + return nil +} + +func (m *ConfigData) GetEthIntervalRetry() *duration.Duration { + if m != nil { + return m.EthIntervalRetry + } + return nil +} + +func (m *ConfigData) GetEthMaxRetries() uint32 { + if m != nil { + return m.EthMaxRetries + } + return 0 +} + +func (m *ConfigData) GetEthGasPrice() uint64 { + if m != nil { + return m.EthGasPrice + } + return 0 +} + +func (m *ConfigData) GetEthGasLimit() uint64 { + if m != nil { + return m.EthGasLimit + } + return 0 +} + +func (m *ConfigData) GetTxPoolEnabled() bool { + if m != nil { + return m.TxPoolEnabled + } + return false +} + +func (m *ConfigData) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +func (m *ConfigData) GetBootstrapPeers() []string { + if m != nil { + return m.BootstrapPeers + } + return nil +} + +func (m *ConfigData) GetNetworkId() uint32 { + if m != nil { + return m.NetworkId + } + return 0 +} + +func (m *ConfigData) GetMainIdentity() *TenantData { + if m != nil { + return m.MainIdentity + } + return nil +} + +func init() { + proto.RegisterType((*GetTenantRequest)(nil), "config.GetTenantRequest") + proto.RegisterType((*GetAllTenantResponse)(nil), "config.GetAllTenantResponse") + proto.RegisterType((*UpdateTenantRequest)(nil), "config.UpdateTenantRequest") + proto.RegisterType((*EthereumAccount)(nil), "config.EthereumAccount") + proto.RegisterType((*KeyPair)(nil), "config.KeyPair") + proto.RegisterType((*TenantData)(nil), "config.TenantData") + proto.RegisterType((*ConfigData)(nil), "config.ConfigData") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// ConfigServiceClient is the client API for ConfigService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ConfigServiceClient interface { + GetConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ConfigData, error) + GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*TenantData, error) + GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) + CreateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) + CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) + UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) + UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) + DeleteConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) + DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) +} + +type configServiceClient struct { + cc *grpc.ClientConn +} + +func NewConfigServiceClient(cc *grpc.ClientConn) ConfigServiceClient { + return &configServiceClient{cc} +} + +func (c *configServiceClient) GetConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ConfigData, error) { + out := new(ConfigData) + err := c.cc.Invoke(ctx, "/config.ConfigService/GetConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*TenantData, error) { + out := new(TenantData) + err := c.cc.Invoke(ctx, "/config.ConfigService/GetTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) { + out := new(GetAllTenantResponse) + err := c.cc.Invoke(ctx, "/config.ConfigService/GetAllTenants", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) CreateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) { + out := new(ConfigData) + err := c.cc.Invoke(ctx, "/config.ConfigService/CreateConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) { + out := new(TenantData) + err := c.cc.Invoke(ctx, "/config.ConfigService/CreateTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) { + out := new(ConfigData) + err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) { + out := new(TenantData) + err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) DeleteConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/config.ConfigService/DeleteConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *configServiceClient) DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/config.ConfigService/DeleteTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ConfigServiceServer is the server API for ConfigService service. +type ConfigServiceServer interface { + GetConfig(context.Context, *empty.Empty) (*ConfigData, error) + GetTenant(context.Context, *GetTenantRequest) (*TenantData, error) + GetAllTenants(context.Context, *empty.Empty) (*GetAllTenantResponse, error) + CreateConfig(context.Context, *ConfigData) (*ConfigData, error) + CreateTenant(context.Context, *TenantData) (*TenantData, error) + UpdateConfig(context.Context, *ConfigData) (*ConfigData, error) + UpdateTenant(context.Context, *UpdateTenantRequest) (*TenantData, error) + DeleteConfig(context.Context, *empty.Empty) (*empty.Empty, error) + DeleteTenant(context.Context, *GetTenantRequest) (*empty.Empty, error) +} + +func RegisterConfigServiceServer(s *grpc.Server, srv ConfigServiceServer) { + s.RegisterService(&_ConfigService_serviceDesc, srv) +} + +func _ConfigService_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).GetConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/GetConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).GetConfig(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_GetTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTenantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).GetTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/GetTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).GetTenant(ctx, req.(*GetTenantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_GetAllTenants_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).GetAllTenants(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/GetAllTenants", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).GetAllTenants(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_CreateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConfigData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).CreateConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/CreateConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).CreateConfig(ctx, req.(*ConfigData)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_CreateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TenantData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).CreateTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/CreateTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).CreateTenant(ctx, req.(*TenantData)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConfigData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).UpdateConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/UpdateConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).UpdateConfig(ctx, req.(*ConfigData)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_UpdateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateTenantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).UpdateTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/UpdateTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).UpdateTenant(ctx, req.(*UpdateTenantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_DeleteConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).DeleteConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/DeleteConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).DeleteConfig(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConfigService_DeleteTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTenantRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).DeleteTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/DeleteTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).DeleteTenant(ctx, req.(*GetTenantRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _ConfigService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "config.ConfigService", + HandlerType: (*ConfigServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetConfig", + Handler: _ConfigService_GetConfig_Handler, + }, + { + MethodName: "GetTenant", + Handler: _ConfigService_GetTenant_Handler, + }, + { + MethodName: "GetAllTenants", + Handler: _ConfigService_GetAllTenants_Handler, + }, + { + MethodName: "CreateConfig", + Handler: _ConfigService_CreateConfig_Handler, + }, + { + MethodName: "CreateTenant", + Handler: _ConfigService_CreateTenant_Handler, + }, + { + MethodName: "UpdateConfig", + Handler: _ConfigService_UpdateConfig_Handler, + }, + { + MethodName: "UpdateTenant", + Handler: _ConfigService_UpdateTenant_Handler, + }, + { + MethodName: "DeleteConfig", + Handler: _ConfigService_DeleteConfig_Handler, + }, + { + MethodName: "DeleteTenant", + Handler: _ConfigService_DeleteTenant_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "config/service.proto", +} + +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_5680e2fa0c56bd70) } + +var fileDescriptor_service_5680e2fa0c56bd70 = []byte{ + // 1248 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xfb, 0x6e, 0x1b, 0xc5, + 0x17, 0x96, 0x9b, 0x36, 0x97, 0xf1, 0x25, 0xc9, 0x24, 0x69, 0xb7, 0xdb, 0xa6, 0xdd, 0xdf, 0xfe, + 0x44, 0xb1, 0xaa, 0x26, 0x96, 0x0c, 0xa2, 0x2d, 0x12, 0x08, 0x37, 0x89, 0xa2, 0x08, 0x5a, 0xac, + 0xa5, 0x55, 0x05, 0x08, 0xad, 0x26, 0xde, 0x13, 0x7b, 0xd5, 0xf5, 0xcc, 0x30, 0x7b, 0x9c, 0xc4, + 0x42, 0x15, 0x82, 0x47, 0x30, 0x8f, 0xc0, 0x7f, 0xbc, 0x0e, 0xaf, 0x00, 0xef, 0x81, 0xe6, 0xb2, + 0x89, 0x1d, 0x3b, 0x89, 0xfa, 0x97, 0x3d, 0xe7, 0xf2, 0x7d, 0xe7, 0x3b, 0x73, 0x66, 0x66, 0xc9, + 0x7a, 0x47, 0xf0, 0xa3, 0xb4, 0xdb, 0xc8, 0x41, 0x1d, 0xa7, 0x1d, 0xd8, 0x96, 0x4a, 0xa0, 0xa0, + 0xf3, 0xd6, 0xea, 0xdf, 0xef, 0x0a, 0xd1, 0xcd, 0xa0, 0xc1, 0x64, 0xda, 0x60, 0x9c, 0x0b, 0x64, + 0x98, 0x0a, 0x9e, 0xdb, 0x28, 0xff, 0x81, 0xf3, 0x9a, 0xd5, 0xe1, 0xe0, 0xa8, 0x91, 0x0c, 0x94, + 0x09, 0x70, 0xfe, 0x7b, 0x17, 0xfd, 0xd0, 0x97, 0x38, 0x74, 0xce, 0x27, 0xe6, 0xa7, 0xb3, 0xd5, + 0x05, 0xbe, 0x95, 0x9f, 0xb0, 0x6e, 0x17, 0x54, 0x43, 0x48, 0x03, 0x3f, 0x4d, 0x15, 0x36, 0xc9, + 0xca, 0x3e, 0xe0, 0x6b, 0xe0, 0x8c, 0x63, 0x04, 0x3f, 0x0f, 0x20, 0x47, 0xfa, 0x80, 0x90, 0x34, + 0x01, 0x8e, 0xe9, 0x51, 0x0a, 0xca, 0x2b, 0x05, 0xa5, 0xfa, 0x52, 0x34, 0x66, 0x09, 0xbf, 0x24, + 0xeb, 0xfb, 0x80, 0xad, 0x2c, 0x2b, 0xd2, 0x72, 0x29, 0x78, 0x0e, 0xf4, 0x11, 0xb9, 0x99, 0x30, + 0x64, 0x5e, 0x29, 0x98, 0xab, 0x97, 0x9b, 0x74, 0xdb, 0x6a, 0xdd, 0xb6, 0x51, 0xbb, 0x0c, 0x59, + 0x64, 0xfc, 0xe1, 0x4f, 0x64, 0xed, 0x8d, 0x4c, 0x18, 0xc2, 0x07, 0xd1, 0x9e, 0xc1, 0xdf, 0x08, + 0x4a, 0x57, 0xc2, 0x7f, 0x4f, 0x96, 0xf7, 0xb0, 0x07, 0x0a, 0x06, 0xfd, 0x56, 0xa7, 0x23, 0x06, + 0x1c, 0xa9, 0x47, 0x16, 0x58, 0x92, 0x28, 0xc8, 0x73, 0x87, 0x5b, 0x2c, 0xe9, 0x0a, 0x99, 0x7b, + 0x07, 0x43, 0x83, 0xb9, 0x14, 0xe9, 0xbf, 0xd4, 0x27, 0x8b, 0x92, 0xe5, 0xf9, 0x89, 0x50, 0x89, + 0x37, 0x67, 0xcc, 0x67, 0xeb, 0x70, 0x8b, 0x2c, 0x7c, 0x0d, 0xc3, 0x36, 0x4b, 0x95, 0x4e, 0x94, + 0x83, 0x43, 0x07, 0xa7, 0xff, 0x1a, 0xcb, 0x31, 0x16, 0x50, 0xf2, 0x18, 0xc3, 0x7f, 0x6f, 0x10, + 0x72, 0x5e, 0x1e, 0x7d, 0x46, 0xca, 0x80, 0xbd, 0x98, 0xd9, 0xa2, 0x4c, 0x6a, 0xb9, 0x79, 0xa7, + 0xd0, 0x71, 0xa1, 0xe6, 0x88, 0x00, 0xf6, 0x8a, 0xfa, 0x9f, 0x12, 0x4f, 0x67, 0x26, 0x70, 0xc4, + 0x06, 0x19, 0x16, 0x08, 0x31, 0x67, 0x7d, 0x70, 0x7c, 0x1b, 0x80, 0xbd, 0x5d, 0xeb, 0x76, 0x49, + 0xaf, 0x58, 0x1f, 0xe8, 0x4b, 0xf2, 0x7f, 0x05, 0x1d, 0x48, 0x8f, 0x21, 0x86, 0x63, 0xd0, 0x29, + 0x42, 0x77, 0xb3, 0x63, 0x66, 0x20, 0x06, 0x9e, 0x48, 0x91, 0x72, 0x74, 0x3a, 0x03, 0x17, 0xba, + 0xa7, 0x23, 0x5f, 0x8d, 0x05, 0xee, 0xb9, 0x38, 0xfa, 0x90, 0x94, 0xed, 0x86, 0xe0, 0x30, 0x4e, + 0x13, 0xef, 0xe6, 0xf8, 0x1e, 0xe1, 0xf0, 0x20, 0xa1, 0xcf, 0xc9, 0x4a, 0x9e, 0x76, 0x79, 0xca, + 0xbb, 0xf1, 0x3b, 0x18, 0xc6, 0x92, 0xa5, 0xca, 0xbb, 0x65, 0x74, 0x2e, 0x17, 0x3a, 0x5d, 0x03, + 0xa3, 0x9a, 0x0b, 0x2c, 0x1a, 0xfa, 0x9c, 0xac, 0x00, 0xf6, 0xd8, 0x00, 0x7b, 0xe7, 0xa9, 0xf3, + 0x97, 0xa4, 0xba, 0x40, 0xb7, 0x0e, 0xff, 0x5a, 0x20, 0x64, 0xc7, 0x84, 0x98, 0x3e, 0xff, 0x8f, + 0x54, 0x72, 0x14, 0x8a, 0x75, 0x21, 0x96, 0x0c, 0x7b, 0x6e, 0x8f, 0xca, 0xce, 0xd6, 0x66, 0xd8, + 0xa3, 0x77, 0xc9, 0xa2, 0x6c, 0xca, 0x58, 0x0a, 0x65, 0x37, 0xec, 0x56, 0xb4, 0x20, 0x9b, 0xb2, + 0x2d, 0x14, 0xd2, 0x47, 0x64, 0x59, 0xbb, 0xe0, 0x14, 0x41, 0x71, 0x96, 0xc5, 0xa9, 0x74, 0xed, + 0xa9, 0xca, 0xa6, 0xdc, 0x73, 0xd6, 0x03, 0x49, 0xbf, 0x25, 0xb7, 0x75, 0x5c, 0x47, 0x70, 0x0e, + 0x1d, 0xd3, 0x4e, 0x4c, 0xfb, 0x20, 0x06, 0x68, 0xda, 0x52, 0x6e, 0xde, 0xdd, 0xb6, 0xa7, 0x74, + 0xbb, 0x38, 0xa5, 0xdb, 0xbb, 0xee, 0x14, 0x47, 0xeb, 0xb2, 0x29, 0x77, 0xce, 0xf2, 0x5e, 0xdb, + 0x34, 0xdd, 0x5c, 0x7d, 0x59, 0x80, 0xb2, 0x65, 0xdd, 0x32, 0x65, 0x11, 0x6b, 0x32, 0x95, 0x7d, + 0x44, 0x6a, 0x2e, 0xa0, 0x18, 0xe6, 0x79, 0x5b, 0x98, 0xb5, 0xb6, 0xdc, 0x48, 0x3f, 0x24, 0x65, + 0x3e, 0xe8, 0xc7, 0x27, 0x42, 0xbd, 0x03, 0x95, 0x7b, 0x0b, 0x16, 0x87, 0x0f, 0xfa, 0x6f, 0xad, + 0x85, 0x6e, 0x91, 0x35, 0xeb, 0x8c, 0x4f, 0x58, 0x8a, 0xa6, 0xec, 0xb8, 0x9f, 0x7b, 0x8b, 0x26, + 0x70, 0xc5, 0xba, 0xde, 0xb2, 0x14, 0x75, 0x61, 0x2f, 0x73, 0x1a, 0x90, 0x8a, 0x1e, 0x3e, 0x2e, + 0x12, 0x88, 0x07, 0x2a, 0xf3, 0x96, 0xec, 0xae, 0x03, 0xf6, 0x5e, 0x89, 0x04, 0xde, 0xa8, 0x8c, + 0xfe, 0x48, 0x36, 0x75, 0x44, 0x47, 0x70, 0x84, 0x53, 0x8c, 0x15, 0xb0, 0xe4, 0x1c, 0x5a, 0x77, + 0x84, 0x5c, 0xd7, 0x91, 0xbb, 0x80, 0xbd, 0x1d, 0x9b, 0x1e, 0x01, 0x4b, 0x0a, 0x76, 0xdd, 0x96, + 0xc8, 0xce, 0x7e, 0x01, 0x3e, 0x81, 0x5b, 0xbe, 0x0e, 0x77, 0xe3, 0x1c, 0x77, 0x1c, 0x73, 0x9f, + 0x50, 0x8d, 0x99, 0x72, 0x04, 0x75, 0xcc, 0xb2, 0x58, 0x01, 0xaa, 0xa1, 0x57, 0xb9, 0x0e, 0x4d, + 0x0f, 0xe8, 0x81, 0xcb, 0x89, 0x74, 0x8a, 0x1e, 0x16, 0x0d, 0xd4, 0x67, 0xa7, 0x06, 0x23, 0x85, + 0xdc, 0xab, 0x06, 0xa5, 0x7a, 0x35, 0xaa, 0x02, 0xf6, 0x5e, 0xb2, 0xd3, 0xc8, 0x1a, 0x69, 0x48, + 0xb4, 0x21, 0xee, 0xb2, 0x3c, 0x96, 0x2a, 0xed, 0x80, 0x57, 0x0b, 0x4a, 0xf5, 0x9b, 0x91, 0xbe, + 0x0f, 0xf6, 0x59, 0xde, 0xd6, 0xa6, 0xf1, 0x98, 0x2c, 0xed, 0xa7, 0xe8, 0x2d, 0x8f, 0xc7, 0x7c, + 0xa3, 0x4d, 0x9a, 0x0f, 0x4f, 0x63, 0x29, 0x44, 0x16, 0x03, 0x67, 0x87, 0x19, 0x24, 0xde, 0x4a, + 0x50, 0xaa, 0x2f, 0x46, 0x55, 0x3c, 0x6d, 0x0b, 0x91, 0xed, 0x59, 0xa3, 0xbe, 0xf0, 0x38, 0xa0, + 0xde, 0x4a, 0x6f, 0xd5, 0x5e, 0x78, 0x6e, 0x49, 0x3f, 0x26, 0xcb, 0x87, 0x42, 0x60, 0x8e, 0x8a, + 0xc9, 0x58, 0x82, 0x9e, 0x10, 0x1a, 0xcc, 0xd5, 0x97, 0xa2, 0xda, 0x99, 0xb9, 0xad, 0xad, 0x74, + 0x93, 0x10, 0x97, 0xa3, 0x8f, 0xfa, 0x9a, 0x51, 0xb5, 0xe4, 0x2c, 0x07, 0x09, 0x7d, 0x4a, 0xaa, + 0x7d, 0x96, 0xf2, 0xb8, 0x38, 0xfc, 0xde, 0xfa, 0xa5, 0xd7, 0x72, 0x45, 0x07, 0x1e, 0xb8, 0xb8, + 0xe6, 0x9f, 0x8b, 0xa4, 0x6a, 0x0f, 0xeb, 0x77, 0xf6, 0x69, 0xa4, 0x8c, 0x2c, 0xed, 0x03, 0x5a, + 0x1b, 0xbd, 0x3d, 0xd5, 0xfe, 0x3d, 0xfd, 0xb8, 0xf9, 0x67, 0xc0, 0xe7, 0x07, 0x3d, 0xac, 0x8f, + 0x5a, 0xab, 0xfe, 0xf2, 0x3e, 0x60, 0xa0, 0x27, 0x31, 0xb0, 0x9e, 0xdf, 0xff, 0xfe, 0xe7, 0x8f, + 0x1b, 0x35, 0x5a, 0x69, 0xb8, 0x07, 0x58, 0xcf, 0x2d, 0x45, 0x43, 0x61, 0x6b, 0xa2, 0x5e, 0x01, + 0x75, 0xf1, 0xe5, 0xf3, 0x67, 0x54, 0x1f, 0x3e, 0x1f, 0xb5, 0xd6, 0xfc, 0x55, 0x4d, 0x62, 0x8d, + 0xe3, 0x34, 0x9b, 0xf4, 0x5e, 0x41, 0x83, 0xc6, 0xd9, 0xf8, 0xe5, 0xfc, 0xc1, 0x7a, 0x4f, 0xdf, + 0x93, 0xea, 0xf8, 0x43, 0x99, 0x5f, 0x2a, 0xee, 0xfe, 0x58, 0x45, 0x53, 0xef, 0x6a, 0xf8, 0xd9, + 0xa8, 0xe5, 0xf9, 0xb7, 0x75, 0x05, 0xad, 0x2c, 0x9b, 0xac, 0x22, 0x37, 0x65, 0x6c, 0xd0, 0xb5, + 0x0b, 0x65, 0x64, 0x69, 0x8e, 0x34, 0x23, 0x95, 0x1d, 0x05, 0x0c, 0xc1, 0xb5, 0x76, 0x46, 0x0b, + 0x67, 0xb6, 0xf5, 0xd3, 0x51, 0xcb, 0xf7, 0x3d, 0x9b, 0x9a, 0x07, 0xba, 0x7f, 0x81, 0x0d, 0x0a, + 0xf4, 0xfb, 0x6a, 0x18, 0x57, 0xc3, 0x89, 0xfe, 0x7e, 0x5e, 0x7a, 0x4c, 0x65, 0xc1, 0xe6, 0xba, + 0x3c, 0xa3, 0x97, 0x33, 0xfb, 0xfb, 0x6c, 0xd4, 0xba, 0xef, 0xfb, 0x05, 0x9b, 0xad, 0x7f, 0x8a, + 0x6f, 0x2d, 0xac, 0x4d, 0x2a, 0xd4, 0x8c, 0x5d, 0x52, 0xb1, 0xdf, 0x11, 0x1f, 0xa8, 0xaf, 0x31, + 0x6a, 0x6d, 0xf8, 0xee, 0x13, 0x64, 0x42, 0x9f, 0x95, 0xe6, 0x4f, 0x49, 0xfb, 0xad, 0x54, 0x30, + 0x39, 0x6d, 0xf7, 0x0a, 0xd4, 0x19, 0xdf, 0x31, 0x33, 0x45, 0x7e, 0x35, 0x6a, 0xdd, 0xf1, 0x37, + 0x0a, 0xca, 0x09, 0x91, 0x86, 0x34, 0xf0, 0xaf, 0x1a, 0x24, 0x5d, 0x43, 0x46, 0x2a, 0xbb, 0x90, + 0xc1, 0x99, 0xd8, 0xcb, 0x46, 0xe9, 0x12, 0x7b, 0xf8, 0xc4, 0x88, 0xb6, 0x10, 0xd3, 0xa2, 0x6b, + 0x8f, 0x27, 0xcf, 0xcb, 0xaf, 0x05, 0xdb, 0xb5, 0x47, 0xe6, 0x32, 0xbe, 0x2f, 0x8c, 0xe2, 0x82, + 0x6f, 0x5a, 0xf1, 0xe6, 0xe3, 0xab, 0x14, 0xbf, 0x78, 0x44, 0x48, 0x47, 0xf4, 0x1d, 0xeb, 0x8b, + 0x8a, 0xbb, 0x2a, 0xda, 0x9a, 0xa3, 0x5d, 0xfa, 0x61, 0xd1, 0xda, 0xe5, 0xe1, 0xe1, 0xbc, 0xa1, + 0xfd, 0xe4, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0x5c, 0x73, 0x03, 0x6f, 0x0b, 0x00, 0x00, +} diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go new file mode 100644 index 000000000..cddd80be6 --- /dev/null +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -0,0 +1,523 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: config/service.proto + +/* +Package configpb is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package configpb + +import ( + "io" + "net/http" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray + +func request_ConfigService_GetConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GetConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_GetTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetTenantRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["identifier"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") + } + + protoReq.Identifier, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) + } + + msg, err := client.GetTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_GetAllTenants_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GetAllTenants(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_CreateConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ConfigData + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_CreateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TenantData + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_UpdateConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ConfigData + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_UpdateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateTenantRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["identifier"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") + } + + protoReq.Identifier, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) + } + + msg, err := client.UpdateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_DeleteConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.DeleteConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ConfigService_DeleteTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetTenantRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["identifier"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") + } + + protoReq.Identifier, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) + } + + msg, err := client.DeleteTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +// RegisterConfigServiceHandlerFromEndpoint is same as RegisterConfigServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterConfigServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterConfigServiceHandler(ctx, mux, conn) +} + +// RegisterConfigServiceHandler registers the http handlers for service ConfigService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterConfigServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterConfigServiceHandlerClient(ctx, mux, NewConfigServiceClient(conn)) +} + +// RegisterConfigServiceHandlerClient registers the http handlers for service ConfigService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ConfigServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ConfigServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "ConfigServiceClient" to call the correct interceptors. +func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ConfigServiceClient) error { + + mux.Handle("GET", pattern_ConfigService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_GetConfig_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_GetConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ConfigService_GetTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_GetTenant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_GetTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_ConfigService_GetAllTenants_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_GetAllTenants_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_GetAllTenants_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ConfigService_CreateConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_CreateConfig_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_CreateConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_ConfigService_CreateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_CreateTenant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_CreateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_ConfigService_UpdateConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_UpdateConfig_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_UpdateConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_ConfigService_UpdateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_UpdateTenant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_UpdateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_ConfigService_DeleteConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_DeleteConfig_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_DeleteConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_ConfigService_DeleteTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_DeleteTenant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_DeleteTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_ConfigService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) + + pattern_ConfigService_GetTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) + + pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"config", "tenant", "list"}, "")) + + pattern_ConfigService_CreateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) + + pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenant"}, "")) + + pattern_ConfigService_UpdateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) + + pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) + + pattern_ConfigService_DeleteConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) + + pattern_ConfigService_DeleteTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) +) + +var ( + forward_ConfigService_GetConfig_0 = runtime.ForwardResponseMessage + + forward_ConfigService_GetTenant_0 = runtime.ForwardResponseMessage + + forward_ConfigService_GetAllTenants_0 = runtime.ForwardResponseMessage + + forward_ConfigService_CreateConfig_0 = runtime.ForwardResponseMessage + + forward_ConfigService_CreateTenant_0 = runtime.ForwardResponseMessage + + forward_ConfigService_UpdateConfig_0 = runtime.ForwardResponseMessage + + forward_ConfigService_UpdateTenant_0 = runtime.ForwardResponseMessage + + forward_ConfigService_DeleteConfig_0 = runtime.ForwardResponseMessage + + forward_ConfigService_DeleteTenant_0 = runtime.ForwardResponseMessage +) diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 9241fdf10..101aae01b 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/list":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json new file mode 100644 index 000000000..20e800380 --- /dev/null +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -0,0 +1,378 @@ +{ + "swagger": "2.0", + "info": { + "title": "config/service.proto", + "version": "version not set" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/config/node": { + "get": { + "description": "Get Node Config", + "operationId": "GetConfig", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configConfigData" + } + } + }, + "tags": [ + "ConfigService" + ] + }, + "delete": { + "description": "Deletes node config", + "operationId": "DeleteConfig", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + } + }, + "tags": [ + "ConfigService" + ] + }, + "post": { + "description": "Creates node config data", + "operationId": "CreateConfig", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configConfigData" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/configConfigData" + } + } + ], + "tags": [ + "ConfigService" + ] + }, + "put": { + "description": "Updates node config", + "operationId": "UpdateConfig", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configConfigData" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/configConfigData" + } + } + ], + "tags": [ + "ConfigService" + ] + } + }, + "/config/tenant": { + "post": { + "description": "Creates tenant config data", + "operationId": "CreateTenant", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/configTenantData" + } + } + ], + "tags": [ + "ConfigService" + ] + } + }, + "/config/tenant/list": { + "get": { + "description": "Get All Tenant Configs", + "operationId": "GetAllTenants", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configGetAllTenantResponse" + } + } + }, + "tags": [ + "ConfigService" + ] + } + }, + "/config/tenant/{identifier}": { + "get": { + "description": "Get Tenant Config", + "operationId": "GetTenant", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ConfigService" + ] + }, + "delete": { + "description": "Deletes tenant config", + "operationId": "DeleteTenant", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + } + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ConfigService" + ] + }, + "put": { + "description": "Updates tenant config", + "operationId": "UpdateTenant", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/configUpdateTenantRequest" + } + } + ], + "tags": [ + "ConfigService" + ] + } + } + }, + "definitions": { + "configConfigData": { + "type": "object", + "properties": { + "storage_path": { + "type": "string" + }, + "p2p_port": { + "type": "integer", + "format": "int32" + }, + "p2p_external_ip": { + "type": "string" + }, + "p2p_connection_timeout": { + "type": "string" + }, + "server_port": { + "type": "integer", + "format": "int32" + }, + "server_address": { + "type": "string" + }, + "num_workers": { + "type": "integer", + "format": "int32" + }, + "worker_wait_time_ms": { + "type": "integer", + "format": "int32" + }, + "eth_node_url": { + "type": "string" + }, + "eth_context_read_wait_timeout": { + "type": "string" + }, + "eth_context_wait_timeout": { + "type": "string" + }, + "eth_interval_retry": { + "type": "string" + }, + "eth_max_retries": { + "type": "integer", + "format": "int64" + }, + "eth_gas_price": { + "type": "string", + "format": "uint64" + }, + "eth_gas_limit": { + "type": "string", + "format": "uint64" + }, + "tx_pool_enabled": { + "type": "boolean", + "format": "boolean" + }, + "network": { + "type": "string" + }, + "bootstrap_peers": { + "type": "array", + "items": { + "type": "string" + } + }, + "network_id": { + "type": "integer", + "format": "int64" + }, + "main_identity": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "configEthereumAccount": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "key": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "configGetAllTenantResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/configTenantData" + } + } + } + }, + "configKeyPair": { + "type": "object", + "properties": { + "pub": { + "type": "string" + }, + "pvt": { + "type": "string" + } + } + }, + "configTenantData": { + "type": "object", + "properties": { + "eth_account": { + "$ref": "#/definitions/configEthereumAccount" + }, + "eth_default_account_name": { + "type": "string" + }, + "receive_event_notification_endpoint": { + "type": "string" + }, + "identity_id": { + "type": "string" + }, + "signing_key_pair": { + "$ref": "#/definitions/configKeyPair" + }, + "ethauth_key_pair": { + "$ref": "#/definitions/configKeyPair" + } + } + }, + "configUpdateTenantRequest": { + "type": "object", + "properties": { + "identifier": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "protobufEmpty": { + "type": "object", + "description": "service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.", + "title": "A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:" + } + } +} From e33d07bf8e650e97a24efe0a04a2e3544b044451 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 21 Dec 2018 18:25:10 +0100 Subject: [PATCH 100/220] [MultiTenancy] P2P refactorings No. 1 (#594) * [MultiTenancy] P2P refactorings No. 1 * Fix problems * Minor cleanups * Debugged integration test * Fix bug --- anchors/anchor_repository_integration_test.go | 2 +- build/configs/testing_config.yaml | 1 + config/configuration.go | 8 + config/test_bootstrapper.go | 3 + context/testingbootstrap/testing_bootstrap.go | 3 +- coredocument/processor.go | 17 +- ethereum/geth_client_integration_test.go | 2 +- .../ethereum_identity_integration_test.go | 2 +- nft/payment_obligation_integration_test.go | 2 +- p2p/bootstrapper.go | 8 +- p2p/client.go | 31 +++- p2p/{ => grpc}/handler.go | 19 ++- p2p/{ => grpc}/handler_integration_test.go | 21 +-- p2p/{ => grpc}/handler_test.go | 14 +- p2p/{ => grpc}/validator.go | 2 +- p2p/{ => grpc}/validator_test.go | 2 +- p2p/server.go | 44 ++++-- p2p/server_test.go | 42 ++++- testingutils/setup.go | 149 ++++++++++++++++++ 19 files changed, 300 insertions(+), 72 deletions(-) rename p2p/{ => grpc}/handler.go (87%) rename p2p/{ => grpc}/handler_integration_test.go (96%) rename p2p/{ => grpc}/handler_test.go (94%) rename p2p/{ => grpc}/validator.go (99%) rename p2p/{ => grpc}/validator_test.go (99%) create mode 100644 testingutils/setup.go diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index db9b29c23..eea5888db 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -23,7 +23,7 @@ var ( ) func TestMain(m *testing.M) { - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index 75eb6188d..e051442e7 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -1,3 +1,4 @@ +centrifugeNetwork: testing ethereum: accounts: main: diff --git a/config/configuration.go b/config/configuration.go index 87f22fa0c..09e597c42 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -34,6 +34,7 @@ type Configuration interface { IsSet(key string) bool Set(key string, value interface{}) SetDefault(key string, value interface{}) + SetupSmartContractAddresses(network string, smartContractAddresses *SmartContractAddresses) Get(key string) interface{} GetString(key string) string GetBool(key string) bool @@ -444,3 +445,10 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { return v, nil } + +func (c *configuration) SetupSmartContractAddresses(network string, smartContractAddresses *SmartContractAddresses) { + c.v.Set("networks."+network+".contractAddresses.identityFactory", smartContractAddresses.IdentityFactoryAddr) + c.v.Set("networks."+network+".contractAddresses.identityRegistry", smartContractAddresses.IdentityRegistryAddr) + c.v.Set("networks."+network+".contractAddresses.anchorRepository", smartContractAddresses.AnchorRepositoryAddr) + c.v.Set("networks."+network+".contractAddresses.paymentObligation", smartContractAddresses.PaymentObligationAddr) +} diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index 59c9b90da..f3fb49a4d 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -11,6 +11,9 @@ import ( ) func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { + if _, ok := context[bootstrap.BootstrappedConfig]; ok { + return nil + } // To get the config location, we need to traverse the path to find the `go-centrifuge` folder path, _ := filepath.Abs("./") match := "" diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index 92caff014..0931796af 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -37,8 +37,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &queue.Starter{}, } -func TestFunctionalEthereumBootstrap() map[string]interface{} { - ctx := map[string]interface{}{} +func TestFunctionalEthereumBootstrap(ctx map[string]interface{}) map[string]interface{} { for _, b := range bootstappers { err := b.TestBootstrap(ctx) if err != nil { diff --git a/coredocument/processor.go b/coredocument/processor.go index fc9b8452d..dd029cf81 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -1,8 +1,6 @@ package coredocument import ( - "fmt" - "context" "time" @@ -43,7 +41,7 @@ type Processor interface { // client defines the methods for p2pclient // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { - OpenClient(target string) (p2ppb.P2PServiceClient, error) + OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } @@ -70,26 +68,17 @@ func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredoc if coreDocument == nil { return centerrors.NilError(coreDocument) } - log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) id, err := dp.identityService.LookupIdentityForID(recipient) if err != nil { return centerrors.Wrap(err, "error fetching receiver identity") } - - lastB58Key, err := id.CurrentP2PKey() - if err != nil { - return centerrors.Wrap(err, "error fetching p2p key") - } - - log.Infof("Sending Document to CentID [%v] with Key [%v]\n", recipient, lastB58Key) - clientWithProtocol := fmt.Sprintf("/ipfs/%s", lastB58Key) - client, err := dp.p2pClient.OpenClient(clientWithProtocol) + client, err := dp.p2pClient.OpenClient(id) if err != nil { return errors.New("failed to open client: %v", err) } - log.Infof("Done opening connection against [%s]\n", lastB58Key) + log.Infof("Done opening connection against recipient [%x]\n", recipient) idConfig := ctx.Self() centIDBytes := idConfig.ID[:] p2pheader := &p2ppb.CentrifugeHeader{ diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 27adca307..175bac8d0 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -16,7 +16,7 @@ import ( var cfg config.Configuration func TestMain(m *testing.M) { - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 688792879..0d675aa73 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 1ec5cca2c..20058d279 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -32,7 +32,7 @@ var payOb nft.PaymentObligation func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index e1813b0f5..a7c5944de 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -1,10 +1,14 @@ package p2p import ( + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/grpc" + "github.com/paralin/go-libp2p-grpc" ) // Bootstrapped constants that are used as key in bootstrap context @@ -27,7 +31,9 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("registry not initialised") } - srv := &p2pServer{config: cfg, registry: registry, handler: GRPCHandler(cfg, registry)} + srv := &p2pServer{grpcSrvs: make(map[identity.CentID]*p2pgrpc.GRPCProtocol), config: cfg, grpcHandlerCreator: func() p2ppb.P2PServiceServer { + return grpc.New(cfg, registry) + }} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[BootstrappedP2PClient] = srv return nil diff --git a/p2p/client.go b/p2p/client.go index fb68191ea..9f57a5aa3 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -21,12 +21,17 @@ import ( // Client defines methods that can be implemented by any type handling p2p communications. type Client interface { - OpenClient(target string) (p2ppb.P2PServiceClient, error) + OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // OpenClient returns P2PServiceClient to contact the remote peer -func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { +func (s *p2pServer) OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) { + lastB58Key, err := id.CurrentP2PKey() + if err != nil { + return nil, errors.New("error fetching p2p key: %v", err) + } + target := fmt.Sprintf("/ipfs/%s", lastB58Key) log.Info("Opening connection to: %s", target) ipfsAddr, err := ma.NewMultiaddr(target) if err != nil { @@ -56,7 +61,20 @@ func (s *p2pServer) OpenClient(target string) (p2ppb.P2PServiceClient, error) { // Retrial is handled internally, connection request will be cancelled by the connection timeout context ctx, cancel := context.WithTimeout(context.Background(), s.config.GetP2PConnectionTimeout()) defer cancel() - g, err := s.protocol.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) + // TODO remove this self config and pass in the selfID in the OpenClient function + selfIDBytes, err := s.config.GetIdentityID() + if err != nil { + return nil, errors.New("failed to get self identity: %v", err) + } + selfID, err := identity.ToCentID(selfIDBytes) + if err != nil { + return nil, errors.New("failed to cast self identity: %v", err) + } + gp, ok := s.grpcSrvs[selfID] + if !ok { + return nil, errors.New("failed to dial peer [%s]: no grpc server found for centID [%s]", peerID.Pretty(), id.CentID()) + } + g, err := gp.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { return nil, errors.New("failed to dial peer [%s]: %v", peerID.Pretty(), err) } @@ -137,13 +155,12 @@ func (s *p2pServer) GetSignaturesForDocument(ctx *header.ContextHeader, identity if err != nil { return centerrors.Wrap(err, "failed to convert to CentID") } - target, err := identityService.GetClientP2PURL(collaboratorID) - + id, err := identityService.LookupIdentityForID(collaboratorID) if err != nil { - return centerrors.Wrap(err, "failed to get P2P url") + return centerrors.Wrap(err, "error fetching collaborator identity") } - client, err := s.OpenClient(target) + client, err := s.OpenClient(id) if err != nil { log.Error(centerrors.Wrap(err, "failed to connect to target")) continue diff --git a/p2p/handler.go b/p2p/grpc/handler.go similarity index 87% rename from p2p/handler.go rename to p2p/grpc/handler.go index 32493347d..2068c22e9 100644 --- a/p2p/handler.go +++ b/p2p/grpc/handler.go @@ -1,4 +1,4 @@ -package p2p +package grpc import ( "context" @@ -14,8 +14,11 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/version" + logging "github.com/ipfs/go-log" ) +var log = logging.Logger("grpc") + // getService looks up the specific registry, derives service from core document func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { if cd == nil { @@ -39,22 +42,22 @@ func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb. return srv, model, nil } -// handler implements the grpc interface -type handler struct { +// Handler implements the grpc interface +type Handler struct { registry *documents.ServiceRegistry config config.Configuration } -// GRPCHandler returns an implementation of P2PServiceServer -func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) p2ppb.P2PServiceServer { - return handler{registry: registry, config: config} +// New returns an implementation of P2PServiceServer +func New(config config.Configuration, registry *documents.ServiceRegistry) *Handler { + return &Handler{registry: registry, config: config} } // RequestDocumentSignature signs the received document and returns the signature of the signingRoot // Document signing root will be recalculated and verified // Existing signatures on the document will be verified // Document will be stored to the repository for state management -func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { +func (srv Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { ctxHeader, err := header.NewContextHeader(ctx, srv.config) if err != nil { log.Error(err) @@ -82,7 +85,7 @@ func (srv handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.S } // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB -func (srv handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (srv Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { err := handshakeValidator(srv.config.GetNetworkID()).Validate(docReq.Header) if err != nil { return nil, err diff --git a/p2p/handler_integration_test.go b/p2p/grpc/handler_integration_test.go similarity index 96% rename from p2p/handler_integration_test.go rename to p2p/grpc/handler_integration_test.go index 0853da204..a1ed98931 100644 --- a/p2p/handler_integration_test.go +++ b/p2p/grpc/handler_integration_test.go @@ -1,6 +1,6 @@ // +build integration -package p2p_test +package grpc_test import ( "context" @@ -8,18 +8,22 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + + "github.com/centrifuge/go-centrifuge/testingutils" + + "github.com/centrifuge/go-centrifuge/p2p/grpc" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/keytools/secp256k1" - "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" @@ -40,16 +44,13 @@ var ( func TestMain(m *testing.M) { flag.Parse() - ctx := cc.TestFunctionalEthereumBootstrap() + cm := testingutils.BuildIntegrationTestingContext() + ctx := cc.TestFunctionalEthereumBootstrap(cm) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - handler = p2p.GRPCHandler(cfg, registry) + handler = grpc.New(cfg, registry) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() cc.TestFunctionalEthereumTearDown() diff --git a/p2p/handler_test.go b/p2p/grpc/handler_test.go similarity index 94% rename from p2p/handler_test.go rename to p2p/grpc/handler_test.go index ce204e8ee..18625cee0 100644 --- a/p2p/handler_test.go +++ b/p2p/grpc/handler_test.go @@ -1,6 +1,6 @@ // +build unit -package p2p +package grpc import ( "context" @@ -32,7 +32,6 @@ var ( registry *documents.ServiceRegistry coreDoc = testingcoredocument.GenerateCoreDocument() cfg config.Configuration - testClient *p2pServer ) func TestMain(m *testing.M) { @@ -45,13 +44,12 @@ func TestMain(m *testing.M) { ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + cfg.Set("keys.signing.publicKey", "../../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - grpcHandler = GRPCHandler(cfg, registry) - testClient = &p2pServer{config: cfg} + grpcHandler = New(cfg, registry) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/p2p/validator.go b/p2p/grpc/validator.go similarity index 99% rename from p2p/validator.go rename to p2p/grpc/validator.go index 4f1604425..1776368c7 100644 --- a/p2p/validator.go +++ b/p2p/grpc/validator.go @@ -1,4 +1,4 @@ -package p2p +package grpc import ( "fmt" diff --git a/p2p/validator_test.go b/p2p/grpc/validator_test.go similarity index 99% rename from p2p/validator_test.go rename to p2p/grpc/validator_test.go index 84289a802..322b5a494 100644 --- a/p2p/validator_test.go +++ b/p2p/grpc/validator_test.go @@ -1,6 +1,6 @@ // +build unit -package p2p +package grpc import ( "testing" diff --git a/p2p/server.go b/p2p/server.go index dd921594f..52593314e 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -6,10 +6,11 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/documents" cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -41,11 +42,10 @@ type Config interface { // p2pServer implements api.Server type p2pServer struct { - config Config - host host.Host - registry *documents.ServiceRegistry - protocol *p2pgrpc.GRPCProtocol - handler p2ppb.P2PServiceServer + config Config + host host.Host + grpcSrvs map[identity.CentID]*p2pgrpc.GRPCProtocol + grpcHandlerCreator func() p2ppb.P2PServiceServer } // Name returns the P2PServer @@ -70,29 +70,43 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch return } + // TODO remove following after proper multi tenant setup. Before that the node only has one configure main identity + id, err := s.config.GetIdentityID() + if err != nil { + startupErr <- err + return + } + + centID, err := identity.ToCentID(id) + if err != nil { + startupErr <- err + return + } + // Set the grpc protocol handler on it - s.protocol = p2pgrpc.NewGRPCProtocol(ctx, s.host) - p2ppb.RegisterP2PServiceServer(s.protocol.GetGRPCServer(), s.handler) + // TODO create NewGRPCProtocol per tenant after multi tenancy is implemented + s.grpcSrvs[centID] = p2pgrpc.NewGRPCProtocol(ctx, s.host) + p2ppb.RegisterP2PServiceServer(s.grpcSrvs[centID].GetGRPCServer(), s.grpcHandlerCreator()) serveErr := make(chan error) - go func() { - err := s.protocol.Serve() + go func(p *p2pgrpc.GRPCProtocol) { + err := p.Serve() serveErr <- err - }() + }(s.grpcSrvs[centID]) s.host.Peerstore().AddAddr(s.host.ID(), s.host.Addrs()[0], pstore.TempAddrTTL) - // Start DHT - s.runDHT(ctx, s.host) + // Start DHT and properly ignore errors :) + _ = s.runDHT(ctx, s.host) select { case err := <-serveErr: log.Infof("GRPC server error: %v", err) - s.protocol.GetGRPCServer().GracefulStop() + s.grpcSrvs[centID].GetGRPCServer().GracefulStop() log.Info("GRPC server stopped") return case <-ctx.Done(): log.Info("Shutting down GRPC server") - s.protocol.GetGRPCServer().GracefulStop() + s.grpcSrvs[centID].GetGRPCServer().GracefulStop() log.Info("GRPC server stopped") return } diff --git a/p2p/server_test.go b/p2p/server_test.go index 698ea7bb0..acfc95d7d 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -5,21 +5,61 @@ package p2p import ( "context" "fmt" + "os" "sync" "testing" "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/p2p/grpc" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/paralin/go-libp2p-grpc" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/storage" + + "github.com/centrifuge/go-centrifuge/config" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" ) +var ( + cfg config.Configuration + testClient *p2pServer +) + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + documents.Bootstrapper{}, + } + ctx := make(map[string]interface{}) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + testClient = &p2pServer{config: cfg} + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestCentP2PServer_Start(t *testing.T) { } func TestCentP2PServer_StartContextCancel(t *testing.T) { cfg.Set("p2p.port", 38203) - cp2p := &p2pServer{config: cfg, handler: GRPCHandler(cfg, nil)} + cp2p := &p2pServer{grpcSrvs: make(map[identity.CentID]*p2pgrpc.GRPCProtocol), config: cfg, grpcHandlerCreator: func() p2ppb.P2PServiceServer { + return grpc.New(cfg, nil) + }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) var wg sync.WaitGroup diff --git a/testingutils/setup.go b/testingutils/setup.go new file mode 100644 index 000000000..78312b68d --- /dev/null +++ b/testingutils/setup.go @@ -0,0 +1,149 @@ +// +build integration unit + +package testingutils + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + + "github.com/centrifuge/go-centrifuge/bootstrap" + + "github.com/centrifuge/go-centrifuge/config" + logging "github.com/ipfs/go-log" + "github.com/savaki/jq" +) + +var log = logging.Logger("test-setup") +var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 + +// StartPOAGeth runs the proof of authority geth for tests +func StartPOAGeth() { + // don't run if its already running + if IsPOAGethRunning() { + return + } + projDir := getProjectDir() + gethRunScript := path.Join(projDir, "build", "scripts", "docker", "run.sh") + o, err := exec.Command(gethRunScript, "dev").Output() + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s", string(o)) +} + +// RunSmartContractMigrations migrates smart contracts to localgeth +func RunSmartContractMigrations() { + if isRunningOnCI { + return + } + projDir := getProjectDir() + migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") + _, err := exec.Command(migrationScript, projDir).Output() + if err != nil { + log.Fatal(err) + } +} + +// GetSmartContractAddresses finds migrated smart contract addresses for localgeth +func GetSmartContractAddresses() *config.SmartContractAddresses { + dat, err := findContractDeployJSON() + if err != nil { + panic(err) + } + idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") + idRegistryAddrOp := getOpForContract(".contracts.IdentityRegistry.address") + anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") + payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") + return &config.SmartContractAddresses{ + IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), + IdentityRegistryAddr: getOpAddr(idRegistryAddrOp, dat), + AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), + PaymentObligationAddr: getOpAddr(payObAddrOp, dat), + } +} + +func findContractDeployJSON() ([]byte, error) { + projDir := getProjectDir() + deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + dat, err := ioutil.ReadFile(deployJSONFile) + if err != nil { + return nil, err + } + return dat, nil +} + +func getOpAddr(addrOp jq.Op, dat []byte) string { + addr, err := addrOp.Apply(dat) + if err != nil { + panic(err) + } + + // remove extra quotes inside the string + addrStr := string(addr) + if len(addrStr) > 0 && addrStr[0] == '"' { + addrStr = addrStr[1:] + } + if len(addrStr) > 0 && addrStr[len(addrStr)-1] == '"' { + addrStr = addrStr[:len(addrStr)-1] + } + return addrStr +} + +func getOpForContract(selector string) jq.Op { + addrOp, err := jq.Parse(selector) + if err != nil { + panic(err) + } + return addrOp +} + +func getProjectDir() string { + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") + return projDir +} + +// IsPOAGethRunning checks if POA geth is running in the background +func IsPOAGethRunning() bool { + cmd := "docker ps -a --filter \"name=geth-node\" --filter \"status=running\" --quiet" + o, err := exec.Command("/bin/sh", "-c", cmd).Output() + if err != nil { + panic(err) + } + return len(o) != 0 +} + +// LoadTestConfig loads configuration for integration tests +func LoadTestConfig() config.Configuration { + // To get the config location, we need to traverse the path to find the `go-centrifuge` folder + projDir := getProjectDir() + c := config.LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", projDir)) + return c +} + +// SetupSmartContractAddresses sets up smart contract addresses on provided config +func SetupSmartContractAddresses(cfg config.Configuration, sca *config.SmartContractAddresses) { + network := cfg.Get("centrifugeNetwork").(string) + cfg.SetupSmartContractAddresses(network, sca) + fmt.Printf("contract addresses %+v\n", sca) +} + +// BuildIntegrationTestingContext sets up configuration for integration tests +func BuildIntegrationTestingContext() map[string]interface{} { + projDir := getProjectDir() + StartPOAGeth() + RunSmartContractMigrations() + addresses := GetSmartContractAddresses() + cfg := LoadTestConfig() + cfg.Set("keys.signing.publicKey", fmt.Sprintf("%s/build/resources/signingKey.pub.pem", projDir)) + cfg.Set("keys.signing.privateKey", fmt.Sprintf("%s/build/resources/signingKey.key.pem", projDir)) + cfg.Set("keys.ethauth.publicKey", fmt.Sprintf("%s/build/resources/ethauth.pub.pem", projDir)) + cfg.Set("keys.ethauth.privateKey", fmt.Sprintf("%s/build/resources/ethauth.key.pem", projDir)) + SetupSmartContractAddresses(cfg, addresses) + cm := make(map[string]interface{}) + cm[bootstrap.BootstrappedConfig] = cfg + return cm +} From bb14875ab91b50734a22b49c0d5b1b0f8424c60b Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 21 Dec 2018 22:52:36 +0100 Subject: [PATCH 101/220] Fully debuggable integration tests (#595) * [MultiTenancy] P2P refactorings No. 1 * Fix problems * Minor cleanups * Debugged integration test * Fully debuggable integration tests * Fix bug * Minor --- anchors/anchor_repository_integration_test.go | 2 +- context/testingbootstrap/testing_bootstrap.go | 8 +++++--- ethereum/geth_client_integration_test.go | 2 +- identity/ethereum_identity_integration_test.go | 6 +----- nft/payment_obligation_integration_test.go | 14 +------------- p2p/grpc/handler_integration_test.go | 5 +---- 6 files changed, 10 insertions(+), 27 deletions(-) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index eea5888db..db9b29c23 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -23,7 +23,7 @@ var ( ) func TestMain(m *testing.M) { - ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) + ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() diff --git a/context/testingbootstrap/testing_bootstrap.go b/context/testingbootstrap/testing_bootstrap.go index 0931796af..350ee5d64 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/context/testingbootstrap/testing_bootstrap.go @@ -16,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils" logging "github.com/ipfs/go-log" ) @@ -37,16 +38,17 @@ var bootstappers = []bootstrap.TestBootstrapper{ &queue.Starter{}, } -func TestFunctionalEthereumBootstrap(ctx map[string]interface{}) map[string]interface{} { +func TestFunctionalEthereumBootstrap() map[string]interface{} { + cm := testingutils.BuildIntegrationTestingContext() for _, b := range bootstappers { - err := b.TestBootstrap(ctx) + err := b.TestBootstrap(cm) if err != nil { log.Error("Error encountered while bootstrapping", err) panic(err) } } - return ctx + return cm } func TestFunctionalEthereumTearDown() { for _, b := range bootstappers { diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 175bac8d0..27adca307 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -16,7 +16,7 @@ import ( var cfg config.Configuration func TestMain(m *testing.M) { - ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) + ctx := cc.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 0d675aa73..02ba7a458 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -23,12 +23,8 @@ var cfg config.Configuration func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) - - ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) + ctx := cc.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 20058d279..34ca134f1 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -32,24 +32,12 @@ var payOb nft.PaymentObligation func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") - ctx := cc.TestFunctionalEthereumBootstrap(make(map[string]interface{})) + ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) - prevSignPubkey := cfg.Get("keys.signing.publicKey") - prevSignPrivkey := cfg.Get("keys.signing.privateKey") - prevEthPubkey := cfg.Get("keys.ethauth.publicKey") - prevEthPrivkey := cfg.Get("keys.ethauth.privateKey") - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() - cfg.Set("keys.signing.publicKey", prevSignPubkey) - cfg.Set("keys.signing.privateKey", prevSignPrivkey) - cfg.Set("keys.ethauth.publicKey", prevEthPubkey) - cfg.Set("keys.ethauth.privateKey", prevEthPrivkey) cc.TestFunctionalEthereumTearDown() os.Exit(result) } diff --git a/p2p/grpc/handler_integration_test.go b/p2p/grpc/handler_integration_test.go index a1ed98931..d247d33a0 100644 --- a/p2p/grpc/handler_integration_test.go +++ b/p2p/grpc/handler_integration_test.go @@ -10,8 +10,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/p2p/grpc" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -44,8 +42,7 @@ var ( func TestMain(m *testing.M) { flag.Parse() - cm := testingutils.BuildIntegrationTestingContext() - ctx := cc.TestFunctionalEthereumBootstrap(cm) + ctx := cc.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) From f4c1bd63bf77719458d4e4f4a155f8018d29c5f2 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 24 Dec 2018 11:30:59 +0100 Subject: [PATCH 102/220] Transaction Status Check API (#596) Fixes #496 - Add Transaction Status check endpoint --- api/server.go | 6 +- api/server_test.go | 5 +- api/service.go | 10 + common/common.go | 13 + protobufs/gen/go/transactions/service.pb.go | 232 ++++++++++++++++++ .../gen/go/transactions/service.pb.gw.go | 134 ++++++++++ protobufs/gen/swagger.json | 2 +- .../swagger/transactions/service.swagger.json | 64 +++++ protobufs/transactions/service.proto | 34 +++ transactions/bootstrapper.go | 6 + transactions/bootstrapper_test.go | 1 + transactions/handler.go | 34 +++ transactions/handler_test.go | 49 ++++ transactions/service.go | 46 ++++ transactions/service_test.go | 54 ++++ transactions/transaction.go | 22 +- 16 files changed, 696 insertions(+), 16 deletions(-) create mode 100644 common/common.go create mode 100644 protobufs/gen/go/transactions/service.pb.go create mode 100644 protobufs/gen/go/transactions/service.pb.gw.go create mode 100644 protobufs/gen/swagger/transactions/service.swagger.json create mode 100644 protobufs/transactions/service.proto create mode 100644 transactions/handler.go create mode 100644 transactions/handler_test.go create mode 100644 transactions/service.go create mode 100644 transactions/service_test.go diff --git a/api/server.go b/api/server.go index 23f9aef88..f6c43fae0 100644 --- a/api/server.go +++ b/api/server.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -29,9 +30,6 @@ var ( // noAuthPaths holds the paths that doesn't require header to be passed. noAuthPaths = [...]string{"/health.HealthCheckService/Ping"} - - // TenantKey represents the key used to fetch the tenant id from context - TenantKey struct{} ) // Config defines methods required for the package api @@ -212,7 +210,7 @@ func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, hand return nil, err } - ctx = context.WithValue(ctx, TenantKey, auth[0]) + ctx = context.WithValue(ctx, common.TenantKey, auth[0]) return handler(ctx, req) } diff --git a/api/server_test.go b/api/server_test.go index a35ebba66..0de14b796 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -12,6 +12,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" @@ -25,6 +26,7 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" "google.golang.org/grpc" "google.golang.org/grpc/metadata" @@ -43,6 +45,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + transactions.Bootstrapper{}, &queue.Bootstrapper{}, anchors.Bootstrapper{}, &identity.Bootstrapper{}, @@ -115,7 +118,7 @@ func TestCentAPIServer_FailedToGetRegistry(t *testing.T) { func Test_auth(t *testing.T) { handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return ctx.Value(TenantKey), nil + return ctx.Value(common.TenantKey), nil } // send ping path diff --git a/api/service.go b/api/service.go index 70a9e1135..7d978237e 100644 --- a/api/service.go +++ b/api/service.go @@ -14,6 +14,8 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/grpc-ecosystem/grpc-gateway/runtime" "golang.org/x/net/context" "google.golang.org/grpc" @@ -83,5 +85,13 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, return err } + // transactions + txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Service) + h := transactions.GRPCHandler(txSrv) + transactionspb.RegisterTransactionServiceServer(grpcServer, h) + if err := transactionspb.RegisterTransactionServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts); err != nil { + return err + } + return nil } diff --git a/common/common.go b/common/common.go new file mode 100644 index 000000000..4db660451 --- /dev/null +++ b/common/common.go @@ -0,0 +1,13 @@ +// Package common holds the common types used across the node +package common + +import "github.com/ethereum/go-ethereum/common" + +var ( + // TenantKey is used as key for the tenant identity in the context.ContextWithValue. + TenantKey struct{} + + // DummyIdentity to be used until we have identity coming from auth header + // TODO(ved): get rid of this once we have multitenancy enabled/ + DummyIdentity = common.Address([20]byte{1}) +) diff --git a/protobufs/gen/go/transactions/service.pb.go b/protobufs/gen/go/transactions/service.pb.go new file mode 100644 index 000000000..4c130990f --- /dev/null +++ b/protobufs/gen/go/transactions/service.pb.go @@ -0,0 +1,232 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: transactions/service.proto + +package transactionspb + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" +import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" +import _ "google.golang.org/genproto/googleapis/api/annotations" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type TransactionStatusRequest struct { + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TransactionStatusRequest) Reset() { *m = TransactionStatusRequest{} } +func (m *TransactionStatusRequest) String() string { return proto.CompactTextString(m) } +func (*TransactionStatusRequest) ProtoMessage() {} +func (*TransactionStatusRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_service_b7b04d343851d658, []int{0} +} +func (m *TransactionStatusRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TransactionStatusRequest.Unmarshal(m, b) +} +func (m *TransactionStatusRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TransactionStatusRequest.Marshal(b, m, deterministic) +} +func (dst *TransactionStatusRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransactionStatusRequest.Merge(dst, src) +} +func (m *TransactionStatusRequest) XXX_Size() int { + return xxx_messageInfo_TransactionStatusRequest.Size(m) +} +func (m *TransactionStatusRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TransactionStatusRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_TransactionStatusRequest proto.InternalMessageInfo + +func (m *TransactionStatusRequest) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + +type TransactionStatusResponse struct { + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + LastUpdated *timestamp.Timestamp `protobuf:"bytes,4,opt,name=last_updated,json=lastUpdated,proto3" json:"last_updated,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TransactionStatusResponse) Reset() { *m = TransactionStatusResponse{} } +func (m *TransactionStatusResponse) String() string { return proto.CompactTextString(m) } +func (*TransactionStatusResponse) ProtoMessage() {} +func (*TransactionStatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_service_b7b04d343851d658, []int{1} +} +func (m *TransactionStatusResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TransactionStatusResponse.Unmarshal(m, b) +} +func (m *TransactionStatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TransactionStatusResponse.Marshal(b, m, deterministic) +} +func (dst *TransactionStatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransactionStatusResponse.Merge(dst, src) +} +func (m *TransactionStatusResponse) XXX_Size() int { + return xxx_messageInfo_TransactionStatusResponse.Size(m) +} +func (m *TransactionStatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TransactionStatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TransactionStatusResponse proto.InternalMessageInfo + +func (m *TransactionStatusResponse) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + +func (m *TransactionStatusResponse) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +func (m *TransactionStatusResponse) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *TransactionStatusResponse) GetLastUpdated() *timestamp.Timestamp { + if m != nil { + return m.LastUpdated + } + return nil +} + +func init() { + proto.RegisterType((*TransactionStatusRequest)(nil), "transactions.TransactionStatusRequest") + proto.RegisterType((*TransactionStatusResponse)(nil), "transactions.TransactionStatusResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// TransactionServiceClient is the client API for TransactionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TransactionServiceClient interface { + GetTransactionStatus(ctx context.Context, in *TransactionStatusRequest, opts ...grpc.CallOption) (*TransactionStatusResponse, error) +} + +type transactionServiceClient struct { + cc *grpc.ClientConn +} + +func NewTransactionServiceClient(cc *grpc.ClientConn) TransactionServiceClient { + return &transactionServiceClient{cc} +} + +func (c *transactionServiceClient) GetTransactionStatus(ctx context.Context, in *TransactionStatusRequest, opts ...grpc.CallOption) (*TransactionStatusResponse, error) { + out := new(TransactionStatusResponse) + err := c.cc.Invoke(ctx, "/transactions.TransactionService/GetTransactionStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TransactionServiceServer is the server API for TransactionService service. +type TransactionServiceServer interface { + GetTransactionStatus(context.Context, *TransactionStatusRequest) (*TransactionStatusResponse, error) +} + +func RegisterTransactionServiceServer(s *grpc.Server, srv TransactionServiceServer) { + s.RegisterService(&_TransactionService_serviceDesc, srv) +} + +func _TransactionService_GetTransactionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TransactionStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TransactionServiceServer).GetTransactionStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/transactions.TransactionService/GetTransactionStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TransactionServiceServer).GetTransactionStatus(ctx, req.(*TransactionStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _TransactionService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "transactions.TransactionService", + HandlerType: (*TransactionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTransactionStatus", + Handler: _TransactionService_GetTransactionStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "transactions/service.proto", +} + +func init() { proto.RegisterFile("transactions/service.proto", fileDescriptor_service_b7b04d343851d658) } + +var fileDescriptor_service_b7b04d343851d658 = []byte{ + // 346 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4a, 0xc3, 0x40, + 0x10, 0x86, 0x49, 0x95, 0x8a, 0xdb, 0x2a, 0xb2, 0x48, 0x89, 0x41, 0x69, 0x28, 0xa8, 0x3d, 0xd8, + 0x2c, 0xd4, 0xb3, 0x60, 0x7b, 0x29, 0xde, 0x4a, 0xad, 0x17, 0x2f, 0x65, 0x9b, 0x8c, 0x21, 0xd0, + 0x64, 0xd7, 0xcc, 0x46, 0x0f, 0xe2, 0xc5, 0x47, 0xd0, 0xa7, 0xf0, 0xec, 0x0b, 0xf8, 0x0e, 0xbe, + 0x82, 0x0f, 0x22, 0xdd, 0x4d, 0x71, 0x4b, 0x15, 0x3d, 0x85, 0xd9, 0xff, 0xcf, 0x3f, 0x33, 0xdf, + 0x10, 0x4f, 0xe5, 0x3c, 0x43, 0x1e, 0xaa, 0x44, 0x64, 0xc8, 0x10, 0xf2, 0xbb, 0x24, 0x84, 0x40, + 0xe6, 0x42, 0x09, 0x5a, 0xb7, 0x35, 0x6f, 0x3f, 0x16, 0x22, 0x9e, 0x01, 0xe3, 0x32, 0x61, 0x3c, + 0xcb, 0x84, 0xe2, 0xfa, 0xdd, 0x78, 0xbd, 0x66, 0xa9, 0xea, 0x6a, 0x5a, 0xdc, 0x30, 0x95, 0xa4, + 0x80, 0x8a, 0xa7, 0xb2, 0x34, 0x9c, 0xe8, 0x4f, 0xd8, 0x89, 0x21, 0xeb, 0xe0, 0x3d, 0x8f, 0x63, + 0xc8, 0x99, 0x90, 0xa6, 0xed, 0x4a, 0x5c, 0xab, 0x47, 0xdc, 0xf1, 0x77, 0xf3, 0x4b, 0xc5, 0x55, + 0x81, 0x23, 0xb8, 0x2d, 0x00, 0x15, 0x3d, 0x24, 0xdb, 0xd6, 0x60, 0x93, 0x24, 0x72, 0x1d, 0xdf, + 0x69, 0x6f, 0x8e, 0xb6, 0xac, 0xd7, 0x8b, 0xa8, 0xf5, 0xe6, 0x90, 0xbd, 0x1f, 0x32, 0x50, 0x8a, + 0x0c, 0xe1, 0x9f, 0x21, 0xb4, 0x41, 0xaa, 0xa8, 0x7f, 0x74, 0x2b, 0x5a, 0x2e, 0x2b, 0xea, 0x92, + 0x8d, 0x14, 0x10, 0x79, 0x0c, 0xee, 0x9a, 0x16, 0x16, 0x25, 0x3d, 0x23, 0xf5, 0x19, 0x47, 0x35, + 0x29, 0x64, 0xc4, 0x15, 0x44, 0xee, 0xba, 0xef, 0xb4, 0x6b, 0x5d, 0x2f, 0x30, 0x7c, 0x82, 0x05, + 0x9f, 0x60, 0xbc, 0xe0, 0x33, 0xaa, 0xcd, 0xfd, 0x57, 0xc6, 0xde, 0x7d, 0x77, 0x08, 0xb5, 0xa7, + 0x36, 0x07, 0xa1, 0xaf, 0x0e, 0xd9, 0x1d, 0x80, 0x5a, 0xd9, 0x87, 0x1e, 0x05, 0xf6, 0x91, 0x82, + 0xdf, 0xa0, 0x79, 0xc7, 0x7f, 0xfa, 0x0c, 0x98, 0xd6, 0xf9, 0x73, 0xcf, 0xf5, 0x1a, 0x03, 0x50, + 0xbe, 0xe5, 0xf1, 0x8d, 0xe9, 0xe9, 0xe3, 0xf3, 0xa5, 0xd2, 0xa4, 0x07, 0xcc, 0xca, 0x62, 0x0f, + 0xcb, 0x1c, 0x1f, 0xfb, 0x5d, 0xb2, 0x13, 0x8a, 0x74, 0xa9, 0x5f, 0xbf, 0x5e, 0x2e, 0x32, 0x9c, + 0xaf, 0x3f, 0x74, 0xae, 0x6d, 0xf8, 0x28, 0xa7, 0xd3, 0xaa, 0xe6, 0x72, 0xfa, 0x15, 0x00, 0x00, + 0xff, 0xff, 0x43, 0x55, 0xde, 0xba, 0x8f, 0x02, 0x00, 0x00, +} diff --git a/protobufs/gen/go/transactions/service.pb.gw.go b/protobufs/gen/go/transactions/service.pb.gw.go new file mode 100644 index 000000000..21cf13fd8 --- /dev/null +++ b/protobufs/gen/go/transactions/service.pb.gw.go @@ -0,0 +1,134 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: transactions/service.proto + +/* +Package transactionspb is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package transactionspb + +import ( + "io" + "net/http" + + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray + +func request_TransactionService_GetTransactionStatus_0(ctx context.Context, marshaler runtime.Marshaler, client TransactionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TransactionStatusRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["transaction_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "transaction_id") + } + + protoReq.TransactionId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "transaction_id", err) + } + + msg, err := client.GetTransactionStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +// RegisterTransactionServiceHandlerFromEndpoint is same as RegisterTransactionServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterTransactionServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterTransactionServiceHandler(ctx, mux, conn) +} + +// RegisterTransactionServiceHandler registers the http handlers for service TransactionService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterTransactionServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterTransactionServiceHandlerClient(ctx, mux, NewTransactionServiceClient(conn)) +} + +// RegisterTransactionServiceHandlerClient registers the http handlers for service TransactionService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TransactionServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TransactionServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "TransactionServiceClient" to call the correct interceptors. +func RegisterTransactionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TransactionServiceClient) error { + + mux.Handle("GET", pattern_TransactionService_GetTransactionStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_TransactionService_GetTransactionStatus_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_TransactionService_GetTransactionStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_TransactionService_GetTransactionStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"transaction", "transaction_id"}, "")) +) + +var ( + forward_TransactionService_GetTransactionStatus_0 = runtime.ForwardResponseMessage +) diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 101aae01b..78575a2a5 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/list":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/list":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/transactions/service.swagger.json b/protobufs/gen/swagger/transactions/service.swagger.json new file mode 100644 index 000000000..f7cf06922 --- /dev/null +++ b/protobufs/gen/swagger/transactions/service.swagger.json @@ -0,0 +1,64 @@ +{ + "swagger": "2.0", + "info": { + "title": "transactions/service.proto", + "version": "version not set" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/transaction/{transaction_id}": { + "get": { + "description": "Get Transaction Status", + "operationId": "GetTransactionStatus", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/transactionsTransactionStatusResponse" + } + } + }, + "parameters": [ + { + "name": "transaction_id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "TransactionService" + ] + } + } + }, + "definitions": { + "transactionsTransactionStatusResponse": { + "type": "object", + "properties": { + "transaction_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "message": { + "type": "string" + }, + "last_updated": { + "type": "string", + "format": "date-time" + } + } + } + } +} diff --git a/protobufs/transactions/service.proto b/protobufs/transactions/service.proto new file mode 100644 index 000000000..407b40975 --- /dev/null +++ b/protobufs/transactions/service.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package transactions; + +option go_package = "transactionspb"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option java_package = "com.transactions"; + +import "google/api/annotations.proto"; +import "google/protobuf/timestamp.proto"; +import "protoc-gen-swagger/options/annotations.proto"; + +message TransactionStatusRequest { + string transaction_id = 1; +} + +message TransactionStatusResponse { + string transaction_id = 1; + string status = 2; + string message = 3; + google.protobuf.Timestamp last_updated = 4; +} + +service TransactionService { + rpc GetTransactionStatus(TransactionStatusRequest) returns (TransactionStatusResponse) { + option (google.api.http) = { + get: "/transaction/{transaction_id}" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get Transaction Status" + }; + } +} diff --git a/transactions/bootstrapper.go b/transactions/bootstrapper.go index f791cb08a..6fd3e57bf 100644 --- a/transactions/bootstrapper.go +++ b/transactions/bootstrapper.go @@ -11,6 +11,9 @@ const ( // BootstrappedRepo is the key mapped to transactions.Repository. BootstrappedRepo = "BootstrappedRepo" + + // BootstrappedService is the key to mapped transactions.Service + BootstrappedService = "BootstrappedService" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -25,5 +28,8 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { txRepo := NewRepository(repo) ctx[BootstrappedRepo] = txRepo + + txSrv := NewService(txRepo) + ctx[BootstrappedService] = txSrv return nil } diff --git a/transactions/bootstrapper_test.go b/transactions/bootstrapper_test.go index c0c0eccfd..493210043 100644 --- a/transactions/bootstrapper_test.go +++ b/transactions/bootstrapper_test.go @@ -23,4 +23,5 @@ func TestBootstrapper_Bootstrap(t *testing.T) { err = b.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRepo]) + assert.NotNil(t, ctx[BootstrappedService]) } diff --git a/transactions/handler.go b/transactions/handler.go new file mode 100644 index 000000000..8f750109e --- /dev/null +++ b/transactions/handler.go @@ -0,0 +1,34 @@ +package transactions + +import ( + "context" + + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/satori/go.uuid" +) + +// ErrInvalidTransactionID error for Invalid transaction ID. +const ErrInvalidTransactionID = errors.Error("Invalid Transaction ID") + +// GRPCHandler returns an implementation of the TransactionServiceServer +func GRPCHandler(srv Service) transactionspb.TransactionServiceServer { + return grpcHandler{srv: srv} +} + +// grpcHandler implements transactionspb.TransactionServiceServer +type grpcHandler struct { + srv Service +} + +// GetTransactionStatus returns transaction status of the given transaction id. +func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactionspb.TransactionStatusRequest) (*transactionspb.TransactionStatusResponse, error) { + identity := common.DummyIdentity + id := uuid.FromStringOrNil(req.TransactionId) + if id == uuid.Nil { + return nil, ErrInvalidTransactionID + } + + return h.srv.GetTransactionStatus(identity, id) +} diff --git a/transactions/handler_test.go b/transactions/handler_test.go new file mode 100644 index 000000000..c185c41bb --- /dev/null +++ b/transactions/handler_test.go @@ -0,0 +1,49 @@ +// +build unit + +package transactions + +import ( + "context" + "testing" + + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/stretchr/testify/assert" +) + +func TestGRPCHandler_GetTransactionStatus(t *testing.T) { + h := GRPCHandler(ctx[BootstrappedService].(Service)) + req := new(transactionspb.TransactionStatusRequest) + ctxl := context.Background() + + // empty ID + res, err := h.GetTransactionStatus(ctxl, req) + assert.Nil(t, res) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrInvalidTransactionID, err)) + + // invalid ID + req.TransactionId = "invalid id" + res, err = h.GetTransactionStatus(ctxl, req) + assert.Nil(t, res) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrInvalidTransactionID, err)) + + // missing err + tx := NewTransaction(common.DummyIdentity, "") + req.TransactionId = tx.ID.String() + res, err = h.GetTransactionStatus(ctxl, req) + assert.Nil(t, res) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + + repo := ctx[BootstrappedRepo].(Repository) + assert.Nil(t, repo.Save(tx)) + + // success + res, err = h.GetTransactionStatus(ctxl, req) + assert.Nil(t, err) + assert.Equal(t, tx.ID.String(), res.TransactionId) + assert.Equal(t, string(tx.Status), res.Status) +} diff --git a/transactions/service.go b/transactions/service.go new file mode 100644 index 000000000..e91a70185 --- /dev/null +++ b/transactions/service.go @@ -0,0 +1,46 @@ +package transactions + +import ( + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" +) + +// Service wraps the repository and exposes specific functions. +type Service interface { + GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) +} + +// NewService returns a Service implementation. +func NewService(repo Repository) Service { + return service{repo: repo} +} + +// service implements Service. +type service struct { + repo Repository +} + +// GetTransactionStatus returns the transaction status associated with identity and id. +func (s service) GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { + tx, err := s.repo.Get(identity, id) + if err != nil { + return nil, err + } + + var msg string + lastUpdated := tx.CreatedAt.UTC() + if len(tx.Logs) > 0 { + log := tx.Logs[len(tx.Logs)-1] + msg = log.Message + lastUpdated = log.CreatedAt.UTC() + } + + return &transactionspb.TransactionStatusResponse{ + TransactionId: tx.ID.String(), + Status: string(tx.Status), + Message: msg, + LastUpdated: utils.ToTimestamp(lastUpdated), + }, nil +} diff --git a/transactions/service_test.go b/transactions/service_test.go new file mode 100644 index 000000000..4fca799e4 --- /dev/null +++ b/transactions/service_test.go @@ -0,0 +1,54 @@ +// +build unit + +package transactions + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" +) + +func TestService_GetTransaction(t *testing.T) { + repo := ctx[BootstrappedRepo].(Repository) + srv := ctx[BootstrappedService].(Service) + + identity := common.Address([20]byte{}) + bytes := utils.RandomSlice(common.AddressLength) + assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) + txn := NewTransaction(identity, "Some transaction") + + // no transaction + txs, err := srv.GetTransactionStatus(identity, txn.ID) + assert.Nil(t, txs) + assert.NotNil(t, err) + assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + + txn.Status = Pending + assert.Nil(t, repo.Save(txn)) + + // pending with no log + txs, err = srv.GetTransactionStatus(identity, txn.ID) + assert.Nil(t, err) + assert.NotNil(t, txs) + assert.Equal(t, txs.TransactionId, txn.ID.String()) + assert.Equal(t, string(Pending), txs.Status) + assert.Empty(t, txs.Message) + assert.Equal(t, utils.ToTimestamp(txn.CreatedAt), txs.LastUpdated) + + log := NewLog("action", "some message") + txn.Logs = append(txn.Logs, log) + txn.Status = Success + assert.Nil(t, repo.Save(txn)) + + // log with message + txs, err = srv.GetTransactionStatus(identity, txn.ID) + assert.Nil(t, err) + assert.NotNil(t, txs) + assert.Equal(t, txs.TransactionId, txn.ID.String()) + assert.Equal(t, string(Success), txs.Status) + assert.Equal(t, log.Message, txs.Message) + assert.Equal(t, utils.ToTimestamp(log.CreatedAt), txs.LastUpdated) +} diff --git a/transactions/transaction.go b/transactions/transaction.go index cb573c310..2510c2650 100644 --- a/transactions/transaction.go +++ b/transactions/transaction.go @@ -10,28 +10,28 @@ import ( ) // Status represents the status of the transaction -type Status uint8 +type Status string // Status constants const ( - Success Status = iota - Failed - Pending + Success Status = "success" + Failed Status = "failed" + Pending Status = "pending" ) // Log represents a single task in a transaction. type Log struct { - Action string - Message string - Time time.Time + Action string + Message string + CreatedAt time.Time } // NewLog constructs a new log with action and message func NewLog(action, message string) Log { return Log{ - Action: action, - Message: message, - Time: time.Now().UTC(), + Action: action, + Message: message, + CreatedAt: time.Now().UTC(), } } @@ -43,6 +43,7 @@ type Transaction struct { Status Status Logs []Log Metadata map[string]string + CreatedAt time.Time } // JSON returns json marshaled transaction. @@ -68,5 +69,6 @@ func NewTransaction(identity common.Address, description string) *Transaction { Description: description, Status: Pending, Metadata: make(map[string]string), + CreatedAt: time.Now().UTC(), } } From 6c5cded7e52463ff8faf7a6ac774854702bdf529 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 26 Dec 2018 22:14:05 +0100 Subject: [PATCH 103/220] Minor refactors (#600) * remove signature package * keytools => crypto * remove signature package * refactor bootstrappers * rename contextheader --- anchors/anchor_repository_integration_test.go | 4 +- anchors/ethereum_anchor_repository_test.go | 2 +- api/server_test.go | 2 +- .../bootstrappers}/bootstrapper.go | 6 +- .../bootstrappers}/bootstrapper_test.go | 2 +- .../testingbootstrap/testing_bootstrap.go | 2 +- .../testlogging/test_bootstrapper.go | 0 cmd/centrifuge/generate_signing_key.go | 4 +- cmd/centrifuge/sign_message.go | 4 +- cmd/centrifuge/verify_message.go | 4 +- cmd/common.go | 15 ++--- config/repository_test.go | 2 +- {header => context}/context.go | 14 ++--- coredocument/coredocument_test.go | 7 ++- coredocument/processor.go | 27 ++++----- coredocument/processor_test.go | 17 +++--- coredocument/validator.go | 5 +- coredocument/validator_test.go | 7 ++- {keytools => crypto}/ed25519/ed25519.go | 0 {keytools => crypto}/ed25519/ed25519_test.go | 0 {keytools => crypto}/generate.go | 6 +- {keytools => crypto}/generate_test.go | 2 +- {keytools => crypto}/keytools.go | 2 +- {keytools => crypto}/secp256k1/secp256k1.go | 0 .../secp256k1/secp256k1_test.go | 2 +- crypto/sign.go | 56 +++++++++++++++++++ {keytools => crypto}/sign_test.go | 38 ++++++++++++- {keytools => crypto}/verify.go | 4 +- {keytools => crypto}/verify_test.go | 2 +- documents/anchor.go | 12 ++-- documents/genericdoc/service.go | 10 ++-- documents/genericdoc/service_test.go | 12 ++-- documents/invoice/handler.go | 8 +-- documents/invoice/handler_test.go | 17 +++--- documents/invoice/model.go | 5 +- documents/invoice/model_test.go | 9 +-- documents/invoice/service.go | 26 +++++---- documents/invoice/service_test.go | 19 ++++--- documents/invoice/validator_test.go | 5 +- documents/model_test.go | 2 +- documents/purchaseorder/handler.go | 7 ++- documents/purchaseorder/handler_test.go | 15 ++--- documents/purchaseorder/model.go | 5 +- documents/purchaseorder/model_test.go | 9 +-- documents/purchaseorder/service.go | 26 +++++---- documents/purchaseorder/service_test.go | 19 ++++--- documents/purchaseorder/validator_test.go | 5 +- documents/service.go | 4 +- documents/test/anchor_test.go | 5 +- ethereum/geth_client_integration_test.go | 2 +- ethereum/geth_client_test.go | 2 +- identity/ethereum_identity.go | 7 ++- .../ethereum_identity_integration_test.go | 2 +- identity/identity.go | 9 +-- identity/identity_test.go | 5 +- keytools/sign.go | 29 ---------- nft/payment_obligation_integration_test.go | 7 ++- notification/notification_test.go | 2 +- p2p/client.go | 7 ++- p2p/grpc/handler.go | 5 +- p2p/grpc/handler_integration_test.go | 4 +- p2p/grpc/handler_test.go | 2 +- p2p/server.go | 2 +- p2p/server_test.go | 2 +- signatures/signatures.go | 31 ---------- signatures/signatures_test.go | 44 --------------- testingutils/coredocument/coredocument.go | 14 ++--- testingutils/documents/documents.go | 4 +- testworld/park.go | 5 +- transactions/repository_test.go | 2 +- 70 files changed, 330 insertions(+), 313 deletions(-) rename {context => bootstrap/bootstrappers}/bootstrapper.go (96%) rename {context => bootstrap/bootstrappers}/bootstrapper_test.go (91%) rename {context => bootstrap/bootstrappers}/testingbootstrap/testing_bootstrap.go (95%) rename {context => bootstrap/bootstrappers}/testlogging/test_bootstrapper.go (100%) rename {header => context}/context.go (66%) rename {keytools => crypto}/ed25519/ed25519.go (100%) rename {keytools => crypto}/ed25519/ed25519_test.go (100%) rename {keytools => crypto}/generate.go (84%) rename {keytools => crypto}/generate_test.go (98%) rename {keytools => crypto}/keytools.go (93%) rename {keytools => crypto}/secp256k1/secp256k1.go (100%) rename {keytools => crypto}/secp256k1/secp256k1_test.go (98%) create mode 100644 crypto/sign.go rename {keytools => crypto}/sign_test.go (54%) rename {keytools => crypto}/verify.go (91%) rename {keytools => crypto}/verify_test.go (97%) delete mode 100644 keytools/sign.go delete mode 100644 signatures/signatures.go delete mode 100644 signatures/signatures_test.go diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index db9b29c23..3e66a56e8 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -8,10 +8,10 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/anchors" - cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" + cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/ethereum_anchor_repository_test.go index 20d81a7e1..355181a46 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/ethereum_anchor_repository_test.go @@ -6,9 +6,9 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/api/server_test.go b/api/server_test.go index 0de14b796..ce9d66a7c 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -12,9 +12,9 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" diff --git a/context/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go similarity index 96% rename from context/bootstrapper.go rename to bootstrap/bootstrappers/bootstrapper.go index 2442ad1ff..422a8d405 100644 --- a/context/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -1,4 +1,4 @@ -package context +package bootstrappers import ( "github.com/centrifuge/go-centrifuge/anchors" @@ -17,10 +17,10 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/version" - logging "github.com/ipfs/go-log" + log2 "github.com/ipfs/go-log" ) -var log = logging.Logger("context") +var log = log2.Logger("context") // MainBootstrapper holds all the bootstrapper implementations type MainBootstrapper struct { diff --git a/context/bootstrapper_test.go b/bootstrap/bootstrappers/bootstrapper_test.go similarity index 91% rename from context/bootstrapper_test.go rename to bootstrap/bootstrappers/bootstrapper_test.go index 6ed5a1e97..1e93a352a 100644 --- a/context/bootstrapper_test.go +++ b/bootstrap/bootstrappers/bootstrapper_test.go @@ -1,6 +1,6 @@ // +build unit -package context +package bootstrappers import ( "testing" diff --git a/context/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go similarity index 95% rename from context/testingbootstrap/testing_bootstrap.go rename to bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 350ee5d64..b4346b1b7 100644 --- a/context/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -5,8 +5,8 @@ package testingbootstrap import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" diff --git a/context/testlogging/test_bootstrapper.go b/bootstrap/bootstrappers/testlogging/test_bootstrapper.go similarity index 100% rename from context/testlogging/test_bootstrapper.go rename to bootstrap/bootstrappers/testlogging/test_bootstrapper.go diff --git a/cmd/centrifuge/generate_signing_key.go b/cmd/centrifuge/generate_signing_key.go index 5ed688490..fd0a9d959 100644 --- a/cmd/centrifuge/generate_signing_key.go +++ b/cmd/centrifuge/generate_signing_key.go @@ -1,7 +1,7 @@ package main import ( - "github.com/centrifuge/go-centrifuge/keytools" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/spf13/cobra" ) @@ -21,7 +21,7 @@ func init() { Long: ``, Run: func(cmd *cobra.Command, args []string) { if createSigningKeyParam { - keytools.GenerateSigningKeyPair(publicKeyFileParam, privateKeyFileParam, curveTypeParam) + crypto.GenerateSigningKeyPair(publicKeyFileParam, privateKeyFileParam, curveTypeParam) } if createEncryptionKeyParam { panic("Not implemented") diff --git a/cmd/centrifuge/sign_message.go b/cmd/centrifuge/sign_message.go index a69ef7892..b0bf989a0 100644 --- a/cmd/centrifuge/sign_message.go +++ b/cmd/centrifuge/sign_message.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/centrifuge/go-centrifuge/keytools" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/spf13/cobra" @@ -27,7 +27,7 @@ func init() { if err != nil { log.Fatal(err) } - signature, err := keytools.SignMessage(privateKey, []byte(messageParam), curveTypeParam, ethereumSignFlag) + signature, err := crypto.SignMessage(privateKey, []byte(messageParam), curveTypeParam, ethereumSignFlag) if err != nil { log.Fatal(err) } diff --git a/cmd/centrifuge/verify_message.go b/cmd/centrifuge/verify_message.go index 5424a171b..28d0d4bed 100644 --- a/cmd/centrifuge/verify_message.go +++ b/cmd/centrifuge/verify_message.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/centrifuge/go-centrifuge/keytools" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/spf13/cobra" @@ -33,7 +33,7 @@ func init() { if err != nil { log.Fatal(err) } - correct := keytools.VerifyMessage(publicKey, []byte(messageParam), signatureBytes, curveTypeParam, ethereumSignFlag) + correct := crypto.VerifyMessage(publicKey, []byte(messageParam), signatureBytes, curveTypeParam, ethereumSignFlag) fmt.Println(correct) }, } diff --git a/cmd/common.go b/cmd/common.go index 7152d9b5b..b093154b7 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,15 +3,16 @@ package cmd import ( "context" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" + "github.com/centrifuge/go-centrifuge/storage" logging "github.com/ipfs/go-log" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - c "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/queue" ) @@ -32,9 +33,9 @@ func createIdentity(idService identity.Service) (identity.CentID, error) { func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetSigningKeyPair() ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() - keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - keytools.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - keytools.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") + crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") + crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") + crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } func addKeys(idService identity.Service) error { @@ -112,7 +113,7 @@ func CreateConfig( // RunBootstrap bootstraps the node for running func RunBootstrap(cfgFile string) { - mb := c.MainBootstrapper{} + mb := bootstrappers.MainBootstrapper{} mb.PopulateRunBootstrappers() ctx := map[string]interface{}{} ctx[config.BootstrappedConfigFile] = cfgFile @@ -125,7 +126,7 @@ func RunBootstrap(cfgFile string) { // BaseBootstrap bootstraps the node for testing purposes mainly func BaseBootstrap(cfgFile string) map[string]interface{} { - mb := c.MainBootstrapper{} + mb := bootstrappers.MainBootstrapper{} mb.PopulateBaseBootstrappers() ctx := map[string]interface{}{} ctx[config.BootstrappedConfigFile] = cfgFile diff --git a/config/repository_test.go b/config/repository_test.go index ba0439d29..ac4693b85 100644 --- a/config/repository_test.go +++ b/config/repository_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" diff --git a/header/context.go b/context/context.go similarity index 66% rename from header/context.go rename to context/context.go index 3e164ee7b..d8db00f3a 100644 --- a/header/context.go +++ b/context/context.go @@ -1,4 +1,4 @@ -package header +package context import ( "context" @@ -8,28 +8,28 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -// ContextHeader holds custom request objects to pass down the pipeline. -type ContextHeader struct { +// Header holds custom request objects to pass down the pipeline. +type Header struct { context context.Context self *identity.IDConfig } // NewContextHeader creates new instance of the request headers. -func NewContextHeader(context context.Context, config config.Configuration) (*ContextHeader, error) { +func NewContextHeader(context context.Context, config config.Configuration) (*Header, error) { idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) if err != nil { return nil, errors.New("failed to get id config: %v", err) } - return &ContextHeader{self: idConfig, context: context}, nil + return &Header{self: idConfig, context: context}, nil } // Self returns Self CentID. -func (h *ContextHeader) Self() *identity.IDConfig { +func (h *Header) Self() *identity.IDConfig { return h.self } // Context returns context.Context of the request. -func (h *ContextHeader) Context() context.Context { +func (h *Header) Context() context.Context { return h.context } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index bfccd4045..1468dee5f 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -9,11 +9,12 @@ import ( "os" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -244,7 +245,7 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) collaborators, err := GetExternalCollaborators(ctxh.Self().ID, cd) assert.Nil(t, err) @@ -259,7 +260,7 @@ func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) cd.Collaborators[1] = utils.RandomSlice(5) - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) _, err = GetExternalCollaborators(ctxh.Self().ID, cd) assert.NotNil(t, err) diff --git a/coredocument/processor.go b/coredocument/processor.go index dd029cf81..9bfbf66ba 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -4,15 +4,16 @@ import ( "context" "time" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" logging "github.com/ipfs/go-log" @@ -30,19 +31,19 @@ type Config interface { // Processor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type Processor interface { - Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) - PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error - RequestSignatures(ctx *header.ContextHeader, model documents.Model) error + Send(ctx *context2.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) + PrepareForSignatureRequests(ctx *context2.Header, model documents.Model) error + RequestSignatures(ctx *context2.Header, model documents.Model) error PrepareForAnchoring(model documents.Model) error - AnchorDocument(ctx *header.ContextHeader, model documents.Model) error - SendDocument(ctx *header.ContextHeader, model documents.Model) error + AnchorDocument(ctx *context2.Header, model documents.Model) error + SendDocument(ctx *context2.Header, model documents.Model) error } // client defines the methods for p2pclient // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // defaultProcessor implements Processor interface @@ -64,7 +65,7 @@ func DefaultProcessor(idService identity.Service, p2pClient client, repository a } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (dp defaultProcessor) Send(ctx *context2.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { if coreDocument == nil { return centerrors.NilError(coreDocument) } @@ -97,7 +98,7 @@ func (dp defaultProcessor) Send(ctx *header.ContextHeader, coreDocument *coredoc } // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature -func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error { +func (dp defaultProcessor) PrepareForSignatureRequests(ctx *context2.Header, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -122,7 +123,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, -func (dp defaultProcessor) RequestSignatures(ctx *header.ContextHeader, model documents.Model) error { +func (dp defaultProcessor) RequestSignatures(ctx *context2.Header, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -179,7 +180,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { } // AnchorDocument validates the model, and anchors the document -func (dp defaultProcessor) AnchorDocument(ctx *header.ContextHeader, model documents.Model) error { +func (dp defaultProcessor) AnchorDocument(ctx *context2.Header, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -229,7 +230,7 @@ func (dp defaultProcessor) AnchorDocument(ctx *header.ContextHeader, model docum } // SendDocument does post anchor validations and sends the document to collaborators -func (dp defaultProcessor) SendDocument(ctx *header.ContextHeader, model documents.Model) error { +func (dp defaultProcessor) SendDocument(ctx *context2.Header, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index b4826fa89..9bf95bc34 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -6,11 +6,12 @@ import ( "context" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -48,7 +49,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) @@ -70,10 +71,10 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - ctxh, err = header.NewContextHeader(context.Background(), cfg) + ctxh, err = context2.NewContextHeader(context.Background(), cfg) assert.NotNil(t, err) cfg.Set("keys.signing.publicKey", pub) - ctxh, err = header.NewContextHeader(context.Background(), cfg) + ctxh, err = context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // failed unpack @@ -105,7 +106,7 @@ type p2pClient struct { client } -func (p p2pClient) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (p p2pClient) GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { args := p.Called(ctx, doc) return args.Error(0) } @@ -114,7 +115,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) // pack failed model := mockModel{} @@ -262,7 +263,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) // pack failed @@ -358,7 +359,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) // pack failed model := mockModel{} diff --git a/coredocument/validator.go b/coredocument/validator.go index ff39ff592..646177a54 100644 --- a/coredocument/validator.go +++ b/coredocument/validator.go @@ -3,13 +3,14 @@ package coredocument import ( "fmt" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -213,7 +214,7 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) documents.Valida return errors.New("expecting only one signature") } - s := signatures.Sign(centIDBytes, priv, pub, cd.SigningRoot) + s := crypto.Sign(centIDBytes, priv, pub, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { err = errors.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 3b7a64e6f..c2177fa9e 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -5,13 +5,14 @@ package coredocument import ( "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "context" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -206,7 +207,7 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] rfsv := readyForSignaturesValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) @@ -537,7 +538,7 @@ func TestPostAnchoredValidator(t *testing.T) { } func TestPreSignatureRequestValidator(t *testing.T) { - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] psv := PreSignatureRequestValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) diff --git a/keytools/ed25519/ed25519.go b/crypto/ed25519/ed25519.go similarity index 100% rename from keytools/ed25519/ed25519.go rename to crypto/ed25519/ed25519.go diff --git a/keytools/ed25519/ed25519_test.go b/crypto/ed25519/ed25519_test.go similarity index 100% rename from keytools/ed25519/ed25519_test.go rename to crypto/ed25519/ed25519_test.go diff --git a/keytools/generate.go b/crypto/generate.go similarity index 84% rename from keytools/generate.go rename to crypto/generate.go index 5806d67f8..b6566da1c 100644 --- a/keytools/generate.go +++ b/crypto/generate.go @@ -1,10 +1,10 @@ -package keytools +package crypto import ( "strings" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" ) diff --git a/keytools/generate_test.go b/crypto/generate_test.go similarity index 98% rename from keytools/generate_test.go rename to crypto/generate_test.go index 0dd9c1a7c..691cd73c5 100644 --- a/keytools/generate_test.go +++ b/crypto/generate_test.go @@ -1,6 +1,6 @@ // +build unit -package keytools +package crypto import ( "os" diff --git a/keytools/keytools.go b/crypto/keytools.go similarity index 93% rename from keytools/keytools.go rename to crypto/keytools.go index c17c79bde..d894d942d 100644 --- a/keytools/keytools.go +++ b/crypto/keytools.go @@ -1,4 +1,4 @@ -package keytools +package crypto import ( logging "github.com/ipfs/go-log" diff --git a/keytools/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go similarity index 100% rename from keytools/secp256k1/secp256k1.go rename to crypto/secp256k1/secp256k1.go diff --git a/keytools/secp256k1/secp256k1_test.go b/crypto/secp256k1/secp256k1_test.go similarity index 98% rename from keytools/secp256k1/secp256k1_test.go rename to crypto/secp256k1/secp256k1_test.go index 43458b380..bda1c7032 100644 --- a/keytools/secp256k1/secp256k1_test.go +++ b/crypto/secp256k1/secp256k1_test.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) diff --git a/crypto/sign.go b/crypto/sign.go new file mode 100644 index 000000000..99d4d1ef9 --- /dev/null +++ b/crypto/sign.go @@ -0,0 +1,56 @@ +package crypto + +import ( + errors2 "errors" + "strings" + "time" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/utils" + "golang.org/x/crypto/ed25519" + + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/centrifuge/go-centrifuge/errors" +) + +// SignMessage signs the message using the private key as the curveType provided. +// if ethereumSign is true, then the signature format is specific to ethereum. +func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool) ([]byte, error) { + curveType = strings.ToLower(curveType) + switch curveType { + case CurveSecp256K1: + msg := make([]byte, MaxMsgLen) + copy(msg, message) + if ethereumSign { + return secp256k1.SignEthereum(msg, privateKey) + } + + return secp256k1.Sign(msg, privateKey) + case CurveEd25519: + return nil, errors.New("curve ed25519 not supported yet") + default: + return nil, errors.New("curve %s not supported", curveType) + } + +} + +// VerifySignature verifies the signature using ed25519 +func VerifySignature(pubKey, message, signature []byte) error { + valid := ed25519.Verify(pubKey, message, signature) + if !valid { + return errors2.New("invalid signature") + } + + return nil +} + +// Sign the document with the private key and return the signature along with the public key for the verification +// assumes that signing root for the document is generated +func Sign(centIDBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { + return &coredocumentpb.Signature{ + EntityId: centIDBytes, + PublicKey: pubKey, + Signature: ed25519.Sign(privateKey, payload), + Timestamp: utils.ToTimestamp(time.Now().UTC()), + } +} diff --git a/keytools/sign_test.go b/crypto/sign_test.go similarity index 54% rename from keytools/sign_test.go rename to crypto/sign_test.go index a4f392d85..a184b66e2 100644 --- a/keytools/sign_test.go +++ b/crypto/sign_test.go @@ -1,18 +1,52 @@ // +build unit -package keytools +package crypto import ( "fmt" "os" "testing" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) +var ( + key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + id1 = []byte{1, 1, 1, 1, 1, 1} + signature = []byte{0x4e, 0x3d, 0x90, 0x5f, 0x25, 0xc7, 0x90, 0x63, 0x7e, 0x6c, 0xd0, 0xe6, 0xc7, 0xbd, 0xe6, 0x81, 0x3b, 0xd0, 0x5b, 0x94, 0x76, 0x86, 0x4e, 0xcb, 0xb9, 0x36, 0x48, 0x44, 0x4b, 0x98, 0xd2, 0x4b, 0x6a, 0x65, 0x22, 0x92, 0x1c, 0x8a, 0xdb, 0xfe, 0xb7, 0x6f, 0xfe, 0x34, 0x52, 0xa3, 0x49, 0xe4, 0xda, 0xdc, 0x5d, 0x1b, 0x0, 0x79, 0x54, 0x60, 0x29, 0x22, 0x94, 0xb, 0x3c, 0x90, 0x3c, 0x3} +) + +func TestSign(t *testing.T) { + sig := Sign(id1, key1, key1Pub, key1Pub) + assert.NotNil(t, sig) + assert.Equal(t, sig.PublicKey, []byte(key1Pub)) + assert.Equal(t, sig.EntityId, id1) + assert.NotEmpty(t, sig.Signature) + assert.Len(t, sig.Signature, 64) + assert.Equal(t, sig.Signature, signature) + assert.NotNil(t, sig.Timestamp, "must be non nil") +} + +func TestValidateSignature_invalid_sig(t *testing.T) { + pubKey := key1Pub + message := key1Pub + signature := utils.RandomSlice(32) + err := VerifySignature(pubKey, message, signature) + assert.NotNil(t, err, "must be not nil") + assert.Contains(t, err.Error(), "invalid signature") +} + +func TestValidateSignature_success(t *testing.T) { + pubKey := key1Pub + message := key1Pub + err := VerifySignature(pubKey, message, signature) + assert.Nil(t, err, "must be nil") +} + func TestSignMessage(t *testing.T) { publicKeyFile := "publicKey" diff --git a/keytools/verify.go b/crypto/verify.go similarity index 91% rename from keytools/verify.go rename to crypto/verify.go index 37f318d76..8a368a434 100644 --- a/keytools/verify.go +++ b/crypto/verify.go @@ -1,7 +1,7 @@ -package keytools +package crypto import ( - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/ethereum/go-ethereum/common/hexutil" ) diff --git a/keytools/verify_test.go b/crypto/verify_test.go similarity index 97% rename from keytools/verify_test.go rename to crypto/verify_test.go index d87fec21d..e389c1891 100644 --- a/keytools/verify_test.go +++ b/crypto/verify_test.go @@ -1,6 +1,6 @@ // +build unit -package keytools +package crypto import ( "os" diff --git a/documents/anchor.go b/documents/anchor.go index 558c468d5..8d9d79c13 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -1,19 +1,19 @@ package documents import ( + "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" ) // anchorProcessor has same methods to coredoc processor // this is to avoid import cycles // this will disappear once we have queueing logic in place type anchorProcessor interface { - PrepareForSignatureRequests(ctx *header.ContextHeader, model Model) error - RequestSignatures(ctx *header.ContextHeader, model Model) error + PrepareForSignatureRequests(ctx *context.Header, model Model) error + RequestSignatures(ctx *context.Header, model Model) error PrepareForAnchoring(model Model) error - AnchorDocument(ctx *header.ContextHeader, model Model) error - SendDocument(ctx *header.ContextHeader, model Model) error + AnchorDocument(ctx *context.Header, model Model) error + SendDocument(ctx *context.Header, model Model) error } // updaterFunc is a wrapper that will be called to save the state of the model between processor steps @@ -21,7 +21,7 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators -func AnchorDocument(ctx *header.ContextHeader, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { +func AnchorDocument(ctx *context.Header, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { cd, err := model.PackCoreDocument() if err != nil { return nil, err diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 25741ce37..ccc3adf95 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -4,9 +4,12 @@ import ( "bytes" "time" + "github.com/centrifuge/go-centrifuge/context" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" @@ -19,7 +22,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" logging "github.com/ipfs/go-log" ) @@ -126,7 +128,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume return nil, nil } -func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -142,7 +144,7 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index e9cd4b9f5..effeff866 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -8,14 +8,14 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/header" + context2 "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/mock" @@ -256,7 +256,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) i.CoreDocument.SigningRoot = nil - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 0cf9a091e..bcd345b06 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -3,6 +3,8 @@ package invoice import ( "fmt" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" @@ -12,8 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" "golang.org/x/net/context" - - "github.com/centrifuge/go-centrifuge/header" ) var apiLog = logging.Logger("invoice-api") @@ -41,7 +41,7 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - ctxHeader, err := header.NewContextHeader(ctx, h.config) + ctxHeader, err := context2.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -72,7 +72,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := header.NewContextHeader(ctx, h.config) + ctxHeader, err := context2.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index cdf518c1b..211b0e937 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,10 +6,11 @@ import ( "context" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" @@ -21,13 +22,13 @@ type mockService struct { mock.Mock } -func (m *mockService) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { +func (m *mockService) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context2.Header) (documents.Model, error) { args := m.Called(payload, contextHeader) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m *mockService) Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { +func (m *mockService) Create(ctx *context2.Header, inv documents.Model) (documents.Model, error) { args := m.Called(ctx, inv) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) @@ -57,13 +58,13 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { +func (m *mockService) Update(ctx *context2.Header, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) doc1, _ := args.Get(0).(documents.Model) return doc1, args.Error(1) } -func (m *mockService) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { +func (m *mockService) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *context2.Header) (documents.Model, error) { args := m.Called(payload, contextHeader) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) @@ -237,7 +238,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() @@ -254,7 +255,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() @@ -272,7 +273,7 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{} diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 58ddb4d75..538d4b649 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -5,12 +5,13 @@ import ( "encoding/json" "reflect" + "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/precise-proofs/proofs" @@ -148,7 +149,7 @@ func (i *Invoice) createP2PProtobuf() *invoicepb.InvoiceData { } // InitInvoiceInput initialize the model based on the received parameters from the rest api call -func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) error { +func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context.Header) error { err := i.initInvoiceFromData(payload.Data) if err != nil { return err diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index c7a455cc0..13c87bc30 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -9,16 +9,17 @@ import ( "reflect" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -183,7 +184,7 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // fail recipient data := &clientinvoicepb.InvoiceData{ @@ -243,7 +244,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - ctxHeader, err := header.NewContextHeader(context.Background(), cfg) + ctxHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) m := new(Invoice) err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), ctxHeader) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 7e9f48ccf..672a6a397 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -4,6 +4,10 @@ import ( "bytes" "time" + "github.com/centrifuge/go-centrifuge/context" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -12,11 +16,9 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" @@ -30,16 +32,16 @@ type Service interface { documents.Service // DeriverFromPayload derives Invoice from clientPayload - DeriveFromCreatePayload(*clientinvoicepb.InvoiceCreatePayload, *header.ContextHeader) (documents.Model, error) + DeriveFromCreatePayload(*clientinvoicepb.InvoiceCreatePayload, *context.Header) (documents.Model, error) // DeriveFromUpdatePayload derives invoice model from update payload - DeriveFromUpdatePayload(*clientinvoicepb.InvoiceUpdatePayload, *header.ContextHeader) (documents.Model, error) + DeriveFromUpdatePayload(*clientinvoicepb.InvoiceUpdatePayload, *context.Header) (documents.Model, error) // Create validates and persists invoice Model and returns a Updated model - Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) + Create(ctx *context.Header, inv documents.Model) (documents.Model, error) // Update validates and updates the invoice model and return the updated model - Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) + Update(ctx *context.Header, inv documents.Model) (documents.Model, error) // DeriveInvoiceData returns the invoice data as client data DeriveInvoiceData(inv documents.Model) (*clientinvoicepb.InvoiceData, error) @@ -117,7 +119,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call -func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context.Header) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -166,7 +168,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { +func (s service) Create(ctx *context.Header, inv documents.Model) (documents.Model, error) { inv, err := s.calculateDataRoot(nil, inv, CreateValidator()) if err != nil { return nil, err @@ -191,7 +193,7 @@ func (s service) updater(id []byte, model documents.Model) error { } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx *header.ContextHeader, inv documents.Model) (documents.Model, error) { +func (s service) Update(ctx *context.Header, inv documents.Model) (documents.Model, error) { cd, err := inv.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) @@ -310,7 +312,7 @@ func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.Invoic } // DeriveFromUpdatePayload returns a new version of the old invoice identified by identifier in payload -func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *header.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *context.Header) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -349,7 +351,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP } // RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature -func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -365,7 +367,7 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 12e12d55f..5a2cf57f4 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -7,12 +7,13 @@ import ( "math/big" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/storage" @@ -108,7 +109,7 @@ func TestService_DeriveFromPayload(t *testing.T) { _, err = invSrv.DeriveFromCreatePayload(&clientinvoicepb.InvoiceCreatePayload{}, nil) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) model, err = invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") @@ -214,7 +215,7 @@ func TestService_Exists(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) _, srv := getServiceWithMockedLayers() invSrv := srv.(service) @@ -266,7 +267,7 @@ func TestService_DeriveInvoiceData(t *testing.T) { // success payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "must be non nil") @@ -279,7 +280,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // success invSrv := service{repo: testRepo()} payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv1, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) assert.Nil(t, err, "must be non nil") @@ -386,7 +387,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) i.CoreDocument.SigningRoot = nil - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) signature, err := invSrv.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) @@ -501,7 +502,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) @@ -571,7 +572,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_Update(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack failed @@ -651,7 +652,7 @@ func TestService_Update(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // type mismatch diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 3f3dc9fd3..54b029b38 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -5,11 +5,12 @@ package invoice import ( "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "context" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -81,7 +82,7 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) inv := new(Invoice) err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) diff --git a/documents/model_test.go b/documents/model_test.go index 0a54b681a..5c1164847 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/storage" ) diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 11e540977..5c37af85b 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -3,13 +3,14 @@ package purchaseorder import ( "fmt" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" @@ -41,7 +42,7 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - ctxh, err := header.NewContextHeader(ctx, h.config) + ctxh, err := context2.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, err.Error()) @@ -72,7 +73,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := header.NewContextHeader(ctx, h.config) + ctxHeader, err := context2.NewContextHeader(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index b81d677c1..a9ce0ae55 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,10 +6,11 @@ import ( "context" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,19 +23,19 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { +func (m mockService) Create(ctx *context2.Header, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) Update(ctx *header.ContextHeader, doc documents.Model) (documents.Model, error) { +func (m mockService) Update(ctx *context2.Header, doc documents.Model) (documents.Model, error) { args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) DeriveFromCreatePayload(req *clientpopb.PurchaseOrderCreatePayload, ctxh *header.ContextHeader) (documents.Model, error) { +func (m mockService) DeriveFromCreatePayload(req *clientpopb.PurchaseOrderCreatePayload, ctxh *context2.Header) (documents.Model, error) { args := m.Called(req, ctxh) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) @@ -64,7 +65,7 @@ func (m mockService) DerivePurchaseOrderResponse(po documents.Model) (*clientpop return data, args.Error(1) } -func (m mockService) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxh *header.ContextHeader) (documents.Model, error) { +func (m mockService) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxh *context2.Header) (documents.Model, error) { args := m.Called(payload, ctxh) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) @@ -75,7 +76,7 @@ func TestGRPCHandler_Create(t *testing.T) { req := testingdocuments.CreatePOPayload() ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) // derive fails @@ -131,7 +132,7 @@ func TestGrpcHandler_Update(t *testing.T) { } ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) // derive fails diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 69d544a60..a4ec324aa 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -5,13 +5,14 @@ import ( "encoding/json" "reflect" + "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/precise-proofs/proofs" @@ -147,7 +148,7 @@ func (p *PurchaseOrder) createP2PProtobuf() *purchaseorderpb.PurchaseOrderData { } // InitPurchaseOrderInput initialize the model based on the received parameters from the rest api call -func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, contextHeader *header.ContextHeader) error { +func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, contextHeader *context.Header) error { err := p.initPurchaseOrderFromData(payload.Data) if err != nil { return err diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 0bbd865bb..981cf082f 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -9,16 +9,17 @@ import ( "reflect" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -178,7 +179,7 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ @@ -216,7 +217,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { } func TestPOModel_calculateDataRoot(t *testing.T) { - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) poModel := new(PurchaseOrder) err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index f9973e04b..1c87d36a1 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -4,6 +4,10 @@ import ( "bytes" "time" + "github.com/centrifuge/go-centrifuge/context" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -12,11 +16,9 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" @@ -30,16 +32,16 @@ type Service interface { documents.Service // DeriverFromPayload derives purchase order from clientPayload - DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, hdr *header.ContextHeader) (documents.Model, error) + DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, hdr *context.Header) (documents.Model, error) // DeriveFromUpdatePayload derives purchase order from update payload - DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, hdr *header.ContextHeader) (documents.Model, error) + DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, hdr *context.Header) (documents.Model, error) // Create validates and persists purchase order and returns a Updated model - Create(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) + Create(ctx *context.Header, po documents.Model) (documents.Model, error) // Update validates and updates the purchase order and return the updated model - Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) + Update(ctx *context.Header, po documents.Model) (documents.Model, error) // DerivePurchaseOrderData returns the purchase order data as client data DerivePurchaseOrderData(po documents.Model) (*clientpopb.PurchaseOrderData, error) @@ -110,7 +112,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { +func (s service) Create(ctx *context.Header, po documents.Model) (documents.Model, error) { po, err := s.calculateDataRoot(nil, po, CreateValidator()) if err != nil { return nil, err @@ -135,7 +137,7 @@ func (s service) updater(id []byte, model documents.Model) error { } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx *header.ContextHeader, po documents.Model) (documents.Model, error) { +func (s service) Update(ctx *context.Header, po documents.Model) (documents.Model, error) { cd, err := po.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) @@ -160,7 +162,7 @@ func (s service) Update(ctx *header.ContextHeader, po documents.Model) (document } // DeriveFromCreatePayload derives purchase order from create payload -func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *header.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *context.Header) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -175,7 +177,7 @@ func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreate } // DeriveFromUpdatePayload derives purchase order from update payload -func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *header.ContextHeader) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *context.Header) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -348,7 +350,7 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str // RequestDocumentSignature validates the document and returns the signature // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service -func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -364,7 +366,7 @@ func (s service) RequestDocumentSignature(contextHeader *header.ContextHeader, m if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := signatures.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) + sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index cf2ed76b4..eaebb73e0 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -7,12 +7,13 @@ import ( "math/big" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/storage" @@ -55,7 +56,7 @@ func TestService_Update(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{config: c, repo: testRepo()} - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack failed @@ -149,7 +150,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) @@ -215,7 +216,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_DeriveFromCreatePayload(t *testing.T) { poSrv := service{} - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // nil payload @@ -270,7 +271,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) @@ -497,7 +498,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model _, poSrv := getServiceWithMockedLayers() - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // unknown type @@ -518,7 +519,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { func TestService_DerivePurchaseOrderResponse(t *testing.T) { poSrv := service{} - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // pack fails @@ -688,7 +689,7 @@ func TestService_ReceiveAnchoredDocument(t *testing.T) { } func TestService_RequestDocumentSignature(t *testing.T) { - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) poSrv := service{} s, err := poSrv.RequestDocumentSignature(ctxh, nil) @@ -700,7 +701,7 @@ func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{config: c, repo: testRepo()} - ctxh, err := header.NewContextHeader(context.Background(), cfg) + ctxh, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // type mismatch diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 0dc56c63c..73713394c 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -5,11 +5,12 @@ package purchaseorder import ( "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "context" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -48,7 +49,7 @@ func TestFieldValidator_Validate(t *testing.T) { func TestDataRootValidation_Validate(t *testing.T) { drv := dataRootValidator() - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) // nil error diff --git a/documents/service.go b/documents/service.go index cbe126990..e3c8581af 100644 --- a/documents/service.go +++ b/documents/service.go @@ -3,7 +3,7 @@ package documents import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/header" + "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -44,7 +44,7 @@ type Service interface { CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) // RequestDocumentSignature Validates and Signs document received over the p2p layer - RequestDocumentSignature(contextHeader *header.ContextHeader, model Model) (*coredocumentpb.Signature, error) + RequestDocumentSignature(contextHeader *context.Header, model Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index ab33cfa0c..93b4c3227 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -7,13 +7,14 @@ import ( "errors" "testing" + context2 "github.com/centrifuge/go-centrifuge/context" + "os" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" @@ -35,7 +36,7 @@ func TestMain(m *testing.M) { func TestAnchorDocument(t *testing.T) { ctx := context.Background() - ctxh, err := header.NewContextHeader(ctx, cfg) + ctxh, err := context2.NewContextHeader(ctx, cfg) assert.Nil(t, err) updater := func(id []byte, model documents.Model) error { return nil diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 27adca307..8bc7e03f1 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" + cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/stretchr/testify/assert" ) diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index c7c41edef..eda9c0271 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -10,8 +10,8 @@ import ( "time" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index e8c38d68a..ec5316967 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -5,16 +5,17 @@ import ( "fmt" "math/big" + "github.com/centrifuge/go-centrifuge/crypto" + "bytes" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -560,5 +561,5 @@ func (ids *EthereumIdentityService) ValidateSignature(signature *coredocumentpb. return err } - return signatures.VerifySignature(signature.PublicKey, message, signature.Signature) + return crypto.VerifySignature(signature.PublicKey, message, signature.Signature) } diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethereum_identity_integration_test.go index 02ba7a458..5fb0106f4 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethereum_identity_integration_test.go @@ -9,8 +9,8 @@ import ( "time" "github.com/centrifuge/go-centrifuge/bootstrap" + cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" diff --git a/identity/identity.go b/identity/identity.go index 569747f1e..8e9671c4d 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -5,15 +5,16 @@ import ( "fmt" "math/big" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/errors" "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/keytools/ed25519" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" - "github.com/centrifuge/go-centrifuge/signatures" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -235,5 +236,5 @@ func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated func Sign(idConfig *IDConfig, purpose int, payload []byte) *coredocumentpb.Signature { - return signatures.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) + return crypto.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) } diff --git a/identity/identity_test.go b/identity/identity_test.go index a0b0f0a7d..d5eaa14a9 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -7,10 +7,11 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/signatures" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -281,6 +282,6 @@ func TestSign(t *testing.T) { msg := utils.RandomSlice(100) sig := Sign(&IDConfig{c, map[int]IDKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) - err := signatures.VerifySignature(key1Pub, msg, sig.Signature) + err := crypto.VerifySignature(key1Pub, msg, sig.Signature) assert.True(t, err == nil) } diff --git a/keytools/sign.go b/keytools/sign.go deleted file mode 100644 index 1b8977d95..000000000 --- a/keytools/sign.go +++ /dev/null @@ -1,29 +0,0 @@ -package keytools - -import ( - "strings" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" -) - -// SignMessage signs the message using the private key as the curveType provided. -// if ethereumSign is true, then the signature format is specific to ethereum. -func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool) ([]byte, error) { - curveType = strings.ToLower(curveType) - switch curveType { - case CurveSecp256K1: - msg := make([]byte, MaxMsgLen) - copy(msg, message) - if ethereumSign { - return secp256k1.SignEthereum(msg, privateKey) - } - - return secp256k1.Sign(msg, privateKey) - case CurveEd25519: - return nil, errors.New("curve ed25519 not supported yet") - default: - return nil, errors.New("curve %s not supported", curveType) - } - -} diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 34ca134f1..4b4c2cd0f 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,17 +8,18 @@ import ( "testing" "time" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" + cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" @@ -50,7 +51,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader, err := header.NewContextHeader(context.Background(), cfg) + contextHeader, err := context2.NewContextHeader(context.Background(), cfg) assert.Nil(t, err) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) diff --git a/notification/notification_test.go b/notification/notification_test.go index 7b8d55012..4db118365 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -11,8 +11,8 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/jsonpb" diff --git a/p2p/client.go b/p2p/client.go index 9f57a5aa3..92b7db02f 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,13 +4,14 @@ import ( "context" "fmt" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/version" "github.com/libp2p/go-libp2p-peer" @@ -22,7 +23,7 @@ import ( // Client defines methods that can be implemented by any type handling p2p communications. type Client interface { OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // OpenClient returns P2PServiceClient to contact the remote peer @@ -140,7 +141,7 @@ func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService ident } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *p2pServer) GetSignaturesForDocument(ctx *header.ContextHeader, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (s *p2pServer) GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) diff --git a/p2p/grpc/handler.go b/p2p/grpc/handler.go index 2068c22e9..fe01e90f2 100644 --- a/p2p/grpc/handler.go +++ b/p2p/grpc/handler.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" @@ -12,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/version" logging "github.com/ipfs/go-log" ) @@ -58,7 +59,7 @@ func New(config config.Configuration, registry *documents.ServiceRegistry) *Hand // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - ctxHeader, err := header.NewContextHeader(ctx, srv.config) + ctxHeader, err := context2.NewContextHeader(ctx, srv.config) if err != nil { log.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/p2p/grpc/handler_integration_test.go b/p2p/grpc/handler_integration_test.go index d247d33a0..6a59f4885 100644 --- a/p2p/grpc/handler_integration_test.go +++ b/p2p/grpc/handler_integration_test.go @@ -16,12 +16,12 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - cc "github.com/centrifuge/go-centrifuge/context/testingbootstrap" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/keytools/secp256k1" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" diff --git a/p2p/grpc/handler_test.go b/p2p/grpc/handler_test.go index 18625cee0..8597ab8fb 100644 --- a/p2p/grpc/handler_test.go +++ b/p2p/grpc/handler_test.go @@ -12,10 +12,10 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" diff --git a/p2p/server.go b/p2p/server.go index 52593314e..0f2feb342 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -11,7 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - cented25519 "github.com/centrifuge/go-centrifuge/keytools/ed25519" + cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-ipfs-addr" diff --git a/p2p/server_test.go b/p2p/server_test.go index acfc95d7d..2a211d785 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -17,7 +17,7 @@ import ( "github.com/paralin/go-libp2p-grpc" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/context/testlogging" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/storage" diff --git a/signatures/signatures.go b/signatures/signatures.go deleted file mode 100644 index ed927c48b..000000000 --- a/signatures/signatures.go +++ /dev/null @@ -1,31 +0,0 @@ -package signatures - -import ( - "errors" - "time" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/utils" - "golang.org/x/crypto/ed25519" -) - -// VerifySignature verifies the signature using ed25519 -func VerifySignature(pubKey, message, signature []byte) error { - valid := ed25519.Verify(pubKey, message, signature) - if !valid { - return errors.New("invalid signature") - } - - return nil -} - -// Sign the document with the private key and return the signature along with the public key for the verification -// assumes that signing root for the document is generated -func Sign(centIDBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { - return &coredocumentpb.Signature{ - EntityId: centIDBytes, - PublicKey: pubKey, - Signature: ed25519.Sign(privateKey, payload), - Timestamp: utils.ToTimestamp(time.Now().UTC()), - } -} diff --git a/signatures/signatures_test.go b/signatures/signatures_test.go deleted file mode 100644 index 5054e034c..000000000 --- a/signatures/signatures_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// +build unit - -package signatures - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -var ( - key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - id1 = []byte{1, 1, 1, 1, 1, 1} - signature = []byte{0x4e, 0x3d, 0x90, 0x5f, 0x25, 0xc7, 0x90, 0x63, 0x7e, 0x6c, 0xd0, 0xe6, 0xc7, 0xbd, 0xe6, 0x81, 0x3b, 0xd0, 0x5b, 0x94, 0x76, 0x86, 0x4e, 0xcb, 0xb9, 0x36, 0x48, 0x44, 0x4b, 0x98, 0xd2, 0x4b, 0x6a, 0x65, 0x22, 0x92, 0x1c, 0x8a, 0xdb, 0xfe, 0xb7, 0x6f, 0xfe, 0x34, 0x52, 0xa3, 0x49, 0xe4, 0xda, 0xdc, 0x5d, 0x1b, 0x0, 0x79, 0x54, 0x60, 0x29, 0x22, 0x94, 0xb, 0x3c, 0x90, 0x3c, 0x3} -) - -func TestSign(t *testing.T) { - sig := Sign(id1, key1, key1Pub, key1Pub) - assert.NotNil(t, sig) - assert.Equal(t, sig.PublicKey, []byte(key1Pub)) - assert.Equal(t, sig.EntityId, id1) - assert.NotEmpty(t, sig.Signature) - assert.Len(t, sig.Signature, 64) - assert.Equal(t, sig.Signature, signature) - assert.NotNil(t, sig.Timestamp, "must be non nil") -} - -func TestValidateSignature_invalid_sig(t *testing.T) { - pubKey := key1Pub - message := key1Pub - signature := utils.RandomSlice(32) - err := VerifySignature(pubKey, message, signature) - assert.NotNil(t, err, "must be not nil") - assert.Contains(t, err.Error(), "invalid signature") -} - -func TestValidateSignature_success(t *testing.T) { - pubKey := key1Pub - message := key1Pub - err := VerifySignature(pubKey, message, signature) - assert.Nil(t, err, "must be nil") -} diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index 0fbb25007..0cbb3b03d 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -5,8 +5,8 @@ package testingcoredocument import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/header" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -38,13 +38,13 @@ type MockCoreDocumentProcessor struct { mock.Mock } -func (m *MockCoreDocumentProcessor) Send(ctx *header.ContextHeader, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (m *MockCoreDocumentProcessor) Send(ctx *context.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { args := m.Called(coreDocument, ctx, recipient) return args.Error(0) } func (m *MockCoreDocumentProcessor) Anchor( - ctx *header.ContextHeader, + ctx *context.Header, coreDocument *coredocumentpb.CoreDocument, saveState func(*coredocumentpb.CoreDocument) error) (err error) { args := m.Called(ctx, coreDocument, saveState) @@ -57,12 +57,12 @@ func (m *MockCoreDocumentProcessor) Anchor( return args.Error(0) } -func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx *header.ContextHeader, model documents.Model) error { +func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx *context.Header, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) RequestSignatures(ctx *header.ContextHeader, model documents.Model) error { +func (m *MockCoreDocumentProcessor) RequestSignatures(ctx *context.Header, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } @@ -72,12 +72,12 @@ func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) e return args.Error(0) } -func (m *MockCoreDocumentProcessor) AnchorDocument(ctx *header.ContextHeader, model documents.Model) error { +func (m *MockCoreDocumentProcessor) AnchorDocument(ctx *context.Header, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) SendDocument(ctx *header.ContextHeader, model documents.Model) error { +func (m *MockCoreDocumentProcessor) SendDocument(ctx *context.Header, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 6e31a3c9d..a74cf7286 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -5,8 +5,8 @@ package testingdocuments import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/header" "github.com/stretchr/testify/mock" ) @@ -39,7 +39,7 @@ func (m *MockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (d return args.Get(0).(documents.Model), args.Error(1) } -func (m *MockService) RequestDocumentSignature(ctx *header.ContextHeader, model documents.Model) (*coredocumentpb.Signature, error) { +func (m *MockService) RequestDocumentSignature(ctx *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { args := m.Called() return args.Get(0).(*coredocumentpb.Signature), args.Error(1) } diff --git a/testworld/park.go b/testworld/park.go index 93e4d2557..86d46b59f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -8,6 +8,8 @@ import ( "os" "os/signal" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" + "testing" "time" @@ -17,7 +19,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/config" - ctx "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/node" @@ -235,7 +236,7 @@ func (h *host) init() error { } } - m := ctx.MainBootstrapper{} + m := bootstrappers.MainBootstrapper{} m.PopulateBaseBootstrappers() h.bootstrappedCtx = map[string]interface{}{ config.BootstrappedConfigFile: h.dir + "/config.yaml", diff --git a/transactions/repository_test.go b/transactions/repository_test.go index 14fb35ef6..62ed71a08 100644 --- a/transactions/repository_test.go +++ b/transactions/repository_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/context/testlogging" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" From a4f33156c02753fe7998d0bbde3016e040ddaa93 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 27 Dec 2018 19:10:04 +0100 Subject: [PATCH 104/220] Convert ContextHeader to Context and make a util (#601) * Fix error * Convert ContextHeader to Context and make a util * fix problem * Fix lint issue --- context/context.go | 35 ----------- contextutil/context.go | 35 +++++++++++ coredocument/coredocument_test.go | 12 ++-- coredocument/processor.go | 71 ++++++++++++++-------- coredocument/processor_test.go | 20 +++--- coredocument/validator_test.go | 16 ++--- crypto/sign.go | 3 +- documents/anchor.go | 13 ++-- documents/genericdoc/service.go | 13 ++-- documents/genericdoc/service_test.go | 4 +- documents/invoice/handler.go | 10 +-- documents/invoice/handler_test.go | 30 ++++----- documents/invoice/model.go | 6 +- documents/invoice/model_test.go | 25 ++++---- documents/invoice/service.go | 44 +++++++++----- documents/invoice/service_test.go | 57 ++++++++--------- documents/invoice/validator_test.go | 9 +-- documents/purchaseorder/handler.go | 10 +-- documents/purchaseorder/handler_test.go | 38 ++++++------ documents/purchaseorder/model.go | 6 +- documents/purchaseorder/model_test.go | 22 ++++--- documents/purchaseorder/service.go | 44 +++++++++----- documents/purchaseorder/service_test.go | 61 ++++++++++--------- documents/purchaseorder/validator_test.go | 9 +-- documents/service.go | 5 +- documents/test/anchor_test.go | 4 +- nft/payment_obligation_integration_test.go | 25 ++++---- p2p/client.go | 15 +++-- p2p/grpc/handler.go | 4 +- testingutils/coredocument/coredocument.go | 15 ++--- testingutils/documents/documents.go | 5 +- 31 files changed, 370 insertions(+), 296 deletions(-) delete mode 100644 context/context.go create mode 100644 contextutil/context.go diff --git a/context/context.go b/context/context.go deleted file mode 100644 index d8db00f3a..000000000 --- a/context/context.go +++ /dev/null @@ -1,35 +0,0 @@ -package context - -import ( - "context" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" -) - -// Header holds custom request objects to pass down the pipeline. -type Header struct { - context context.Context - self *identity.IDConfig -} - -// NewContextHeader creates new instance of the request headers. -func NewContextHeader(context context.Context, config config.Configuration) (*Header, error) { - idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) - if err != nil { - return nil, errors.New("failed to get id config: %v", err) - } - - return &Header{self: idConfig, context: context}, nil -} - -// Self returns Self CentID. -func (h *Header) Self() *identity.IDConfig { - return h.self -} - -// Context returns context.Context of the request. -func (h *Header) Context() context.Context { - return h.context -} diff --git a/contextutil/context.go b/contextutil/context.go new file mode 100644 index 000000000..60ceee1cb --- /dev/null +++ b/contextutil/context.go @@ -0,0 +1,35 @@ +package contextutil + +import ( + "context" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" +) + +// ErrIDConfigNotFound must be used when configuration can't be found +const ErrIDConfigNotFound = errors.Error("id configuration wasn't found") + +// ErrSelfNotFound must be used when self value is not found in the context +const ErrSelfNotFound = errors.Error("self value not found in the context") + +type selfKey string + +// NewCentrifugeContext creates new instance of the request headers. +func NewCentrifugeContext(ctx context.Context, config config.Configuration) (context.Context, error) { + idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) + if err != nil { + return nil, errors.NewTypedError(ErrIDConfigNotFound, errors.New("%v", err)) + } + return context.WithValue(ctx, selfKey("self"), idConfig), nil +} + +// Self returns Self CentID. +func Self(ctx context.Context) (*identity.IDConfig, error) { + self, ok := ctx.Value(selfKey("self")).(*identity.IDConfig) + if ok { + return self, nil + } + return nil, ErrSelfNotFound +} diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 1468dee5f..2c2d78d39 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -9,7 +9,7 @@ import ( "os" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -245,9 +245,10 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - collaborators, err := GetExternalCollaborators(ctxh.Self().ID, cd) + self, _ := contextutil.Self(ctxh) + collaborators, err := GetExternalCollaborators(self.ID, cd) assert.Nil(t, err) assert.NotNil(t, collaborators) assert.Equal(t, [][]byte{c1, c2}, collaborators) @@ -260,8 +261,9 @@ func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) cd.Collaborators[1] = utils.RandomSlice(5) - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - _, err = GetExternalCollaborators(ctxh.Self().ID, cd) + self, _ := contextutil.Self(ctxh) + _, err = GetExternalCollaborators(self.ID, cd) assert.NotNil(t, err) } diff --git a/coredocument/processor.go b/coredocument/processor.go index 9bfbf66ba..a6ecddec2 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -4,12 +4,11 @@ import ( "context" "time" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -31,19 +30,19 @@ type Config interface { // Processor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type Processor interface { - Send(ctx *context2.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) - PrepareForSignatureRequests(ctx *context2.Header, model documents.Model) error - RequestSignatures(ctx *context2.Header, model documents.Model) error + Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) + PrepareForSignatureRequests(ctx context.Context, model documents.Model) error + RequestSignatures(ctx context.Context, model documents.Model) error PrepareForAnchoring(model documents.Model) error - AnchorDocument(ctx *context2.Header, model documents.Model) error - SendDocument(ctx *context2.Header, model documents.Model) error + AnchorDocument(ctx context.Context, model documents.Model) error + SendDocument(ctx context.Context, model documents.Model) error } // client defines the methods for p2pclient // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // defaultProcessor implements Processor interface @@ -65,40 +64,44 @@ func DefaultProcessor(idService identity.Service, p2pClient client, repository a } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx *context2.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { if coreDocument == nil { - return centerrors.NilError(coreDocument) + return errors.New("passed coreDoc is nil") } log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) id, err := dp.identityService.LookupIdentityForID(recipient) if err != nil { - return centerrors.Wrap(err, "error fetching receiver identity") + return errors.New("error fetching receiver identity: %v", err) } client, err := dp.p2pClient.OpenClient(id) if err != nil { return errors.New("failed to open client: %v", err) } + self, err := contextutil.Self(ctx) + if err != nil { + return err + } + log.Infof("Done opening connection against recipient [%x]\n", recipient) - idConfig := ctx.Self() - centIDBytes := idConfig.ID[:] + centIDBytes := self.ID[:] p2pheader := &p2ppb.CentrifugeHeader{ SenderCentrifugeId: centIDBytes, CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: dp.config.GetNetworkID(), } - c, _ := context.WithTimeout(ctx.Context(), dp.config.GetP2PConnectionTimeout()) + c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) resp, err := client.SendAnchoredDocument(c, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) if err != nil || !resp.Accepted { - return centerrors.Wrap(err, "failed to send document to the node") + return errors.New("failed to send document to the node: %v", err) } return nil } // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature -func (dp defaultProcessor) PrepareForSignatureRequests(ctx *context2.Header, model documents.Model) error { +func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -110,7 +113,12 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx *context2.Header, mod return errors.New("failed to calculate signing root: %v", err) } - sig := identity.Sign(ctx.Self(), identity.KeyPurposeSigning, cd.SigningRoot) + self, err := contextutil.Self(ctx) + if err != nil { + return err + } + + sig := identity.Sign(self, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) @@ -123,18 +131,23 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx *context2.Header, mod // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, -func (dp defaultProcessor) RequestSignatures(ctx *context2.Header, model documents.Model) error { +func (dp defaultProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } - idKeys, ok := ctx.Self().Keys[identity.KeyPurposeSigning] + self, err := contextutil.Self(ctx) + if err != nil { + return err + } + + idKeys, ok := self.Keys[identity.KeyPurposeSigning] if !ok { return errors.New("missing keys for signing") } - psv := PreSignatureRequestValidator(ctx.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) + psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) err = psv.Validate(nil, model) if err != nil { return errors.New("failed to validate model for signature request: %v", err) @@ -180,7 +193,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { } // AnchorDocument validates the model, and anchors the document -func (dp defaultProcessor) AnchorDocument(ctx *context2.Header, model documents.Model) error { +func (dp defaultProcessor) AnchorDocument(ctx context.Context, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -212,8 +225,13 @@ func (dp defaultProcessor) AnchorDocument(ctx *context2.Header, model documents. return errors.New("failed to get anchor ID: %v", err) } + self, err := contextutil.Self(ctx) + if err != nil { + return err + } + // generate message authentication code for the anchor call - mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), ctx.Self().Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) + mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), self.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { return errors.New("failed to generate ethereum MAC: %v", err) } @@ -230,7 +248,7 @@ func (dp defaultProcessor) AnchorDocument(ctx *context2.Header, model documents. } // SendDocument does post anchor validations and sends the document to collaborators -func (dp defaultProcessor) SendDocument(ctx *context2.Header, model documents.Model) error { +func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -242,7 +260,12 @@ func (dp defaultProcessor) SendDocument(ctx *context2.Header, model documents.Mo return errors.New("post anchor validations failed: %v", err) } - extCollaborators, err := GetExternalCollaborators(ctx.Self().ID, cd) + self, err := contextutil.Self(ctx) + if err != nil { + return err + } + + extCollaborators, err := GetExternalCollaborators(self.ID, cd) if err != nil { return errors.New("get external collaborators failed: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 9bf95bc34..5a05742b6 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -6,7 +6,7 @@ import ( "context" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" @@ -49,7 +49,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) @@ -71,10 +71,10 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - ctxh, err = context2.NewContextHeader(context.Background(), cfg) + ctxh, err = contextutil.NewCentrifugeContext(context.Background(), cfg) assert.NotNil(t, err) cfg.Set("keys.signing.publicKey", pub) - ctxh, err = context2.NewContextHeader(context.Background(), cfg) + ctxh, err = contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // failed unpack @@ -97,8 +97,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.NotNil(t, cd.Signatures) assert.Len(t, cd.Signatures, 1) sig := cd.Signatures[0] - id := ctxh.Self() - assert.True(t, ed25519.Verify(id.Keys[identity.KeyPurposeSigning].PublicKey, cd.SigningRoot, sig.Signature)) + self, _ := contextutil.Self(ctxh) + assert.True(t, ed25519.Verify(self.Keys[identity.KeyPurposeSigning].PublicKey, cd.SigningRoot, sig.Signature)) } type p2pClient struct { @@ -106,7 +106,7 @@ type p2pClient struct { client } -func (p p2pClient) GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { args := p.Called(ctx, doc) return args.Error(0) } @@ -115,7 +115,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) // pack failed model := mockModel{} @@ -263,7 +263,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) // pack failed @@ -359,7 +359,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) // pack failed model := mockModel{} diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index c2177fa9e..02e5ac5ce 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -5,7 +5,7 @@ package coredocument import ( "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "context" @@ -207,10 +207,11 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] - rfsv := readyForSignaturesValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) + self, _ := contextutil.Self(ctxh) + idKeys := self.Keys[identity.KeyPurposeSigning] + rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) // fail getCoreDoc model := mockModel{} @@ -538,10 +539,11 @@ func TestPostAnchoredValidator(t *testing.T) { } func TestPreSignatureRequestValidator(t *testing.T) { - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - idKeys := ctxh.Self().Keys[identity.KeyPurposeSigning] - psv := PreSignatureRequestValidator(ctxh.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey) + self, _ := contextutil.Self(ctxh) + idKeys := self.Keys[identity.KeyPurposeSigning] + psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) assert.Len(t, psv, 3) } diff --git a/crypto/sign.go b/crypto/sign.go index 99d4d1ef9..401e3ee0f 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -1,7 +1,6 @@ package crypto import ( - errors2 "errors" "strings" "time" @@ -38,7 +37,7 @@ func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool func VerifySignature(pubKey, message, signature []byte) error { valid := ed25519.Verify(pubKey, message, signature) if !valid { - return errors2.New("invalid signature") + return errors.New("invalid signature") } return nil diff --git a/documents/anchor.go b/documents/anchor.go index 8d9d79c13..7eae900cc 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -1,7 +1,8 @@ package documents import ( - "github.com/centrifuge/go-centrifuge/context" + "context" + "github.com/centrifuge/go-centrifuge/errors" ) @@ -9,11 +10,11 @@ import ( // this is to avoid import cycles // this will disappear once we have queueing logic in place type anchorProcessor interface { - PrepareForSignatureRequests(ctx *context.Header, model Model) error - RequestSignatures(ctx *context.Header, model Model) error + PrepareForSignatureRequests(ctx context.Context, model Model) error + RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error - AnchorDocument(ctx *context.Header, model Model) error - SendDocument(ctx *context.Header, model Model) error + AnchorDocument(ctx context.Context, model Model) error + SendDocument(ctx context.Context, model Model) error } // updaterFunc is a wrapper that will be called to save the state of the model between processor steps @@ -21,7 +22,7 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators -func AnchorDocument(ctx *context.Header, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { +func AnchorDocument(ctx context.Context, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { cd, err := model.PackCoreDocument() if err != nil { return nil, err diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index ccc3adf95..472ada1c5 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -2,9 +2,10 @@ package genericdoc import ( "bytes" + "context" "time" - "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/crypto" @@ -128,7 +129,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume return nil, nil } -func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -139,12 +140,16 @@ func (s service) RequestDocumentSignature(contextHeader *context.Header, model d } srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } - idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index effeff866..f761ded07 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -8,7 +8,7 @@ import ( "os" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -256,7 +256,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) i.CoreDocument.SigningRoot = nil - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index bcd345b06..b1e35b02b 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -3,7 +3,7 @@ package invoice import ( "fmt" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" @@ -41,13 +41,13 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - ctxHeader, err := context2.NewContextHeader(ctx, h.config) + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - doc, err := h.service.DeriveFromCreatePayload(req, ctxHeader) + doc, err := h.service.DeriveFromCreatePayload(ctxHeader, req) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not derive create payload") @@ -72,13 +72,13 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := context2.NewContextHeader(ctx, h.config) + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - doc, err := h.service.DeriveFromUpdatePayload(payload, ctxHeader) + doc, err := h.service.DeriveFromUpdatePayload(ctxHeader, payload) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not derive update payload") diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 211b0e937..84a793b88 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,7 +6,7 @@ import ( "context" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -22,13 +22,13 @@ type mockService struct { mock.Mock } -func (m *mockService) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context2.Header) (documents.Model, error) { - args := m.Called(payload, contextHeader) +func (m *mockService) DeriveFromCreatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceCreatePayload) (documents.Model, error) { + args := m.Called(ctx, payload) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m *mockService) Create(ctx *context2.Header, inv documents.Model) (documents.Model, error) { +func (m *mockService) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { args := m.Called(ctx, inv) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) @@ -58,14 +58,14 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx *context2.Header, doc documents.Model) (documents.Model, error) { - args := m.Called(ctx, doc) +func (m *mockService) Update(ctx context.Context, inv documents.Model) (documents.Model, error) { + args := m.Called(ctx, inv) doc1, _ := args.Get(0).(documents.Model) return doc1, args.Error(1) } -func (m *mockService) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *context2.Header) (documents.Model, error) { - args := m.Called(payload, contextHeader) +func (m *mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) { + args := m.Called(ctx, payload) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) } @@ -225,7 +225,7 @@ func TestGrpcHandler_Update_derive_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} - srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(nil, errors.New("derive error")).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(nil, errors.New("derive error")).Once() res, err := h.Update(context.Background(), payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -238,10 +238,10 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} - srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(nil, errors.New("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) @@ -255,10 +255,10 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} - srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DeriveInvoiceResponse", model).Return(nil, errors.New("derive response error")).Once() res, err := h.Update(ctx, payload) @@ -273,11 +273,11 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{} - srv.On("DeriveFromUpdatePayload", payload, mock.Anything).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DeriveInvoiceResponse", model).Return(resp, nil).Once() res, err := h.Update(ctx, payload) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 538d4b649..0aaf19a6f 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -5,8 +5,6 @@ import ( "encoding/json" "reflect" - "github.com/centrifuge/go-centrifuge/context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" @@ -149,13 +147,13 @@ func (i *Invoice) createP2PProtobuf() *invoicepb.InvoiceData { } // InitInvoiceInput initialize the model based on the received parameters from the rest api call -func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context.Header) error { +func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload, self string) error { err := i.initInvoiceFromData(payload.Data) if err != nil { return err } - collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) + collaborators := append([]string{self}, payload.Collaborators...) i.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 13c87bc30..ccf77df80 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" @@ -184,8 +184,9 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) + id, _ := contextutil.Self(contextHeader) // fail recipient data := &clientinvoicepb.InvoiceData{ Sender: "some number", @@ -194,7 +195,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { ExtraData: "some data", } inv := new(Invoice) - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, inv.Recipient) @@ -204,7 +205,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { data.ExtraData = "0x010203020301" data.Recipient = "0x010203040506" - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -212,7 +213,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Nil(t, inv.Payee) data.Sender = "0x010203060506" - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -220,7 +221,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Nil(t, inv.Payee) data.Payee = "0x010203030405" - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -229,25 +230,25 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { data.ExtraData = "0x010203020301" collabs := []string{"0x010102040506", "some id"} - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") collabs = []string{"0x010102040506", "0x010203020302"} - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, contextHeader) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Nil(t, err, "must be nil") assert.Equal(t, inv.Sender[:], []byte{1, 2, 3, 6, 5, 6}) assert.Equal(t, inv.Payee[:], []byte{1, 2, 3, 3, 4, 5}) assert.Equal(t, inv.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, inv.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - id := contextHeader.Self().ID - assert.Equal(t, inv.CoreDocument.Collaborators, [][]byte{id[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + assert.Equal(t, inv.CoreDocument.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - ctxHeader, err := context2.NewContextHeader(context.Background(), cfg) + ctxHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) + id, _ := contextutil.Self(ctxHeader) m := new(Invoice) - err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), ctxHeader) + err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, m.InvoiceSalts, "salts must be nil") diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 672a6a397..1963ac34c 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -2,9 +2,10 @@ package invoice import ( "bytes" + "context" "time" - "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/crypto" @@ -32,16 +33,16 @@ type Service interface { documents.Service // DeriverFromPayload derives Invoice from clientPayload - DeriveFromCreatePayload(*clientinvoicepb.InvoiceCreatePayload, *context.Header) (documents.Model, error) + DeriveFromCreatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceCreatePayload) (documents.Model, error) // DeriveFromUpdatePayload derives invoice model from update payload - DeriveFromUpdatePayload(*clientinvoicepb.InvoiceUpdatePayload, *context.Header) (documents.Model, error) + DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) // Create validates and persists invoice Model and returns a Updated model - Create(ctx *context.Header, inv documents.Model) (documents.Model, error) + Create(ctx context.Context, inv documents.Model) (documents.Model, error) // Update validates and updates the invoice model and return the updated model - Update(ctx *context.Header, inv documents.Model) (documents.Model, error) + Update(ctx context.Context, inv documents.Model) (documents.Model, error) // DeriveInvoiceData returns the invoice data as client data DeriveInvoiceData(inv documents.Model) (*clientinvoicepb.InvoiceData, error) @@ -119,13 +120,18 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call -func (s service) DeriveFromCreatePayload(payload *clientinvoicepb.InvoiceCreatePayload, contextHeader *context.Header) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceCreatePayload) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } + id, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + invoiceModel := new(Invoice) - err := invoiceModel.InitInvoiceInput(payload, contextHeader) + err = invoiceModel.InitInvoiceInput(payload, id.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -168,7 +174,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx *context.Header, inv documents.Model) (documents.Model, error) { +func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { inv, err := s.calculateDataRoot(nil, inv, CreateValidator()) if err != nil { return nil, err @@ -193,7 +199,7 @@ func (s service) updater(id []byte, model documents.Model) error { } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx *context.Header, inv documents.Model) (documents.Model, error) { +func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, error) { cd, err := inv.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) @@ -312,7 +318,7 @@ func (s service) DeriveInvoiceData(doc documents.Model) (*clientinvoicepb.Invoic } // DeriveFromUpdatePayload returns a new version of the old invoice identified by identifier in payload -func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdatePayload, contextHeader *context.Header) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -341,7 +347,12 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + + collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) inv.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) @@ -351,7 +362,7 @@ func (s service) DeriveFromUpdatePayload(payload *clientinvoicepb.InvoiceUpdateP } // RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature -func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -363,11 +374,16 @@ func (s service) RequestDocumentSignature(contextHeader *context.Header, model d srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + + idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) err = model.UnpackCoreDocument(doc) if err != nil { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 5a2cf57f4..3b24069c2 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -7,7 +7,7 @@ import ( "math/big" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" @@ -106,12 +106,12 @@ func TestService_DeriveFromPayload(t *testing.T) { assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") // fail due to nil payload data - _, err = invSrv.DeriveFromCreatePayload(&clientinvoicepb.InvoiceCreatePayload{}, nil) + _, err = invSrv.DeriveFromCreatePayload(nil, &clientinvoicepb.InvoiceCreatePayload{}) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - model, err = invSrv.DeriveFromCreatePayload(payload, contextHeader) + model, err = invSrv.DeriveFromCreatePayload(contextHeader, payload) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") receivedCoreDocument, err := model.PackCoreDocument() @@ -215,7 +215,7 @@ func TestService_Exists(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) _, srv := getServiceWithMockedLayers() invSrv := srv.(service) @@ -227,7 +227,7 @@ func TestService_Create(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // anchor fails - po, err := invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) + po, err := invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() @@ -239,7 +239,7 @@ func TestService_Create(t *testing.T) { assert.Contains(t, err.Error(), "anchoring failed") // success - po, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) + po, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() @@ -267,9 +267,9 @@ func TestService_DeriveInvoiceData(t *testing.T) { // success payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - inv, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) + inv, err := invSrv.DeriveFromCreatePayload(contextHeader, payload) assert.Nil(t, err, "must be non nil") data, err := invSrv.DeriveInvoiceData(inv) assert.Nil(t, err, "Derive must succeed") @@ -280,9 +280,9 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // success invSrv := service{repo: testRepo()} payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) - inv1, err := invSrv.DeriveFromCreatePayload(payload, contextHeader) + inv1, err := invSrv.DeriveFromCreatePayload(contextHeader, payload) assert.Nil(t, err, "must be non nil") inv, ok := inv1.(*Invoice) assert.True(t, ok) @@ -387,7 +387,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) i.CoreDocument.SigningRoot = nil - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) signature, err := invSrv.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) @@ -496,16 +496,16 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // nil payload data - doc, err = invSrv.DeriveFromUpdatePayload(&clientinvoicepb.InvoiceUpdatePayload{}, nil) + doc, err = invSrv.DeriveFromUpdatePayload(nil, &clientinvoicepb.InvoiceUpdatePayload{}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // messed up identifier - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} - doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentIdentifier, err)) assert.Contains(t, err.Error(), "failed to decode identifier") @@ -514,14 +514,15 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // missing last version id := utils.RandomSlice(32) payload.Identifier = hexutil.Encode(id) - doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) assert.Nil(t, doc) // failed to load from data + idC, _ := contextutil.Self(contextHeader) old := new(Invoice) - err = old.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) + err = old.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), idC.ID.String()) assert.Nil(t, err) old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id @@ -536,7 +537,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { ExtraData: "some data", Currency: "EUR", } - doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, doc) @@ -544,7 +545,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // failed core document new version payload.Data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) payload.Collaborators = []string{"some wrong ID"} - doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentPrepareCoreDocument, err)) assert.Nil(t, doc) @@ -552,7 +553,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // success wantCollab := utils.RandomSlice(6) payload.Collaborators = []string{hexutil.Encode(wantCollab)} - doc, err = invSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) cd, err := doc.PackCoreDocument() @@ -572,7 +573,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_Update(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // pack failed @@ -594,7 +595,7 @@ func TestService_Update(t *testing.T) { payload := testingdocuments.CreateInvoicePayload() payload.Collaborators = []string{"0x010203040506"} - inv, err := invSrv.DeriveFromCreatePayload(payload, ctxh) + inv, err := invSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) cd, err = inv.PackCoreDocument() assert.Nil(t, err) @@ -616,11 +617,11 @@ func TestService_Update(t *testing.T) { data.GrossAmount = 100 data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) collab := hexutil.Encode(utils.RandomSlice(6)) - newInv, err := invSrv.DeriveFromUpdatePayload(&clientinvoicepb.InvoiceUpdatePayload{ + newInv, err := invSrv.DeriveFromUpdatePayload(ctxh, &clientinvoicepb.InvoiceUpdatePayload{ Identifier: hexutil.Encode(cd.DocumentIdentifier), Collaborators: []string{collab}, Data: data, - }, ctxh) + }) assert.Nil(t, err) newData, err := invSrv.DeriveInvoiceData(newInv) assert.Nil(t, err) @@ -652,7 +653,7 @@ func TestService_Update(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // type mismatch @@ -662,7 +663,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // failed validator - inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) + inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { @@ -674,7 +675,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), "validations fail") // create failed - inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) + inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) err = invSrv.repo.Create(centIDBytes, inv.(*Invoice).CoreDocument.CurrentVersion, inv) @@ -685,7 +686,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), "db repository could not create the given model, key already exists") // success - inv, err = invSrv.DeriveFromCreatePayload(testingdocuments.CreateInvoicePayload(), ctxh) + inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 54b029b38..88e566bd9 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -5,7 +5,7 @@ package invoice import ( "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "context" @@ -82,10 +82,11 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) + id, _ := contextutil.Self(contextHeader) inv := new(Invoice) - err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) + err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err) inv.CoreDocument = cd err = drv.Validate(nil, inv) @@ -94,7 +95,7 @@ func TestDataRootValidation_Validate(t *testing.T) { // success inv = new(Invoice) - err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), contextHeader) + err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err) err = inv.CalculateDataRoot() assert.Nil(t, err) diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 5c37af85b..b1f265cde 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -3,7 +3,7 @@ package purchaseorder import ( "fmt" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" @@ -42,13 +42,13 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - ctxh, err := context2.NewContextHeader(ctx, h.config) + ctxh, err := contextutil.NewCentrifugeContext(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, err.Error()) } - doc, err := h.service.DeriveFromCreatePayload(req, ctxh) + doc, err := h.service.DeriveFromCreatePayload(ctxh, req) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not derive create payload") @@ -73,13 +73,13 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := context2.NewContextHeader(ctx, h.config) + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - doc, err := h.service.DeriveFromUpdatePayload(payload, ctxHeader) + doc, err := h.service.DeriveFromUpdatePayload(ctxHeader, payload) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not derive update payload") diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index a9ce0ae55..4339998bf 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,7 +6,7 @@ import ( "context" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -23,20 +23,20 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx *context2.Header, doc documents.Model) (documents.Model, error) { - args := m.Called(ctx, doc) +func (m mockService) Create(ctx context.Context, po documents.Model) (documents.Model, error) { + args := m.Called(ctx, po) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) Update(ctx *context2.Header, doc documents.Model) (documents.Model, error) { - args := m.Called(ctx, doc) +func (m mockService) Update(ctx context.Context, po documents.Model) (documents.Model, error) { + args := m.Called(ctx, po) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } -func (m mockService) DeriveFromCreatePayload(req *clientpopb.PurchaseOrderCreatePayload, ctxh *context2.Header) (documents.Model, error) { - args := m.Called(req, ctxh) +func (m mockService) DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) { + args := m.Called(ctx, payload) model, _ := args.Get(0).(documents.Model) return model, args.Error(1) } @@ -65,8 +65,8 @@ func (m mockService) DerivePurchaseOrderResponse(po documents.Model) (*clientpop return data, args.Error(1) } -func (m mockService) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxh *context2.Header) (documents.Model, error) { - args := m.Called(payload, ctxh) +func (m mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderUpdatePayload) (documents.Model, error) { + args := m.Called(ctx, payload) doc, _ := args.Get(0).(documents.Model) return doc, args.Error(1) } @@ -76,12 +76,12 @@ func TestGRPCHandler_Create(t *testing.T) { req := testingdocuments.CreatePOPayload() ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromCreatePayload", req, ctxh).Return(nil, errors.New("derive failed")).Once() + srv.On("DeriveFromCreatePayload", ctxh, req).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Create(ctx, req) srv.AssertExpectations(t) @@ -90,7 +90,7 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() srv.On("Create", ctxh, model).Return(nil, errors.New("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -100,7 +100,7 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "create failed") // derive response fails - srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() srv.On("Create", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv @@ -112,7 +112,7 @@ func TestGRPCHandler_Create(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{} - srv.On("DeriveFromCreatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() srv.On("Create", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv @@ -132,12 +132,12 @@ func TestGrpcHandler_Update(t *testing.T) { } ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromUpdatePayload", req, ctxh).Return(nil, errors.New("derive failed")).Once() + srv.On("DeriveFromUpdatePayload", ctxh, req).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Update(ctx, req) srv.AssertExpectations(t) @@ -146,7 +146,7 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(nil, errors.New("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -156,7 +156,7 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "update failed") // derive response fails - srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv @@ -168,7 +168,7 @@ func TestGrpcHandler_Update(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{} - srv.On("DeriveFromUpdatePayload", req, ctxh).Return(model, nil).Once() + srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index a4ec324aa..5f272d660 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -5,8 +5,6 @@ import ( "encoding/json" "reflect" - "github.com/centrifuge/go-centrifuge/context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" @@ -148,13 +146,13 @@ func (p *PurchaseOrder) createP2PProtobuf() *purchaseorderpb.PurchaseOrderData { } // InitPurchaseOrderInput initialize the model based on the received parameters from the rest api call -func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, contextHeader *context.Header) error { +func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.PurchaseOrderCreatePayload, self string) error { err := p.initPurchaseOrderFromData(payload.Data) if err != nil { return err } - collaborators := append([]string{contextHeader.Self().ID.String()}, payload.Collaborators...) + collaborators := append([]string{self}, payload.Collaborators...) p.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 981cf082f..b4aa8cedf 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" @@ -179,7 +179,8 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) + id, _ := contextutil.Self(contextHeader) assert.Nil(t, err) // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ @@ -187,7 +188,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { ExtraData: "some data", } poModel := new(PurchaseOrder) - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, contextHeader) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, poModel.Recipient) @@ -196,31 +197,32 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { data.ExtraData = "0x010203020301" data.Recipient = "0x010203040506" - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, contextHeader) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, poModel.ExtraData) assert.NotNil(t, poModel.Recipient) data.ExtraData = "0x010203020301" collabs := []string{"0x010102040506", "some id"} - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, contextHeader) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") collabs = []string{"0x010102040506", "0x010203020302"} - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, contextHeader) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Nil(t, err, "must be nil") assert.Equal(t, poModel.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - id := contextHeader.Self().ID - assert.Equal(t, poModel.CoreDocument.Collaborators, [][]byte{id[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + + assert.Equal(t, poModel.CoreDocument.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } func TestPOModel_calculateDataRoot(t *testing.T) { - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) + id, _ := contextutil.Self(contextHeader) poModel := new(PurchaseOrder) - err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) + err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, poModel.PurchaseOrderSalt, "salts must be nil") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 1c87d36a1..81ca55c12 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -2,9 +2,10 @@ package purchaseorder import ( "bytes" + "context" "time" - "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/crypto" @@ -32,16 +33,16 @@ type Service interface { documents.Service // DeriverFromPayload derives purchase order from clientPayload - DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, hdr *context.Header) (documents.Model, error) + DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) // DeriveFromUpdatePayload derives purchase order from update payload - DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, hdr *context.Header) (documents.Model, error) + DeriveFromUpdatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderUpdatePayload) (documents.Model, error) // Create validates and persists purchase order and returns a Updated model - Create(ctx *context.Header, po documents.Model) (documents.Model, error) + Create(ctx context.Context, po documents.Model) (documents.Model, error) // Update validates and updates the purchase order and return the updated model - Update(ctx *context.Header, po documents.Model) (documents.Model, error) + Update(ctx context.Context, po documents.Model) (documents.Model, error) // DerivePurchaseOrderData returns the purchase order data as client data DerivePurchaseOrderData(po documents.Model) (*clientpopb.PurchaseOrderData, error) @@ -112,7 +113,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx *context.Header, po documents.Model) (documents.Model, error) { +func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, error) { po, err := s.calculateDataRoot(nil, po, CreateValidator()) if err != nil { return nil, err @@ -137,7 +138,7 @@ func (s service) updater(id []byte, model documents.Model) error { } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx *context.Header, po documents.Model) (documents.Model, error) { +func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, error) { cd, err := po.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) @@ -162,13 +163,18 @@ func (s service) Update(ctx *context.Header, po documents.Model) (documents.Mode } // DeriveFromCreatePayload derives purchase order from create payload -func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreatePayload, ctxH *context.Header) (documents.Model, error) { +func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + po := new(PurchaseOrder) - err := po.InitPurchaseOrderInput(payload, ctxH) + err = po.InitPurchaseOrderInput(payload, idConf.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -177,7 +183,7 @@ func (s service) DeriveFromCreatePayload(payload *clientpopb.PurchaseOrderCreate } // DeriveFromUpdatePayload derives purchase order from update payload -func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdatePayload, ctxH *context.Header) (documents.Model, error) { +func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderUpdatePayload) (documents.Model, error) { if payload == nil || payload.Data == nil { return nil, documents.ErrDocumentNil } @@ -206,7 +212,12 @@ func (s service) DeriveFromUpdatePayload(payload *clientpopb.PurchaseOrderUpdate return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - collaborators := append([]string{ctxH.Self().ID.String()}, payload.Collaborators...) + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + + collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) po.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) @@ -350,7 +361,7 @@ func (s service) CreateProofsForVersion(documentID, version []byte, fields []str // RequestDocumentSignature validates the document and returns the signature // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service -func (s service) RequestDocumentSignature(contextHeader *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { +func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -362,11 +373,16 @@ func (s service) RequestDocumentSignature(contextHeader *context.Header, model d srvLog.Infof("coredoc received %x with signing root %x", cd.DocumentIdentifier, cd.SigningRoot) - idKeys, ok := contextHeader.Self().Keys[identity.KeyPurposeSigning] + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + + idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] if !ok { return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) } - sig := crypto.Sign(contextHeader.Self().ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) + sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) err = model.UnpackCoreDocument(cd) if err != nil { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index eaebb73e0..0c3b7e090 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -7,7 +7,7 @@ import ( "math/big" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" @@ -56,7 +56,7 @@ func TestService_Update(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{config: c, repo: testRepo()} - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // pack failed @@ -78,7 +78,7 @@ func TestService_Update(t *testing.T) { payload := testingdocuments.CreatePOPayload() payload.Collaborators = []string{"0x010203040506"} - po, err := poSrv.DeriveFromCreatePayload(payload, ctxh) + po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) cd, err = po.PackCoreDocument() assert.Nil(t, err) @@ -100,11 +100,11 @@ func TestService_Update(t *testing.T) { data.OrderAmount = 100 data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) collab := hexutil.Encode(utils.RandomSlice(6)) - newInv, err := poSrv.DeriveFromUpdatePayload(&clientpurchaseorderpb.PurchaseOrderUpdatePayload{ + newInv, err := poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{ Identifier: hexutil.Encode(cd.DocumentIdentifier), Collaborators: []string{collab}, Data: data, - }, ctxh) + }) assert.Nil(t, err) newData, err := poSrv.DerivePurchaseOrderData(newInv) assert.Nil(t, err) @@ -144,16 +144,16 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // nil payload data - doc, err = poSrv.DeriveFromUpdatePayload(&clientpurchaseorderpb.PurchaseOrderUpdatePayload{}, nil) + doc, err = poSrv.DeriveFromUpdatePayload(nil, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // messed up identifier - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} - doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to decode identifier") assert.Nil(t, doc) @@ -161,14 +161,15 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // missing last version id := utils.RandomSlice(32) payload.Identifier = hexutil.Encode(id) - doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) assert.Nil(t, doc) // failed to load from data + self, _ := contextutil.Self(contextHeader) old := new(PurchaseOrder) - err = old.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) + err = old.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), self.ID.String()) assert.Nil(t, err) old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id @@ -181,7 +182,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { Currency: "EUR", } - doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to load purchase order from data") assert.Nil(t, doc) @@ -189,7 +190,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // failed core document new version payload.Data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) payload.Collaborators = []string{"some wrong ID"} - doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentPrepareCoreDocument, err)) assert.Nil(t, doc) @@ -197,7 +198,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // success wantCollab := utils.RandomSlice(6) payload.Collaborators = []string{hexutil.Encode(wantCollab)} - doc, err = poSrv.DeriveFromUpdatePayload(payload, contextHeader) + doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) cd, err := doc.PackCoreDocument() @@ -216,17 +217,17 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_DeriveFromCreatePayload(t *testing.T) { poSrv := service{} - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // nil payload - m, err := poSrv.DeriveFromCreatePayload(nil, ctxh) + m, err := poSrv.DeriveFromCreatePayload(ctxh, nil) assert.Nil(t, m) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) // nil data payload - m, err = poSrv.DeriveFromCreatePayload(&clientpurchaseorderpb.PurchaseOrderCreatePayload{}, ctxh) + m, err = poSrv.DeriveFromCreatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderCreatePayload{}) assert.Nil(t, m) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) @@ -238,14 +239,14 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { }, } - m, err = poSrv.DeriveFromCreatePayload(payload, ctxh) + m, err = poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, m) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) // success payload.Data.ExtraData = "0x01020304050607" - m, err = poSrv.DeriveFromCreatePayload(payload, ctxh) + m, err = poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) assert.NotNil(t, m) po := m.(*PurchaseOrder) @@ -271,7 +272,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) @@ -284,7 +285,7 @@ func TestService_Create(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // anchor fails - po, err := poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) + po, err := poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) proc := &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() @@ -296,7 +297,7 @@ func TestService_Create(t *testing.T) { assert.Contains(t, err.Error(), "anchoring failed") // success - po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) + po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) proc = &testingcoredocument.MockCoreDocumentProcessor{} proc.On("PrepareForSignatureRequests", po).Return(nil).Once() @@ -498,7 +499,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model _, poSrv := getServiceWithMockedLayers() - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // unknown type @@ -510,7 +511,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - m, err = poSrv.DeriveFromCreatePayload(payload, ctxh) + m, err = poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) d, err = poSrv.DerivePurchaseOrderData(m) assert.Nil(t, err) @@ -519,7 +520,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { func TestService_DerivePurchaseOrderResponse(t *testing.T) { poSrv := service{} - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // pack fails @@ -554,7 +555,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - po, err := poSrv.DeriveFromCreatePayload(payload, ctxh) + po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) r, err = poSrv.DerivePurchaseOrderResponse(po) assert.Nil(t, err) @@ -689,7 +690,7 @@ func TestService_ReceiveAnchoredDocument(t *testing.T) { } func TestService_RequestDocumentSignature(t *testing.T) { - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) poSrv := service{} s, err := poSrv.RequestDocumentSignature(ctxh, nil) @@ -701,7 +702,7 @@ func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{config: c, repo: testRepo()} - ctxh, err := context2.NewContextHeader(context.Background(), cfg) + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // type mismatch @@ -711,7 +712,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // failed validator - po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) + po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { @@ -723,7 +724,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), "validations fail") // create failed - po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) + po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) err = poSrv.repo.Create(centIDBytes, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) @@ -734,7 +735,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists) // success - po, err = poSrv.DeriveFromCreatePayload(testingdocuments.CreatePOPayload(), ctxh) + po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 73713394c..0f044b237 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -5,7 +5,7 @@ package purchaseorder import ( "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "context" @@ -49,7 +49,7 @@ func TestFieldValidator_Validate(t *testing.T) { func TestDataRootValidation_Validate(t *testing.T) { drv := dataRootValidator() - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // nil error @@ -84,8 +84,9 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch + id, _ := contextutil.Self(contextHeader) po := new(PurchaseOrder) - err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) + err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err) po.CoreDocument = cd err = drv.Validate(nil, po) @@ -94,7 +95,7 @@ func TestDataRootValidation_Validate(t *testing.T) { // success po = new(PurchaseOrder) - err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), contextHeader) + err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err) err = po.calculateDataRoot() assert.Nil(t, err) diff --git a/documents/service.go b/documents/service.go index e3c8581af..954500f0c 100644 --- a/documents/service.go +++ b/documents/service.go @@ -1,9 +1,10 @@ package documents import ( + "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -44,7 +45,7 @@ type Service interface { CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) // RequestDocumentSignature Validates and Signs document received over the p2p layer - RequestDocumentSignature(contextHeader *context.Header, model Model) (*coredocumentpb.Signature, error) + RequestDocumentSignature(ctx context.Context, model Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index 93b4c3227..94a23fbb4 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -7,7 +7,7 @@ import ( "errors" "testing" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "os" @@ -36,7 +36,7 @@ func TestMain(m *testing.M) { func TestAnchorDocument(t *testing.T) { ctx := context.Background() - ctxh, err := context2.NewContextHeader(ctx, cfg) + ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) updater := func(id []byte, model documents.Model) error { return nil diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 4b4c2cd0f..561dd6ee5 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -51,21 +51,20 @@ func TestPaymentObligationService_mint(t *testing.T) { // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader, err := context2.NewContextHeader(context.Background(), cfg) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) - model, err := invoiceService.DeriveFromCreatePayload( - &invoicepb.InvoiceCreatePayload{ - Collaborators: []string{}, - Data: &invoicepb.InvoiceData{ - InvoiceNumber: "2132131", - GrossAmount: 123, - NetAmount: 123, - Currency: "EUR", - DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, - }, - }, contextHeader) + model, err := invoiceService.DeriveFromCreatePayload(contextHeader, &invoicepb.InvoiceCreatePayload{ + Collaborators: []string{}, + Data: &invoicepb.InvoiceData{ + InvoiceNumber: "2132131", + GrossAmount: 123, + NetAmount: 123, + Currency: "EUR", + DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, + }, + }) assert.Nil(t, err, "should not error out when creating invoice model") modelUpdated, err := invoiceService.Create(contextHeader, model) diff --git a/p2p/client.go b/p2p/client.go index 92b7db02f..5ae46c590 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -23,7 +23,7 @@ import ( // Client defines methods that can be implemented by any type handling p2p communications. type Client interface { OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) - GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error } // OpenClient returns P2PServiceClient to contact the remote peer @@ -141,11 +141,16 @@ func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService ident } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *p2pServer) GetSignaturesForDocument(ctx *context2.Header, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) - extCollaborators, err := coredocument.GetExternalCollaborators(ctx.Self().ID, doc) + self, err := contextutil.Self(ctx) + if err != nil { + return centerrors.Wrap(err, "failed to get self") + } + + extCollaborators, err := coredocument.GetExternalCollaborators(self.ID, doc) if err != nil { return centerrors.Wrap(err, "failed to get external collaborators") } @@ -170,7 +175,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx *context2.Header, identityServi // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - c, _ := context.WithTimeout(ctx.Context(), s.config.GetP2PConnectionTimeout()) + c, _ := context.WithTimeout(ctx, s.config.GetP2PConnectionTimeout()) go s.getSignatureAsync(c, identityService, *doc, client, collaboratorID, in) } diff --git a/p2p/grpc/handler.go b/p2p/grpc/handler.go index fe01e90f2..eec51c6f6 100644 --- a/p2p/grpc/handler.go +++ b/p2p/grpc/handler.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - context2 "github.com/centrifuge/go-centrifuge/context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -59,7 +59,7 @@ func New(config config.Configuration, registry *documents.ServiceRegistry) *Hand // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - ctxHeader, err := context2.NewContextHeader(ctx, srv.config) + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, srv.config) if err != nil { log.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index 0cbb3b03d..b00a166fb 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -3,9 +3,10 @@ package testingcoredocument import ( + "context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" @@ -38,13 +39,13 @@ type MockCoreDocumentProcessor struct { mock.Mock } -func (m *MockCoreDocumentProcessor) Send(ctx *context.Header, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { +func (m *MockCoreDocumentProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { args := m.Called(coreDocument, ctx, recipient) return args.Error(0) } func (m *MockCoreDocumentProcessor) Anchor( - ctx *context.Header, + ctx context.Context, coreDocument *coredocumentpb.CoreDocument, saveState func(*coredocumentpb.CoreDocument) error) (err error) { args := m.Called(ctx, coreDocument, saveState) @@ -57,12 +58,12 @@ func (m *MockCoreDocumentProcessor) Anchor( return args.Error(0) } -func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx *context.Header, model documents.Model) error { +func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx context.Context, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) RequestSignatures(ctx *context.Header, model documents.Model) error { +func (m *MockCoreDocumentProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } @@ -72,12 +73,12 @@ func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) e return args.Error(0) } -func (m *MockCoreDocumentProcessor) AnchorDocument(ctx *context.Header, model documents.Model) error { +func (m *MockCoreDocumentProcessor) AnchorDocument(ctx context.Context, model documents.Model) error { args := m.Called(model) return args.Error(0) } -func (m *MockCoreDocumentProcessor) SendDocument(ctx *context.Header, model documents.Model) error { +func (m *MockCoreDocumentProcessor) SendDocument(ctx context.Context, model documents.Model) error { args := m.Called(ctx, model) return args.Error(0) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index a74cf7286..23c7a3df9 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -3,9 +3,10 @@ package testingdocuments import ( + "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/context" "github.com/centrifuge/go-centrifuge/documents" "github.com/stretchr/testify/mock" ) @@ -39,7 +40,7 @@ func (m *MockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (d return args.Get(0).(documents.Model), args.Error(1) } -func (m *MockService) RequestDocumentSignature(ctx *context.Header, model documents.Model) (*coredocumentpb.Signature, error) { +func (m *MockService) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { args := m.Called() return args.Get(0).(*coredocumentpb.Signature), args.Error(1) } From 277972a3854d5a797a8c84937365872eee4a3bbe Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Sat, 29 Dec 2018 11:49:22 +0100 Subject: [PATCH 105/220] Remove P2P GRPC (#597) * Buggy iteration * Remove GRPC POC * Remove GRPC POC * Fix lint * Fix protobuf generated code * Fixed client test * Messenger tests * Messenger tests * correct testworld * remove useless code * Rename --- Gopkg.lock | 14 +- Gopkg.toml | 5 - coredocument/processor.go | 8 +- p2p/bootstrapper.go | 9 +- p2p/client.go | 139 ++++--- p2p/client_test.go | 89 ++++- p2p/messenger.go | 342 ++++++++++++++++++ p2p/messenger_test.go | 116 ++++++ p2p/{grpc => receiver}/handler.go | 64 +++- .../handler_integration_test.go | 6 +- p2p/{grpc => receiver}/handler_test.go | 2 +- p2p/{grpc => receiver}/validator.go | 2 +- p2p/{grpc => receiver}/validator_test.go | 2 +- p2p/server.go | 203 +++++------ p2p/server_test.go | 33 +- protobufs/gen/go/protocol/protocol.pb.go | 129 +++++++ .../swagger/protocol/protocol.swagger.json | 19 + protobufs/protocol/protocol.proto | 24 ++ 18 files changed, 972 insertions(+), 234 deletions(-) create mode 100644 p2p/messenger.go create mode 100644 p2p/messenger_test.go rename p2p/{grpc => receiver}/handler.go (62%) rename p2p/{grpc => receiver}/handler_integration_test.go (98%) rename p2p/{grpc => receiver}/handler_test.go (99%) rename p2p/{grpc => receiver}/validator.go (99%) rename p2p/{grpc => receiver}/validator_test.go (99%) create mode 100644 protobufs/gen/go/protocol/protocol.pb.go create mode 100644 protobufs/gen/swagger/protocol/protocol.swagger.json create mode 100644 protobufs/protocol/protocol.proto diff --git a/Gopkg.lock b/Gopkg.lock index 81c3cf42e..e54abf7ba 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -971,14 +971,6 @@ revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" version = "v1.0.2" -[[projects]] - digest = "1:317c23d0134d82f8158538d6d61ec0b5425319bcd6af716cda898636e51fb757" - name = "github.com/paralin/go-libp2p-grpc" - packages = ["."] - pruneopts = "UT" - revision = "04711f07389ecbca09d7999474dda4a88c955c73" - source = "github.com/vedhavyas/go-libp2p-grpc" - [[projects]] digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9" name = "github.com/pborman/uuid" @@ -1526,11 +1518,13 @@ "github.com/ethereum/go-ethereum/rpc", "github.com/gavv/httpexpect", "github.com/go-errors/errors", + "github.com/gogo/protobuf/io", "github.com/golang/protobuf/jsonpb", "github.com/golang/protobuf/proto", "github.com/golang/protobuf/protoc-gen-go", "github.com/golang/protobuf/ptypes", "github.com/golang/protobuf/ptypes/any", + "github.com/golang/protobuf/ptypes/duration", "github.com/golang/protobuf/ptypes/empty", "github.com/golang/protobuf/ptypes/timestamp", "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway", @@ -1541,17 +1535,19 @@ "github.com/ipfs/go-datastore", "github.com/ipfs/go-ipfs-addr", "github.com/ipfs/go-log", + "github.com/jbenet/go-context/io", "github.com/libp2p/go-libp2p", "github.com/libp2p/go-libp2p-crypto", "github.com/libp2p/go-libp2p-host", "github.com/libp2p/go-libp2p-kad-dht", + "github.com/libp2p/go-libp2p-net", "github.com/libp2p/go-libp2p-peer", "github.com/libp2p/go-libp2p-peerstore", + "github.com/libp2p/go-libp2p-protocol", "github.com/magiconair/properties/assert", "github.com/mitchellh/go-homedir", "github.com/multiformats/go-multiaddr", "github.com/multiformats/go-multihash", - "github.com/paralin/go-libp2p-grpc", "github.com/roboll/go-vendorinstall", "github.com/satori/go.uuid", "github.com/savaki/jq", diff --git a/Gopkg.toml b/Gopkg.toml index 51f388f56..f7b695419 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -214,11 +214,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/multiformats/go-multihash" version = "1.0.8" -[[constraint]] - name = "github.com/paralin/go-libp2p-grpc" - source = "github.com/vedhavyas/go-libp2p-grpc" - revision = "04711f07389ecbca09d7999474dda4a88c955c73" - [[constraint]] name = "github.com/spf13/cobra" version = "0.0.3" diff --git a/coredocument/processor.go b/coredocument/processor.go index a6ecddec2..d6d84d7db 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -41,8 +41,8 @@ type Processor interface { // client defines the methods for p2pclient // we redefined it here so that we can avoid cyclic dependencies with p2p type client interface { - OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) } // defaultProcessor implements Processor interface @@ -73,10 +73,6 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp if err != nil { return errors.New("error fetching receiver identity: %v", err) } - client, err := dp.p2pClient.OpenClient(id) - if err != nil { - return errors.New("failed to open client: %v", err) - } self, err := contextutil.Self(ctx) if err != nil { @@ -92,7 +88,7 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) - resp, err := client.SendAnchoredDocument(c, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) + resp, err := dp.p2pClient.SendAnchoredDocument(c, id, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) if err != nil || !resp.Accepted { return errors.New("failed to send document to the node: %v", err) } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index a7c5944de..e8ddee7cb 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -1,14 +1,11 @@ package p2p import ( - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p/grpc" - "github.com/paralin/go-libp2p-grpc" + "github.com/centrifuge/go-centrifuge/p2p/receiver" ) // Bootstrapped constants that are used as key in bootstrap context @@ -31,8 +28,8 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("registry not initialised") } - srv := &p2pServer{grpcSrvs: make(map[identity.CentID]*p2pgrpc.GRPCProtocol), config: cfg, grpcHandlerCreator: func() p2ppb.P2PServiceServer { - return grpc.New(cfg, registry) + srv := &p2pServer{config: cfg, handlerCreator: func() *receiver.Handler { + return receiver.New(cfg, registry) }} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[BootstrappedP2PClient] = srv diff --git a/p2p/client.go b/p2p/client.go index 5ae46c590..ddca7f0a0 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,9 +4,13 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" @@ -17,36 +21,69 @@ import ( "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" ma "github.com/multiformats/go-multiaddr" - "google.golang.org/grpc" ) // Client defines methods that can be implemented by any type handling p2p communications. type Client interface { - OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) + + // GetSignaturesForDocument gets the signatures for document GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + + // after all signatures are collected the sender sends the document including the signatures + SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) +} + +func (s *p2pServer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { + pid, err := s.getPeerID(id) + if err != nil { + return nil, err + } + marshalledRequest, err := proto.Marshal(in) + if err != nil { + return nil, err + } + recv, err := s.mes.sendMessage(ctx, pid, &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, CentrifugeProtocol) + if err != nil { + return nil, err + } + + // handle client error + if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { + return nil, convertClientError(recv) + } + + if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP { + return nil, errors.New("the received send anchored document response is incorrect") + } + r := new(p2ppb.AnchorDocumentResponse) + err = proto.Unmarshal(recv.Body, r) + if err != nil { + return nil, err + } + return r, nil } // OpenClient returns P2PServiceClient to contact the remote peer -func (s *p2pServer) OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, error) { +func (s *p2pServer) getPeerID(id identity.Identity) (peer.ID, error) { lastB58Key, err := id.CurrentP2PKey() if err != nil { - return nil, errors.New("error fetching p2p key: %v", err) + return "", errors.New("error fetching p2p key: %v", err) } target := fmt.Sprintf("/ipfs/%s", lastB58Key) log.Info("Opening connection to: %s", target) ipfsAddr, err := ma.NewMultiaddr(target) if err != nil { - return nil, err + return "", err } pid, err := ipfsAddr.ValueForProtocol(ma.P_IPFS) if err != nil { - return nil, err + return "", err } peerID, err := peer.IDB58Decode(pid) if err != nil { - return nil, err + return "", err } // Decapsulate the /ipfs/ part from the target @@ -58,54 +95,39 @@ func (s *p2pServer) OpenClient(id identity.Identity) (p2ppb.P2PServiceClient, er // so LibP2P knows how to contact it s.host.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) - // make a new stream from host B to host A with timeout - // Retrial is handled internally, connection request will be cancelled by the connection timeout context - ctx, cancel := context.WithTimeout(context.Background(), s.config.GetP2PConnectionTimeout()) - defer cancel() - // TODO remove this self config and pass in the selfID in the OpenClient function - selfIDBytes, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.New("failed to get self identity: %v", err) - } - selfID, err := identity.ToCentID(selfIDBytes) - if err != nil { - return nil, errors.New("failed to cast self identity: %v", err) - } - gp, ok := s.grpcSrvs[selfID] - if !ok { - return nil, errors.New("failed to dial peer [%s]: no grpc server found for centID [%s]", peerID.Pretty(), id.CentID()) - } - g, err := gp.Dial(ctx, peerID, grpc.WithInsecure(), grpc.WithBlock()) - if err != nil { - return nil, errors.New("failed to dial peer [%s]: %v", peerID.Pretty(), err) - } - - return p2ppb.NewP2PServiceClient(g), nil + return peerID, nil } // getSignatureForDocument requests the target node to sign the document -func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer peer.ID, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { senderID, err := s.config.GetIdentityID() if err != nil { return nil, err } - h := p2ppb.CentrifugeHeader{ - NetworkIdentifier: s.config.GetNetworkID(), - CentNodeVersion: version.GetVersion().String(), - SenderCentrifugeId: senderID, + req, err := s.createSignatureRequest(senderID, &doc) + if err != nil { + return nil, err } - req := &p2ppb.SignatureRequest{ - Header: &h, - Document: &doc, + log.Infof("Requesting signature from %s\n", receiverCentID) + recv, err := s.mes.sendMessage(ctx, receiverPeer, req, CentrifugeProtocol) + if err != nil { + return nil, err } - log.Infof("Requesting signature from %s\n", receiverCentID) + // handle client error + if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { + return nil, convertClientError(recv) + } - resp, err := client.RequestDocumentSignature(ctx, req) + if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP { + return nil, errors.New("the received request signature response is incorrect") + } + resp := new(p2ppb.SignatureResponse) + err = proto.Unmarshal(recv.Body, resp) if err != nil { - return nil, centerrors.Wrap(err, "request for document signature failed") + return nil, err } compatible := version.CheckVersion(resp.CentNodeVersion) @@ -132,8 +154,8 @@ type signatureResponseWrap struct { err error } -func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, client p2ppb.P2PServiceClient, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, identityService, doc, client, receiverCentID) +func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer peer.ID, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, identityService, doc, receiverPeer, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, @@ -166,7 +188,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityServic return centerrors.Wrap(err, "error fetching collaborator identity") } - client, err := s.OpenClient(id) + receiverPeer, err := s.getPeerID(id) if err != nil { log.Error(centerrors.Wrap(err, "failed to connect to target")) continue @@ -176,7 +198,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityServic // we can use context.Timeout for that count++ c, _ := context.WithTimeout(ctx, s.config.GetP2PConnectionTimeout()) - go s.getSignatureAsync(c, identityService, *doc, client, collaboratorID, in) + go s.getSignatureAsync(c, identityService, *doc, receiverPeer, collaboratorID, in) } var responses []signatureResponseWrap @@ -195,3 +217,30 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityServic return nil } + +func (s *p2pServer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { + h := p2ppb.CentrifugeHeader{ + NetworkIdentifier: s.config.GetNetworkID(), + CentNodeVersion: version.GetVersion().String(), + SenderCentrifugeId: senderID, + } + req := &p2ppb.SignatureRequest{ + Header: &h, + Document: doc, + } + + reqB, err := proto.Marshal(req) + if err != nil { + return nil, err + } + return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: reqB}, nil +} + +func convertClientError(recv *protocolpb.P2PEnvelope) error { + resp := new(errorspb.Error) + err := proto.Unmarshal(recv.Body, resp) + if err != nil { + return err + } + return errors.New(resp.Message) +} diff --git a/p2p/client_test.go b/p2p/client_test.go index fb5e7681e..e16569799 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -6,11 +6,17 @@ import ( "context" "testing" + "github.com/golang/protobuf/proto" + + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" @@ -18,22 +24,48 @@ import ( "github.com/stretchr/testify/mock" ) +type MockMessenger struct { + mock.Mock +} + +func (mm *MockMessenger) addHandler(mType protocolpb.MessageType, handler func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *protocolpb.P2PEnvelope) (*protocolpb.P2PEnvelope, error)) { + mm.Called(mType, handler) +} + +func (mm *MockMessenger) init(id ...protocol.ID) { + mm.Called(id) +} + +func (mm *MockMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *protocolpb.P2PEnvelope, protoc protocol.ID) (*protocolpb.P2PEnvelope, error) { + args := mm.Called(ctx, p, pmes, protoc) + resp, _ := args.Get(0).(*protocolpb.P2PEnvelope) + return resp, args.Error(1) +} + func TestGetSignatureForDocument_fail_connect(t *testing.T) { - client := &testingcommons.P2PMockClient{} + m := &MockMessenger{} + testClient := &p2pServer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(nil, errors.New("signature failed")).Once() - resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) - client.AssertExpectations(t) + + sender, err := cfg.GetIdentityID() + assert.Nil(t, err, "sender centrifugeId not initialized correctly ") + r, err := testClient.createSignatureRequest(sender, coreDoc) + assert.Nil(t, err, "signature request could not be created") + + m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(nil, errors.New("some error")) + resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) + m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") } func TestGetSignatureForDocument_fail_version_check(t *testing.T) { - client := &testingcommons.P2PMockClient{} + m := &MockMessenger{} + testClient := &p2pServer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} @@ -41,36 +73,55 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(resp, nil).Once() - resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) - client.AssertExpectations(t) + sender, err := cfg.GetIdentityID() + assert.Nil(t, err, "sender centrifugeId not initialized correctly ") + r, err := testClient.createSignatureRequest(sender, coreDoc) + assert.Nil(t, err, "signature request could not be created") + + m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp("", nil), nil) + resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) + m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") assert.Nil(t, resp, "must be nil") } func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { - client := &testingcommons.P2PMockClient{} + m := &MockMessenger{} + testClient := &p2pServer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - randomBytes := utils.RandomSlice(identity.CentIDLength) + sender, err := cfg.GetIdentityID() + assert.Nil(t, err, "sender centrifugeId not initialized correctly ") + r, err := testClient.createSignatureRequest(sender, coreDoc) + assert.Nil(t, err, "signature request could not be created") + randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - sigResp := &p2ppb.SignatureResponse{ - CentNodeVersion: version.GetVersion().String(), - Signature: signature, - } + m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - client.On("RequestDocumentSignature", ctx, mock.Anything, mock.Anything).Return(sigResp, nil).Once() - resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, client, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) - client.AssertExpectations(t) + m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") assert.Error(t, err, "must not be nil") assert.Contains(t, err.Error(), "[5]provided bytes doesn't match centID") } + +func (s *p2pServer) createSignatureResp(centNodeVer string, signature *coredocumentpb.Signature) *protocolpb.P2PEnvelope { + req := &p2ppb.SignatureResponse{ + CentNodeVersion: centNodeVer, + Signature: signature, + } + + reqB, err := proto.Marshal(req) + if err != nil { + return nil + } + return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, Body: reqB} +} diff --git a/p2p/messenger.go b/p2p/messenger.go new file mode 100644 index 000000000..b3ca4fd93 --- /dev/null +++ b/p2p/messenger.go @@ -0,0 +1,342 @@ +package p2p + +import ( + "bufio" + "context" + "io" + "sync" + "time" + + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/libp2p/go-libp2p-host" + "github.com/libp2p/go-libp2p-protocol" + + pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + ggio "github.com/gogo/protobuf/io" + "github.com/jbenet/go-context/io" + inet "github.com/libp2p/go-libp2p-net" + "github.com/libp2p/go-libp2p-peer" +) + +// ErrReadTimeout must be used when receiving timeout while reading +const ErrReadTimeout = errors.Error("timed out reading response") + +// ErrInvalidatedMessageSender must be used when the message sender object created is no longer valid (connection has dropped) +const ErrInvalidatedMessageSender = errors.Error("message sender has been invalidated") + +type bufferedWriteCloser interface { + ggio.WriteCloser + Flush() error +} + +// The Protobuf writer performs multiple small writes when writing a message. +// We need to buffer those writes, to make sure that we're not sending a new +// packet for every single write. +type bufferedDelimitedWriter struct { + *bufio.Writer + ggio.WriteCloser +} + +func newBufferedDelimitedWriter(str io.Writer) bufferedWriteCloser { + w := bufio.NewWriter(str) + return &bufferedDelimitedWriter{ + Writer: w, + WriteCloser: ggio.NewDelimitedWriter(w), + } +} + +func (w *bufferedDelimitedWriter) Flush() error { + return w.Writer.Flush() +} + +type p2pMessenger struct { + host host.Host // the network services we need + self peer.ID // Local peer (yourself) + + timout time.Duration + ctx context.Context + + strmap map[peer.ID]map[protocol.ID]*messageSender + smlk sync.Mutex + + plk sync.Mutex + + msgHandlers map[pb.MessageType]func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) +} + +func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration) *p2pMessenger { + return &p2pMessenger{ + ctx: ctx, + host: host, + self: host.ID(), + timout: p2pTimeout, + strmap: make(map[peer.ID]map[protocol.ID]*messageSender), + msgHandlers: make(map[pb.MessageType]func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error))} +} + +// init initiates listening to given set of protocol streams +func (mes *p2pMessenger) init(protocols ...protocol.ID) { + for _, p := range protocols { + mes.host.SetStreamHandler(p, mes.handleNewStream) + } +} + +// addHandler adds a message handler for a specific message type +func (mes *p2pMessenger) addHandler(mType pb.MessageType, handler func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) { + mes.msgHandlers[mType] = handler +} + +// handleNewStream implements the inet.StreamHandler +func (mes *p2pMessenger) handleNewStream(s inet.Stream) { + go mes.handleNewMessage(s) +} + +func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { + ctx := mes.ctx + // ok to use. we defer close stream in this func + cr := ctxio.NewReader(ctx, s) + cw := ctxio.NewWriter(ctx, s) + + // delimited readers and writers to set length of the protobuf messages to the stream + r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax) + w := newBufferedDelimitedWriter(cw) + mPeer := s.Conn().RemotePeer() + + for { + // receive msg + pmes := new(pb.P2PEnvelope) + switch err := r.ReadMsg(pmes); err { + case io.EOF: + s.Close() + return + case nil: + default: + s.Reset() + log.Debugf("Error unmarshaling data: %s", err) + return + } + + // get handler for this msg type. + handler := mes.msgHandlers[pmes.GetType()] + if handler == nil { + s.Reset() + log.Warning("got back nil handler from handlerForMsgType") + return + } + + // dispatch handler. + rpmes, err := handler(ctx, mPeer, s.Protocol(), pmes) + if err != nil { + s.Reset() + log.Errorf("handle message error: %s", err) + return + } + + // if nil response, return it before serializing + if rpmes == nil { + log.Warning("got back nil response from request") + continue + } + + // send out response msg + err = w.WriteMsg(rpmes) + if err == nil { + err = w.Flush() + } + if err != nil { + s.Reset() + log.Errorf("send response error: %s", err) + return + } + } +} + +// sendMessage sends out a request +func (mes *p2pMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) { + ms, err := mes.messageSenderForPeerAndProto(p, protoc) + if err != nil { + return nil, err + } + + rpmes, err := ms.sendMessage(ctx, pmes) + if err != nil { + return nil, err + } + + return rpmes, nil +} + +func (mes *p2pMessenger) messageSenderForPeerAndProto(p peer.ID, protoc protocol.ID) (*messageSender, error) { + mes.smlk.Lock() + ms, ok := mes.strmap[p][protoc] + if ok { + mes.smlk.Unlock() + return ms, nil + } + + // create a new message sender for the peer and protocol + ms = &messageSender{p: p, mes: mes, protoc: protoc} + if mes.strmap[p] == nil { + mes.strmap[p] = make(map[protocol.ID]*messageSender) + } + mes.strmap[p][protoc] = ms + mes.smlk.Unlock() + + if err := ms.prepOrInvalidate(); err != nil { + mes.smlk.Lock() + defer mes.smlk.Unlock() + + if msCur, ok := mes.strmap[p][protoc]; ok { + // Changed. Use the new one, old one is invalid and + // not in the map so we can just throw it away. + if ms != msCur { + return msCur, nil + } + // Not changed, remove the now invalid stream from the + // map. + delete(mes.strmap[p], protoc) + } + // Invalid but not in map. Must have been removed by a disconnect. + return nil, err + } + // All ready to go. + return ms, nil +} + +type messageSender struct { + s inet.Stream + r ggio.ReadCloser + w bufferedWriteCloser + lk sync.Mutex + p peer.ID + protoc protocol.ID + mes *p2pMessenger + + invalid bool + singleMes int +} + +// invalidate is called before this messageSender is removed from the strmap. +// It prevents the messageSender from being reused/reinitialized and then +// forgotten (leaving the stream open). +func (ms *messageSender) invalidate() { + ms.invalid = true + if ms.s != nil { + ms.s.Reset() + ms.s = nil + } +} + +func (ms *messageSender) prepOrInvalidate() error { + ms.lk.Lock() + defer ms.lk.Unlock() + if err := ms.prep(); err != nil { + ms.invalidate() + return err + } + return nil +} + +func (ms *messageSender) prep() error { + if ms.invalid { + return ErrInvalidatedMessageSender + } + if ms.s != nil { + return nil + } + + // set the p2p timeout as the connection timeout + timeoutCtx, canc := context.WithTimeout(ms.mes.ctx, ms.mes.timout) + nstr, err := ms.mes.host.NewStream(timeoutCtx, ms.p, ms.protoc) + if err != nil { + canc() + return err + } + + ms.r = ggio.NewDelimitedReader(nstr, inet.MessageSizeMax) + ms.w = newBufferedDelimitedWriter(nstr) + ms.s = nstr + + return nil +} + +// streamReuseTries is the number of times we will try to reuse a stream to a +// given peer before giving up and reverting to the old one-message-per-stream +// behaviour. +const streamReuseTries = 3 + +func (ms *messageSender) sendMessage(ctx context.Context, pmes *pb.P2PEnvelope) (*pb.P2PEnvelope, error) { + ms.lk.Lock() + defer ms.lk.Unlock() + retry := false + for { + if err := ms.prep(); err != nil { + return nil, err + } + + if err := ms.writeMsg(pmes); err != nil { + ms.s.Reset() + ms.s = nil + + if retry { + log.Info("error writing message, bailing: ", err) + return nil, err + } + log.Info("error writing message, trying again: ", err) + retry = true + continue + + } + + mes := new(pb.P2PEnvelope) + if err := ms.ctxReadMsg(ctx, mes); err != nil { + ms.s.Reset() + ms.s = nil + + if retry { + log.Info("error reading message, bailing: ", err) + return nil, err + } + log.Info("error reading message, trying again: ", err) + retry = true + continue + + } + + if ms.singleMes > streamReuseTries { + go inet.FullClose(ms.s) + ms.s = nil + } else if retry { + ms.singleMes++ + } + + return mes, nil + } +} + +func (ms *messageSender) writeMsg(pmes *pb.P2PEnvelope) error { + if err := ms.w.WriteMsg(pmes); err != nil { + return err + } + return ms.w.Flush() +} + +func (ms *messageSender) ctxReadMsg(ctx context.Context, mes *pb.P2PEnvelope) error { + errc := make(chan error, 1) + go func(r ggio.ReadCloser) { + errc <- r.ReadMsg(mes) + }(ms.r) + + t := time.NewTimer(ms.mes.timout) + defer t.Stop() + + select { + case err := <-errc: + return err + case <-ctx.Done(): + return ctx.Err() + case <-t.C: + return ErrReadTimeout + } +} diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go new file mode 100644 index 000000000..d23b28463 --- /dev/null +++ b/p2p/messenger_test.go @@ -0,0 +1,116 @@ +// +build unit + +package p2p + +import ( + "context" + "crypto/rand" + "fmt" + "io" + "testing" + "time" + + "github.com/centrifuge/go-centrifuge/errors" + + pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/libp2p/go-libp2p-crypto" + "github.com/libp2p/go-libp2p-host" + "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" + "github.com/stretchr/testify/assert" +) + +const MessengerDummyProtocol protocol.ID = "/messeger/dummy/0.0.1" +const MessengerDummyProtocol2 protocol.ID = "/messeger/dummy/0.0.2" + +// Using a single test for all cases to use the same hosts in a synchronous way +func TestHandleNewMessage(t *testing.T) { + c, canc := context.WithCancel(context.Background()) + r := rand.Reader + p1 := 35000 + p2 := 35001 + p3 := 35002 + h1 := createRandomHost(t, p1, r) + h2 := createRandomHost(t, p2, r) + h3 := createRandomHost(t, p3, r) + // set h2 as the bootnode for h1 + _ = runDHT(c, h1, []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", p2, h2.ID().Pretty())}) + + m1 := newP2PMessenger(c, h1, 1*time.Second) + m1.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP}, nil + }) + m2 := newP2PMessenger(c, h2, 1*time.Second) + m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP}, nil + }) + m2.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC}, nil + }) + // error + m2.addHandler(pb.MessageType_MESSAGE_TYPE_ERROR, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + return nil, errors.New("dummy error") + }) + // nil response - message type here is irrelevant using the reply type for convenience + m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + return nil, nil + }) + + m1.init(MessengerDummyProtocol) + m2.init(MessengerDummyProtocol) + m2.init(MessengerDummyProtocol2) + + // 1. happy path + // from h1 to h2 + msg, err := m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + assert.NoError(t, err) + assert.Equal(t, pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, msg.Type) + // from h1 to h2 different protocol - intentionally setting reply-response in opposite for differentiation + msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, Body: utils.RandomSlice(3)}, MessengerDummyProtocol2) + assert.NoError(t, err) + assert.Equal(t, pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, msg.Type) + // from h2 to h1 + msg, err = m2.sendMessage(c, h1.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + assert.NoError(t, err) + assert.Equal(t, pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, msg.Type) + + // 2. unrecognized protocol + msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, "wrong") + if assert.Error(t, err) { + assert.Equal(t, "protocol not supported", err.Error()) + } + + // 3. unrecognized message type - stream would be reset by the peer + msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_INVALID, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } + + // 4. handler error + msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_ERROR, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } + + // 5. can't find host - h3 + msg, err = m1.sendMessage(c, h3.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "dial attempt failed: failed to dial Date: Sun, 30 Dec 2018 12:30:01 +0100 Subject: [PATCH 106/220] [MultiTenancy] Enable config database and api (#602) * Enable config database and api * Enable config database and api * Minor * Fix createConfig issue * Add Testworld test for config API * Fix bug with GET /config/tenant/list (end point url ambigous) * Fix bug with GET /config/tenant/list (end point url ambigous) * Lint fix * Generate swagger * Remove race detection from TestWorld to improve perf * Fix unit tests --- anchors/ethereum_anchor_repository.go | 1 + api/bootstrapper.go | 6 + api/bootstrapper_test.go | 3 + api/server_test.go | 3 + api/service.go | 14 ++ bootstrap/bootstrappers/bootstrapper.go | 16 ++ .../testingbootstrap/testing_bootstrap.go | 2 + cmd/common.go | 8 +- config/configstore/bootstrapper.go | 57 ++++++ config/configstore/bootstrapper_test.go | 26 +++ config/configstore/error.go | 8 + config/{ => configstore}/handler.go | 2 +- config/{ => configstore}/handler_test.go | 2 +- config/configstore/mock_service.go | 45 +++++ config/{ => configstore}/model.go | 82 ++++---- config/{ => configstore}/model_test.go | 108 ++++------- config/{ => configstore}/repository.go | 22 +-- config/{ => configstore}/repository_test.go | 60 +++--- config/{ => configstore}/service.go | 2 +- config/{ => configstore}/service_test.go | 2 +- config/configstore/test_bootstrapper.go | 11 ++ config/test_bootstrapper.go | 21 +-- contextutil/context.go | 19 +- coredocument/processor.go | 3 +- documents/genericdoc/service.go | 1 + documents/invoice/handler.go | 3 +- documents/invoice/service.go | 1 + documents/purchaseorder/handler.go | 3 +- documents/purchaseorder/service.go | 1 + ethereum/geth_client.go | 3 +- identity/ethereum_identity.go | 2 + .../key_registration_confirmation_task.go | 9 +- nft/ethereum_payment_obligation.go | 7 +- notification/notification.go | 1 + protobufs/config/service.proto | 2 +- protobufs/gen/go/config/service.pb.go | 178 +++++++++--------- protobufs/gen/go/config/service.pb.gw.go | 2 +- protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 32 ++-- storage/test_bootstrapper.go | 3 +- testworld/config_test.go | 29 +++ testworld/httputils.go | 26 +++ 42 files changed, 531 insertions(+), 297 deletions(-) create mode 100644 config/configstore/bootstrapper.go create mode 100644 config/configstore/bootstrapper_test.go create mode 100644 config/configstore/error.go rename config/{ => configstore}/handler.go (99%) rename config/{ => configstore}/handler_test.go (99%) create mode 100644 config/configstore/mock_service.go rename config/{ => configstore}/model.go (77%) rename config/{ => configstore}/model_test.go (79%) rename config/{ => configstore}/repository.go (93%) rename config/{ => configstore}/repository_test.go (88%) rename config/{ => configstore}/service.go (98%) rename config/{ => configstore}/service_test.go (99%) create mode 100644 config/configstore/test_bootstrapper.go create mode 100644 testworld/config_test.go diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index ab2defb0a..c2a38ae1a 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -29,6 +29,7 @@ type watchAnchorPreCommitted interface { } type ethereumAnchorRepository struct { + // TODO [multi-tenancy] replace this with config service config Config anchorRepositoryContract anchorRepositoryContract gethClientFinder func() ethereum.Client diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 1028555af..03ffdecf8 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -2,6 +2,7 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" ) @@ -16,6 +17,11 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("config not initialised") } + _, ok = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + if !ok { + return errors.New("config store not initialised") + } + // just check to make sure that registry is initialised _, ok = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index 0c62a19c8..facccab19 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -5,6 +5,8 @@ package api import ( "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" @@ -22,6 +24,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) + m[configstore.BootstrappedConfigStorage] = new(configstore.MockService) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/api/server_test.go b/api/server_test.go index ce9d66a7c..03526a6e4 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -45,6 +47,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, anchors.Bootstrapper{}, diff --git a/api/service.go b/api/service.go index 7d978237e..838d3b2d1 100644 --- a/api/service.go +++ b/api/service.go @@ -3,12 +3,14 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/healthcheck" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/health" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -79,12 +81,24 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, return err } + // nft api nftpb.RegisterNFTServiceServer(grpcServer, nft.GRPCHandler(payObService)) err = nftpb.RegisterNFTServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err } + // config api + configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(configstore.Service) + if !ok { + return errors.New("failed to get %s", configstore.BootstrappedConfigStorage) + } + configpb.RegisterConfigServiceServer(grpcServer, configstore.GRPCHandler(configService)) + err = configpb.RegisterConfigServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) + if err != nil { + return err + } + // transactions txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Service) h := transactions.GRPCHandler(txSrv) diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 422a8d405..31687dc3a 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/api" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" @@ -33,6 +34,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, transactions.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, @@ -47,6 +49,20 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { } } +// PopulateCommandBootstrappers adds all the bootstrapper implementations relevant for one off commands +func (m *MainBootstrapper) PopulateCommandBootstrappers() { + m.Bootstrappers = []bootstrap.Bootstrapper{ + &version.Bootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + transactions.Bootstrapper{}, + ethereum.Bootstrapper{}, + &queue.Bootstrapper{}, + &anchors.Bootstrapper{}, + &identity.Bootstrapper{}, + } +} + // PopulateRunBootstrappers adds blocking Node bootstrapper at the end. // Note: Node bootstrapper must be the last bootstrapper to be invoked as it won't return until node is shutdown func (m *MainBootstrapper) PopulateRunBootstrappers() { diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index b4346b1b7..b40a8bf21 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" @@ -26,6 +27,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, anchors.Bootstrapper{}, diff --git a/cmd/common.go b/cmd/common.go index b093154b7..8c1d6a223 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -124,10 +124,10 @@ func RunBootstrap(cfgFile string) { } } -// BaseBootstrap bootstraps the node for testing purposes mainly -func BaseBootstrap(cfgFile string) map[string]interface{} { +// ExecCmdBootstrap bootstraps the node for command line and testing purposes +func ExecCmdBootstrap(cfgFile string) map[string]interface{} { mb := bootstrappers.MainBootstrapper{} - mb.PopulateBaseBootstrappers() + mb.PopulateCommandBootstrappers() ctx := map[string]interface{}{} ctx[config.BootstrappedConfigFile] = cfgFile err := mb.Bootstrap(ctx) @@ -140,7 +140,7 @@ func BaseBootstrap(cfgFile string) map[string]interface{} { // CommandBootstrap bootstraps the node for one time commands func CommandBootstrap(cfgFile string) (map[string]interface{}, context.CancelFunc, error) { - ctx := BaseBootstrap(cfgFile) + ctx := ExecCmdBootstrap(cfgFile) queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) // init node with only the queue server which is needed by commands n := node.New([]node.Server{queueSrv}) diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go new file mode 100644 index 000000000..7c0c12e5d --- /dev/null +++ b/config/configstore/bootstrapper.go @@ -0,0 +1,57 @@ +package configstore + +import ( + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" +) + +const ( + // BootstrappedConfigStorage indicates that config storage has been bootstrapped and its the key for config storage service in the bootstrap context + BootstrappedConfigStorage string = "BootstrappedConfigStorage" +) + +// Bootstrapper implements bootstrap.Bootstrapper to initialise configstore package. +type Bootstrapper struct{} + +// Bootstrap takes the passed in config file, loads the config and puts the config back into context. +func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + cfg, ok := context[bootstrap.BootstrappedConfig].(config.Configuration) + if !ok { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("could not find the bootstrapped config")) + } + configdb, ok := context[storage.BootstrappedConfigDB].(storage.Repository) + if !ok { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("could not find the storage repository")) + } + repo := &repo{configdb} + service := &service{repo} + + nc := NewNodeConfig(cfg) + configdb.Register(nc) + _, err := service.GetConfig() + // if node config doesn't exist in the db, add it + if err != nil { + nc, err = service.CreateConfig(NewNodeConfig(cfg)) + if err != nil { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + } + } + tc, err := NewTenantConfig(nc.MainIdentity.EthereumDefaultAccountName, cfg) + if err != nil { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + } + configdb.Register(tc) + _, err = service.GetTenant(nc.MainIdentity.ID()) + // if main tenant config doesn't exist in the db, add it + // Another additional check we can do is check if there are more than 0 tenant configs in the db but main tenant is not, then it might indicate a problem + if err != nil { + _, err = service.CreateTenant(tc) + if err != nil { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + } + } + context[BootstrappedConfigStorage] = service + return nil +} diff --git a/config/configstore/bootstrapper_test.go b/config/configstore/bootstrapper_test.go new file mode 100644 index 000000000..b403d3dd4 --- /dev/null +++ b/config/configstore/bootstrapper_test.go @@ -0,0 +1,26 @@ +// +build unit + +package configstore + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_BootstrapHappy(t *testing.T) { + b := Bootstrapper{} + err := b.Bootstrap(ctx) + assert.NoError(t, err) + configService, ok := ctx[BootstrappedConfigStorage].(Service) + assert.True(t, ok) + _, err = configService.GetConfig() + assert.NoError(t, err) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + nc := NewNodeConfig(cfg) + _, err = configService.GetTenant(nc.MainIdentity.IdentityID) + assert.NoError(t, err) +} diff --git a/config/configstore/error.go b/config/configstore/error.go new file mode 100644 index 000000000..43b2986c4 --- /dev/null +++ b/config/configstore/error.go @@ -0,0 +1,8 @@ +package configstore + +import "github.com/centrifuge/go-centrifuge/errors" + +const ( + // ErrConfigStorageBootstrap must be returned when there is an error while bootstrapping the config storage + ErrConfigStorageBootstrap = errors.Error("error when bootstrapping config storage") +) diff --git a/config/handler.go b/config/configstore/handler.go similarity index 99% rename from config/handler.go rename to config/configstore/handler.go index b82881b39..44d3cb85a 100644 --- a/config/handler.go +++ b/config/configstore/handler.go @@ -1,4 +1,4 @@ -package config +package configstore import ( "context" diff --git a/config/handler_test.go b/config/configstore/handler_test.go similarity index 99% rename from config/handler_test.go rename to config/configstore/handler_test.go index 50d327027..da2aa4988 100644 --- a/config/handler_test.go +++ b/config/configstore/handler_test.go @@ -1,6 +1,6 @@ // +build unit -package config +package configstore import ( "context" diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go new file mode 100644 index 000000000..11c4a87d4 --- /dev/null +++ b/config/configstore/mock_service.go @@ -0,0 +1,45 @@ +// +build unit + +package configstore + +import "github.com/stretchr/testify/mock" + +type MockService struct { + mock.Mock +} + +func (MockService) GetConfig() (*NodeConfig, error) { + panic("implement me") +} + +func (MockService) GetTenant(identifier []byte) (*TenantConfig, error) { + panic("implement me") +} + +func (MockService) GetAllTenants() ([]*TenantConfig, error) { + panic("implement me") +} + +func (MockService) CreateConfig(data *NodeConfig) (*NodeConfig, error) { + panic("implement me") +} + +func (MockService) CreateTenant(data *TenantConfig) (*TenantConfig, error) { + panic("implement me") +} + +func (MockService) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { + panic("implement me") +} + +func (MockService) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { + panic("implement me") +} + +func (MockService) DeleteConfig() error { + panic("implement me") +} + +func (MockService) DeleteTenant(identifier []byte) error { + panic("implement me") +} diff --git a/config/model.go b/config/configstore/model.go similarity index 77% rename from config/model.go rename to config/configstore/model.go index afd2401f4..6e02fd280 100644 --- a/config/model.go +++ b/config/configstore/model.go @@ -1,4 +1,4 @@ -package config +package configstore import ( "encoding/json" @@ -6,6 +6,8 @@ import ( "reflect" "time" + "github.com/centrifuge/go-centrifuge/config" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" @@ -109,7 +111,7 @@ func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) { identityID, _ := hexutil.Decode(data.MainIdentity.IdentityId) nc.MainIdentity = TenantConfig{ - EthereumAccount: &AccountConfig{ + EthereumAccount: &config.AccountConfig{ Address: data.MainIdentity.EthAccount.Address, Key: data.MainIdentity.EthAccount.Key, Password: data.MainIdentity.EthAccount.Password, @@ -148,22 +150,22 @@ func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) { } // NewNodeConfig creates a new NodeConfig instance with configs -func NewNodeConfig(config Configuration) *NodeConfig { - mainAccount, _ := config.GetEthereumAccount(config.GetEthereumDefaultAccountName()) - mainIdentity, _ := config.GetIdentityID() - signPub, signPriv := config.GetSigningKeyPair() - ethAuthPub, ethAuthPriv := config.GetEthAuthKeyPair() +func NewNodeConfig(c config.Configuration) *NodeConfig { + mainAccount, _ := c.GetEthereumAccount(c.GetEthereumDefaultAccountName()) + mainIdentity, _ := c.GetIdentityID() + signPub, signPriv := c.GetSigningKeyPair() + ethAuthPub, ethAuthPriv := c.GetEthAuthKeyPair() return &NodeConfig{ MainIdentity: TenantConfig{ - EthereumAccount: &AccountConfig{ + EthereumAccount: &config.AccountConfig{ Address: mainAccount.Address, Key: mainAccount.Key, Password: mainAccount.Password, }, - EthereumDefaultAccountName: config.GetEthereumDefaultAccountName(), + EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), IdentityID: mainIdentity, - ReceiveEventNotificationEndpoint: config.GetReceiveEventNotificationEndpoint(), + ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), SigningKeyPair: KeyPair{ Pub: signPub, Priv: signPriv, @@ -173,31 +175,31 @@ func NewNodeConfig(config Configuration) *NodeConfig { Priv: ethAuthPriv, }, }, - StoragePath: config.GetStoragePath(), - P2PPort: config.GetP2PPort(), - P2PExternalIP: config.GetP2PExternalIP(), - P2PConnectionTimeout: config.GetP2PConnectionTimeout(), - ServerPort: config.GetServerPort(), - ServerAddress: config.GetServerAddress(), - NumWorkers: config.GetNumWorkers(), - WorkerWaitTimeMS: config.GetWorkerWaitTimeMS(), - EthereumNodeURL: config.GetEthereumNodeURL(), - EthereumContextReadWaitTimeout: config.GetEthereumContextReadWaitTimeout(), - EthereumContextWaitTimeout: config.GetEthereumContextWaitTimeout(), - EthereumIntervalRetry: config.GetEthereumIntervalRetry(), - EthereumMaxRetries: config.GetEthereumMaxRetries(), - EthereumGasPrice: config.GetEthereumGasPrice(), - EthereumGasLimit: config.GetEthereumGasLimit(), - TxPoolAccessEnabled: config.GetTxPoolAccessEnabled(), - NetworkString: config.GetNetworkString(), - BootstrapPeers: config.GetBootstrapPeers(), - NetworkID: config.GetNetworkID(), + StoragePath: c.GetStoragePath(), + P2PPort: c.GetP2PPort(), + P2PExternalIP: c.GetP2PExternalIP(), + P2PConnectionTimeout: c.GetP2PConnectionTimeout(), + ServerPort: c.GetServerPort(), + ServerAddress: c.GetServerAddress(), + NumWorkers: c.GetNumWorkers(), + WorkerWaitTimeMS: c.GetWorkerWaitTimeMS(), + EthereumNodeURL: c.GetEthereumNodeURL(), + EthereumContextReadWaitTimeout: c.GetEthereumContextReadWaitTimeout(), + EthereumContextWaitTimeout: c.GetEthereumContextWaitTimeout(), + EthereumIntervalRetry: c.GetEthereumIntervalRetry(), + EthereumMaxRetries: c.GetEthereumMaxRetries(), + EthereumGasPrice: c.GetEthereumGasPrice(), + EthereumGasLimit: c.GetEthereumGasLimit(), + TxPoolAccessEnabled: c.GetTxPoolAccessEnabled(), + NetworkString: c.GetNetworkString(), + BootstrapPeers: c.GetBootstrapPeers(), + NetworkID: c.GetNetworkID(), } } // TenantConfig exposes configs specific to a tenant in the node type TenantConfig struct { - EthereumAccount *AccountConfig + EthereumAccount *config.AccountConfig EthereumDefaultAccountName string ReceiveEventNotificationEndpoint string IdentityID []byte @@ -206,8 +208,8 @@ type TenantConfig struct { } // ID Get the ID of the document represented by this model -func (tc *TenantConfig) ID() ([]byte, error) { - return tc.IdentityID, nil +func (tc *TenantConfig) ID() []byte { + return tc.IdentityID } // Type Returns the underlying type of the Model @@ -247,7 +249,7 @@ func (tc *TenantConfig) createProtobuf() *configpb.TenantData { } func (tc *TenantConfig) loadFromProtobuf(data *configpb.TenantData) { - tc.EthereumAccount = &AccountConfig{ + tc.EthereumAccount = &config.AccountConfig{ Address: data.EthAccount.Address, Key: data.EthAccount.Key, Password: data.EthAccount.Password, @@ -266,21 +268,21 @@ func (tc *TenantConfig) loadFromProtobuf(data *configpb.TenantData) { } // NewTenantConfig creates a new TenantConfig instance with configs -func NewTenantConfig(ethAccountName string, config Configuration) (*TenantConfig, error) { - id, err := config.GetIdentityID() +func NewTenantConfig(ethAccountName string, c config.Configuration) (*TenantConfig, error) { + id, err := c.GetIdentityID() if err != nil { return nil, err } - acc, err := config.GetEthereumAccount(ethAccountName) + acc, err := c.GetEthereumAccount(ethAccountName) if err != nil { return nil, err } return &TenantConfig{ EthereumAccount: acc, - EthereumDefaultAccountName: config.GetEthereumDefaultAccountName(), + EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), IdentityID: id, - ReceiveEventNotificationEndpoint: config.GetReceiveEventNotificationEndpoint(), - SigningKeyPair: NewKeyPair(config.GetSigningKeyPair()), - EthAuthKeyPair: NewKeyPair(config.GetEthAuthKeyPair()), + ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), + SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), + EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil } diff --git a/config/model_test.go b/config/configstore/model_test.go similarity index 79% rename from config/model_test.go rename to config/configstore/model_test.go index abbbbb87e..71775a1ed 100644 --- a/config/model_test.go +++ b/config/configstore/model_test.go @@ -1,10 +1,12 @@ // +build unit -package config +package configstore import ( "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/ethereum/go-ethereum/common/hexutil" "math/big" @@ -17,7 +19,7 @@ import ( ) type mockConfig struct { - Configuration + config.Configuration mock.Mock } @@ -111,9 +113,9 @@ func (m *mockConfig) GetEthereumDefaultAccountName() string { return args.Get(0).(string) } -func (m *mockConfig) GetEthereumAccount(accountName string) (account *AccountConfig, err error) { +func (m *mockConfig) GetEthereumAccount(accountName string) (account *config.AccountConfig, err error) { args := m.Called(accountName) - return args.Get(0).(*AccountConfig), args.Error(1) + return args.Get(0).(*config.AccountConfig), args.Error(1) } func (m *mockConfig) GetTxPoolAccessEnabled() bool { @@ -167,37 +169,7 @@ func (m *mockConfig) GetEthAuthKeyPair() (pub, priv string) { } func TestNewNodeConfig(t *testing.T) { - c := &mockConfig{} - c.On("GetStoragePath").Return("dummyStorage").Once() - c.On("GetP2PPort").Return(30000).Once() - c.On("GetP2PExternalIP").Return("ip").Once() - c.On("GetP2PConnectionTimeout").Return(time.Second).Once() - - c.On("GetServerPort").Return(8080).Once() - c.On("GetServerAddress").Return("dummyServer").Once() - c.On("GetNumWorkers").Return(2).Once() - c.On("GetWorkerWaitTimeMS").Return(1).Once() - c.On("GetEthereumNodeURL").Return("dummyNode").Once() - - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() - c.On("GetSigningKeyPair").Return("pub", "priv").Once() - c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() - c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() - c.On("GetEthereumAccount", "dummyAcc").Return(&AccountConfig{}, nil).Once() - c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() - - c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() - c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() - c.On("GetEthereumIntervalRetry").Return(time.Second).Once() - c.On("GetEthereumMaxRetries").Return(1).Once() - c.On("GetEthereumGasPrice").Return(big.NewInt(1)).Once() - - c.On("GetEthereumGasLimit").Return(uint64(100)).Once() - c.On("GetTxPoolAccessEnabled").Return(true).Once() - c.On("GetNetworkString").Return("somehill").Once() - c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() - - c.On("GetNetworkID").Return(uint32(1)).Once() + c := createMockConfig() NewNodeConfig(c) c.AssertExpectations(t) @@ -205,7 +177,7 @@ func TestNewNodeConfig(t *testing.T) { func TestNewTenantConfig(t *testing.T) { c := &mockConfig{} - c.On("GetEthereumAccount", "name").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() @@ -216,37 +188,7 @@ func TestNewTenantConfig(t *testing.T) { } func TestNodeConfigProtobuf(t *testing.T) { - c := &mockConfig{} - c.On("GetStoragePath").Return("dummyStorage").Once() - c.On("GetP2PPort").Return(30000).Once() - c.On("GetP2PExternalIP").Return("ip").Once() - c.On("GetP2PConnectionTimeout").Return(time.Second).Once() - - c.On("GetServerPort").Return(8080).Once() - c.On("GetServerAddress").Return("dummyServer").Once() - c.On("GetNumWorkers").Return(2).Once() - c.On("GetWorkerWaitTimeMS").Return(1).Once() - c.On("GetEthereumNodeURL").Return("dummyNode").Once() - - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() - c.On("GetSigningKeyPair").Return("pub", "priv").Once() - c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() - c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() - c.On("GetEthereumAccount", "dummyAcc").Return(&AccountConfig{}, nil).Once() - c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() - - c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() - c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() - c.On("GetEthereumIntervalRetry").Return(time.Second).Once() - c.On("GetEthereumMaxRetries").Return(1).Once() - c.On("GetEthereumGasPrice").Return(big.NewInt(1)).Once() - - c.On("GetEthereumGasLimit").Return(uint64(100)).Once() - c.On("GetTxPoolAccessEnabled").Return(true).Once() - c.On("GetNetworkString").Return("somehill").Once() - c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() - - c.On("GetNetworkID").Return(uint32(1)).Once() + c := createMockConfig() nc := NewNodeConfig(c) c.AssertExpectations(t) @@ -264,7 +206,7 @@ func TestNodeConfigProtobuf(t *testing.T) { func TestTenantConfigProtobuf(t *testing.T) { c := &mockConfig{} - c.On("GetEthereumAccount", "name").Return(&AccountConfig{}, nil).Once() + c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() @@ -285,3 +227,33 @@ func TestTenantConfigProtobuf(t *testing.T) { assert.Equal(t, tcpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) assert.Equal(t, tcpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) } + +func createMockConfig() *mockConfig { + c := &mockConfig{} + c.On("GetStoragePath").Return("dummyStorage").Once() + c.On("GetP2PPort").Return(30000).Once() + c.On("GetP2PExternalIP").Return("ip").Once() + c.On("GetP2PConnectionTimeout").Return(time.Second).Once() + c.On("GetServerPort").Return(8080).Once() + c.On("GetServerAddress").Return("dummyServer").Once() + c.On("GetNumWorkers").Return(2).Once() + c.On("GetWorkerWaitTimeMS").Return(1).Once() + c.On("GetEthereumNodeURL").Return("dummyNode").Once() + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetSigningKeyPair").Return("pub", "priv").Once() + c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() + c.On("GetEthereumAccount", "dummyAcc").Return(&config.AccountConfig{}, nil).Once() + c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() + c.On("GetEthereumContextReadWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() + c.On("GetEthereumIntervalRetry").Return(time.Second).Once() + c.On("GetEthereumMaxRetries").Return(1).Once() + c.On("GetEthereumGasPrice").Return(big.NewInt(1)).Once() + c.On("GetEthereumGasLimit").Return(uint64(100)).Once() + c.On("GetTxPoolAccessEnabled").Return(true).Once() + c.On("GetNetworkString").Return("somehill").Once() + c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() + c.On("GetNetworkID").Return(uint32(1)).Once() + return c +} diff --git a/config/repository.go b/config/configstore/repository.go similarity index 93% rename from config/repository.go rename to config/configstore/repository.go index 6f31c026f..79071f046 100644 --- a/config/repository.go +++ b/config/configstore/repository.go @@ -1,4 +1,4 @@ -package config +package configstore import ( "github.com/centrifuge/go-centrifuge/storage" @@ -55,11 +55,11 @@ type repo struct { db storage.Repository } -func (r *repo) getTenantKey(id []byte) []byte { +func getTenantKey(id []byte) []byte { return append([]byte(tenantPrefix), id...) } -func (r *repo) getConfigKey() []byte { +func getConfigKey() []byte { return []byte(configPrefix) } @@ -80,7 +80,7 @@ func (r *repo) RegisterConfig(config *NodeConfig) { // GetTenant returns the tenant config Model associated with tenant ID func (r *repo) GetTenant(id []byte) (*TenantConfig, error) { - key := r.getTenantKey(id) + key := getTenantKey(id) model, err := r.db.Get(key) if err != nil { return nil, err @@ -90,7 +90,7 @@ func (r *repo) GetTenant(id []byte) (*TenantConfig, error) { // GetConfig returns the node config model func (r *repo) GetConfig() (*NodeConfig, error) { - key := r.getConfigKey() + key := getConfigKey() model, err := r.db.Get(key) if err != nil { return nil, err @@ -115,41 +115,41 @@ func (r *repo) GetAllTenants() ([]*TenantConfig, error) { // Create creates the tenant config model if not present in the DB. // should error out if the config exists. func (r *repo) CreateTenant(id []byte, tenant *TenantConfig) error { - key := r.getTenantKey(id) + key := getTenantKey(id) return r.db.Create(key, tenant) } // Create creates the node config model if not present in the DB. // should error out if the config exists. func (r *repo) CreateConfig(nodeConfig *NodeConfig) error { - key := r.getConfigKey() + key := getConfigKey() return r.db.Create(key, nodeConfig) } // Update strictly updates the tenant config model. // Will error out when the config model doesn't exist in the DB. func (r *repo) UpdateTenant(id []byte, tenant *TenantConfig) error { - key := r.getTenantKey(id) + key := getTenantKey(id) return r.db.Update(key, tenant) } // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. func (r *repo) UpdateConfig(nodeConfig *NodeConfig) error { - key := r.getConfigKey() + key := getConfigKey() return r.db.Update(key, nodeConfig) } // Delete deletes tenant config // Will not error out when config model doesn't exists in DB func (r *repo) DeleteTenant(id []byte) error { - key := r.getTenantKey(id) + key := getTenantKey(id) return r.db.Delete(key) } // Delete deletes node config // Will not error out when config model doesn't exists in DB func (r *repo) DeleteConfig() error { - key := r.getConfigKey() + key := getConfigKey() return r.db.Delete(key) } diff --git a/config/repository_test.go b/config/configstore/repository_test.go similarity index 88% rename from config/repository_test.go rename to config/configstore/repository_test.go index ac4693b85..a957b13a6 100644 --- a/config/repository_test.go +++ b/config/configstore/repository_test.go @@ -1,12 +1,14 @@ // +build unit -package config +package configstore import ( "os" "reflect" "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -17,34 +19,21 @@ import ( var dbFiles []string var ctx = map[string]interface{}{} -var cfg Configuration - -func cleanupDBFiles() { - for _, db := range dbFiles { - err := os.RemoveAll(db) - if err != nil { - log.Warningf("Cleanup warn: %v", err) - } - } -} - -func getRandomStorage() (Repository, string, error) { - randomPath := storage.GetRandomTestStoragePath() - db, err := storage.NewLevelDBStorage(randomPath) - if err != nil { - return nil, "", err - } - dbFiles = append(dbFiles, randomPath) - return NewDBRepository(storage.NewLevelDBRepository(db)), randomPath, nil -} +var cfg config.Configuration func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, - &Bootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(Configuration) + configdb := ctx[storage.BootstrappedConfigDB].(storage.Repository) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + nc := NewNodeConfig(cfg) + // clean db + _ = configdb.Delete(getConfigKey()) + _ = configdb.Delete(getTenantKey(nc.MainIdentity.IdentityID)) result := m.Run() cleanupDBFiles() os.Exit(result) @@ -177,10 +166,29 @@ func TestLevelDBRepo_GetAllTenants(t *testing.T) { tenants, err := repo.GetAllTenants() assert.Nil(t, err) assert.Equal(t, 3, len(tenants)) - t0Id, _ := tenants[0].ID() - t1Id, _ := tenants[1].ID() - t2Id, _ := tenants[2].ID() + t0Id := tenants[0].ID() + t1Id := tenants[1].ID() + t2Id := tenants[2].ID() assert.Contains(t, ids, t0Id) assert.Contains(t, ids, t1Id) assert.Contains(t, ids, t2Id) } + +func cleanupDBFiles() { + for _, db := range dbFiles { + err := os.RemoveAll(db) + if err != nil { + apiLog.Warningf("Cleanup warn: %v", err) + } + } +} + +func getRandomStorage() (Repository, string, error) { + randomPath := storage.GetRandomTestStoragePath() + db, err := storage.NewLevelDBStorage(randomPath) + if err != nil { + return nil, "", err + } + dbFiles = append(dbFiles, randomPath) + return NewDBRepository(storage.NewLevelDBRepository(db)), randomPath, nil +} diff --git a/config/service.go b/config/configstore/service.go similarity index 98% rename from config/service.go rename to config/configstore/service.go index aa076a61d..36832ffb8 100644 --- a/config/service.go +++ b/config/configstore/service.go @@ -1,4 +1,4 @@ -package config +package configstore // Service exposes functions over the config objects type Service interface { diff --git a/config/service_test.go b/config/configstore/service_test.go similarity index 99% rename from config/service_test.go rename to config/configstore/service_test.go index ce9338d51..4f5283e39 100644 --- a/config/service_test.go +++ b/config/configstore/service_test.go @@ -1,6 +1,6 @@ // +build unit -package config +package configstore import ( "testing" diff --git a/config/configstore/test_bootstrapper.go b/config/configstore/test_bootstrapper.go new file mode 100644 index 000000000..9eb20f00d --- /dev/null +++ b/config/configstore/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build integration unit + +package configstore + +func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { + return b.Bootstrap(context) +} + +func (b *Bootstrapper) TestTearDown() error { + return nil +} diff --git a/config/test_bootstrapper.go b/config/test_bootstrapper.go index f3fb49a4d..ccec8d9da 100644 --- a/config/test_bootstrapper.go +++ b/config/test_bootstrapper.go @@ -4,8 +4,8 @@ package config import ( "fmt" - "path/filepath" - "strings" + "os" + "path" "github.com/centrifuge/go-centrifuge/bootstrap" ) @@ -15,20 +15,9 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) error { return nil } // To get the config location, we need to traverse the path to find the `go-centrifuge` folder - path, _ := filepath.Abs("./") - match := "" - for match == "" { - path = filepath.Join(path, "../") - if strings.HasSuffix(path, "go-centrifuge") { - match = path - } - if filepath.Dir(path) == "/" { - log.Fatal("Current working dir is not in `go-centrifuge`") - } - } - - context[bootstrap.BootstrappedConfig] = LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", match)) - + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") + context[bootstrap.BootstrappedConfig] = LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", projDir)) return nil } diff --git a/contextutil/context.go b/contextutil/context.go index 60ceee1cb..7a3ec39cd 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -8,26 +8,31 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -// ErrIDConfigNotFound must be used when configuration can't be found -const ErrIDConfigNotFound = errors.Error("id configuration wasn't found") +type contextKey string -// ErrSelfNotFound must be used when self value is not found in the context -const ErrSelfNotFound = errors.Error("self value not found in the context") +const ( + // ErrIDConfigNotFound must be used when configuration can't be found + ErrIDConfigNotFound = errors.Error("id configuration wasn't found") -type selfKey string + // ErrSelfNotFound must be used when self value is not found in the context + ErrSelfNotFound = errors.Error("self value not found in the context") + + self = contextKey("self") +) // NewCentrifugeContext creates new instance of the request headers. +// TODO [multi-tenancy] replace config.Configuration with *configstore.TenantConfig func NewCentrifugeContext(ctx context.Context, config config.Configuration) (context.Context, error) { idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) if err != nil { return nil, errors.NewTypedError(ErrIDConfigNotFound, errors.New("%v", err)) } - return context.WithValue(ctx, selfKey("self"), idConfig), nil + return context.WithValue(ctx, self, idConfig), nil } // Self returns Self CentID. func Self(ctx context.Context) (*identity.IDConfig, error) { - self, ok := ctx.Value(selfKey("self")).(*identity.IDConfig) + self, ok := ctx.Value(self).(*identity.IDConfig) if ok { return self, nil } diff --git a/coredocument/processor.go b/coredocument/processor.go index d6d84d7db..f23b400b6 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -50,7 +50,8 @@ type defaultProcessor struct { identityService identity.Service p2pClient client anchorRepository anchors.AnchorRepository - config Config + // TODO [multi-tenancy] replace this with config service + config Config } // DefaultProcessor returns the default implementation of CoreDocument Processor diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 472ada1c5..761329011 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -29,6 +29,7 @@ import ( // service implements Service type service struct { + // TODO [multi-tenancy] replace this with config service config documents.Config repo documents.Repository identityService identity.Service diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index b1e35b02b..08551d740 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -22,7 +22,8 @@ var apiLog = logging.Logger("invoice-api") // anchoring, sending, finding stored invoice document type grpcHandler struct { service Service - config config.Configuration + // TODO [multi-tenancy] replace this with config service + config config.Configuration } // GRPCHandler returns an implementation of invoice.DocumentServiceServer diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 1963ac34c..b7e932beb 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -54,6 +54,7 @@ type Service interface { // service implements Service and handles all invoice related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { + // TODO [multi-tenancy] replace this with config service config documents.Config repo documents.Repository coreDocProcessor coredocument.Processor diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index b1f265cde..4beb731ab 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -23,7 +23,8 @@ var apiLog = logging.Logger("purchaseorder-api") // anchoring, sending, finding stored purchase order document type grpcHandler struct { service Service - config config.Configuration + // TODO [multi-tenancy] replace this with config service + config config.Configuration } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 81ca55c12..dd56fa746 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -54,6 +54,7 @@ type Service interface { // service implements Service and handles all purchase order related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { + // TODO [multi-tenancy] replace this with config service config documents.Config repo documents.Repository coreDocProcessor coredocument.Processor diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index ffa7dbf70..ebf9610d3 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -80,7 +80,8 @@ type gethClient struct { host *url.URL accounts map[string]*bind.TransactOpts accMu sync.Mutex // accMu to protect accounts - config Config + // TODO [multi-tenancy] replace this with config service + config Config // txMu to ensure one transaction at a time per client txMu sync.Mutex diff --git a/identity/ethereum_identity.go b/identity/ethereum_identity.go index ec5316967..207088b4e 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethereum_identity.go @@ -80,6 +80,7 @@ type ethereumIdentity struct { contract contract contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) registryContract registry + // TODO [multi-tenancy] replace this with config service config Config gethClientFinder func() ethereum.Client queue *queue.Server @@ -348,6 +349,7 @@ func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue // EthereumIdentityService implements `Service` type EthereumIdentityService struct { + // TODO [multi-tenancy] replace this with config service config Config factoryContract factory registryContract registry diff --git a/identity/key_registration_confirmation_task.go b/identity/key_registration_confirmation_task.go index 5cac6f7c1..d448e2f8f 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/key_registration_confirmation_task.go @@ -37,10 +37,11 @@ type keyRegistrationConfirmationTask struct { ctx context.Context filterer keyRegisteredFilterer contract *EthereumIdentityRegistryContract - config Config - gethClientFinder func() ethereum.Client - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) - queue *queue.Server + // TODO [multi-tenancy] replace this with config service + config Config + gethClientFinder func() ethereum.Client + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) + queue *queue.Server } func newKeyRegistrationConfirmationTask( diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index c1ff084b0..fb0d2c026 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -41,9 +41,10 @@ type ethereumPaymentObligationContract interface { // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum type ethereumPaymentObligation struct { - registry *documents.ServiceRegistry - identityService identity.Service - ethClient ethereum.Client + registry *documents.ServiceRegistry + identityService identity.Service + ethClient ethereum.Client + // TODO [multi-tenancy] replace this with config service config Config queue *queue.Server setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error) diff --git a/notification/notification.go b/notification/notification.go index 9b620fb95..ba51fff22 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -43,6 +43,7 @@ func NewWebhookSender(config Config) Sender { // NewWebhookSender implements Sender. // Sends notification through a webhook defined. type webhookSender struct { + // TODO [multi-tenancy] replace this with config service config Config } diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index 675843b1c..f30e632f9 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -32,7 +32,7 @@ service ConfigService { } rpc GetAllTenants(google.protobuf.Empty) returns (GetAllTenantResponse) { option (google.api.http) = { - get: "/config/tenant/list" + get: "/config/tenant" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Get All Tenant Configs" diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index cd9f37f8c..3f54e730c 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -38,7 +38,7 @@ func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } func (*GetTenantRequest) ProtoMessage() {} func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{0} + return fileDescriptor_service_c60469d31810ca8e, []int{0} } func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } func (*GetAllTenantResponse) ProtoMessage() {} func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{1} + return fileDescriptor_service_c60469d31810ca8e, []int{1} } func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) @@ -115,7 +115,7 @@ func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } func (*UpdateTenantRequest) ProtoMessage() {} func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{2} + return fileDescriptor_service_c60469d31810ca8e, []int{2} } func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) @@ -162,7 +162,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{3} + return fileDescriptor_service_c60469d31810ca8e, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -215,7 +215,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{4} + return fileDescriptor_service_c60469d31810ca8e, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -265,7 +265,7 @@ func (m *TenantData) Reset() { *m = TenantData{} } func (m *TenantData) String() string { return proto.CompactTextString(m) } func (*TenantData) ProtoMessage() {} func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{5} + return fileDescriptor_service_c60469d31810ca8e, []int{5} } func (m *TenantData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TenantData.Unmarshal(m, b) @@ -357,7 +357,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_5680e2fa0c56bd70, []int{6} + return fileDescriptor_service_c60469d31810ca8e, []int{6} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -863,86 +863,86 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_5680e2fa0c56bd70) } - -var fileDescriptor_service_5680e2fa0c56bd70 = []byte{ - // 1248 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xfb, 0x6e, 0x1b, 0xc5, - 0x17, 0x96, 0x9b, 0x36, 0x97, 0xf1, 0x25, 0xc9, 0x24, 0x69, 0xb7, 0xdb, 0xa6, 0xdd, 0xdf, 0xfe, - 0x44, 0xb1, 0xaa, 0x26, 0x96, 0x0c, 0xa2, 0x2d, 0x12, 0x08, 0x37, 0x89, 0xa2, 0x08, 0x5a, 0xac, - 0xa5, 0x55, 0x05, 0x08, 0xad, 0x26, 0xde, 0x13, 0x7b, 0xd5, 0xf5, 0xcc, 0x30, 0x7b, 0x9c, 0xc4, - 0x42, 0x15, 0x82, 0x47, 0x30, 0x8f, 0xc0, 0x7f, 0xbc, 0x0e, 0xaf, 0x00, 0xef, 0x81, 0xe6, 0xb2, - 0x89, 0x1d, 0x3b, 0x89, 0xfa, 0x97, 0x3d, 0xe7, 0xf2, 0x7d, 0xe7, 0x3b, 0x73, 0x66, 0x66, 0xc9, - 0x7a, 0x47, 0xf0, 0xa3, 0xb4, 0xdb, 0xc8, 0x41, 0x1d, 0xa7, 0x1d, 0xd8, 0x96, 0x4a, 0xa0, 0xa0, - 0xf3, 0xd6, 0xea, 0xdf, 0xef, 0x0a, 0xd1, 0xcd, 0xa0, 0xc1, 0x64, 0xda, 0x60, 0x9c, 0x0b, 0x64, - 0x98, 0x0a, 0x9e, 0xdb, 0x28, 0xff, 0x81, 0xf3, 0x9a, 0xd5, 0xe1, 0xe0, 0xa8, 0x91, 0x0c, 0x94, - 0x09, 0x70, 0xfe, 0x7b, 0x17, 0xfd, 0xd0, 0x97, 0x38, 0x74, 0xce, 0x27, 0xe6, 0xa7, 0xb3, 0xd5, - 0x05, 0xbe, 0x95, 0x9f, 0xb0, 0x6e, 0x17, 0x54, 0x43, 0x48, 0x03, 0x3f, 0x4d, 0x15, 0x36, 0xc9, - 0xca, 0x3e, 0xe0, 0x6b, 0xe0, 0x8c, 0x63, 0x04, 0x3f, 0x0f, 0x20, 0x47, 0xfa, 0x80, 0x90, 0x34, - 0x01, 0x8e, 0xe9, 0x51, 0x0a, 0xca, 0x2b, 0x05, 0xa5, 0xfa, 0x52, 0x34, 0x66, 0x09, 0xbf, 0x24, - 0xeb, 0xfb, 0x80, 0xad, 0x2c, 0x2b, 0xd2, 0x72, 0x29, 0x78, 0x0e, 0xf4, 0x11, 0xb9, 0x99, 0x30, - 0x64, 0x5e, 0x29, 0x98, 0xab, 0x97, 0x9b, 0x74, 0xdb, 0x6a, 0xdd, 0xb6, 0x51, 0xbb, 0x0c, 0x59, - 0x64, 0xfc, 0xe1, 0x4f, 0x64, 0xed, 0x8d, 0x4c, 0x18, 0xc2, 0x07, 0xd1, 0x9e, 0xc1, 0xdf, 0x08, - 0x4a, 0x57, 0xc2, 0x7f, 0x4f, 0x96, 0xf7, 0xb0, 0x07, 0x0a, 0x06, 0xfd, 0x56, 0xa7, 0x23, 0x06, - 0x1c, 0xa9, 0x47, 0x16, 0x58, 0x92, 0x28, 0xc8, 0x73, 0x87, 0x5b, 0x2c, 0xe9, 0x0a, 0x99, 0x7b, - 0x07, 0x43, 0x83, 0xb9, 0x14, 0xe9, 0xbf, 0xd4, 0x27, 0x8b, 0x92, 0xe5, 0xf9, 0x89, 0x50, 0x89, - 0x37, 0x67, 0xcc, 0x67, 0xeb, 0x70, 0x8b, 0x2c, 0x7c, 0x0d, 0xc3, 0x36, 0x4b, 0x95, 0x4e, 0x94, - 0x83, 0x43, 0x07, 0xa7, 0xff, 0x1a, 0xcb, 0x31, 0x16, 0x50, 0xf2, 0x18, 0xc3, 0x7f, 0x6f, 0x10, - 0x72, 0x5e, 0x1e, 0x7d, 0x46, 0xca, 0x80, 0xbd, 0x98, 0xd9, 0xa2, 0x4c, 0x6a, 0xb9, 0x79, 0xa7, - 0xd0, 0x71, 0xa1, 0xe6, 0x88, 0x00, 0xf6, 0x8a, 0xfa, 0x9f, 0x12, 0x4f, 0x67, 0x26, 0x70, 0xc4, - 0x06, 0x19, 0x16, 0x08, 0x31, 0x67, 0x7d, 0x70, 0x7c, 0x1b, 0x80, 0xbd, 0x5d, 0xeb, 0x76, 0x49, - 0xaf, 0x58, 0x1f, 0xe8, 0x4b, 0xf2, 0x7f, 0x05, 0x1d, 0x48, 0x8f, 0x21, 0x86, 0x63, 0xd0, 0x29, - 0x42, 0x77, 0xb3, 0x63, 0x66, 0x20, 0x06, 0x9e, 0x48, 0x91, 0x72, 0x74, 0x3a, 0x03, 0x17, 0xba, - 0xa7, 0x23, 0x5f, 0x8d, 0x05, 0xee, 0xb9, 0x38, 0xfa, 0x90, 0x94, 0xed, 0x86, 0xe0, 0x30, 0x4e, - 0x13, 0xef, 0xe6, 0xf8, 0x1e, 0xe1, 0xf0, 0x20, 0xa1, 0xcf, 0xc9, 0x4a, 0x9e, 0x76, 0x79, 0xca, - 0xbb, 0xf1, 0x3b, 0x18, 0xc6, 0x92, 0xa5, 0xca, 0xbb, 0x65, 0x74, 0x2e, 0x17, 0x3a, 0x5d, 0x03, - 0xa3, 0x9a, 0x0b, 0x2c, 0x1a, 0xfa, 0x9c, 0xac, 0x00, 0xf6, 0xd8, 0x00, 0x7b, 0xe7, 0xa9, 0xf3, - 0x97, 0xa4, 0xba, 0x40, 0xb7, 0x0e, 0xff, 0x5a, 0x20, 0x64, 0xc7, 0x84, 0x98, 0x3e, 0xff, 0x8f, - 0x54, 0x72, 0x14, 0x8a, 0x75, 0x21, 0x96, 0x0c, 0x7b, 0x6e, 0x8f, 0xca, 0xce, 0xd6, 0x66, 0xd8, - 0xa3, 0x77, 0xc9, 0xa2, 0x6c, 0xca, 0x58, 0x0a, 0x65, 0x37, 0xec, 0x56, 0xb4, 0x20, 0x9b, 0xb2, - 0x2d, 0x14, 0xd2, 0x47, 0x64, 0x59, 0xbb, 0xe0, 0x14, 0x41, 0x71, 0x96, 0xc5, 0xa9, 0x74, 0xed, - 0xa9, 0xca, 0xa6, 0xdc, 0x73, 0xd6, 0x03, 0x49, 0xbf, 0x25, 0xb7, 0x75, 0x5c, 0x47, 0x70, 0x0e, - 0x1d, 0xd3, 0x4e, 0x4c, 0xfb, 0x20, 0x06, 0x68, 0xda, 0x52, 0x6e, 0xde, 0xdd, 0xb6, 0xa7, 0x74, - 0xbb, 0x38, 0xa5, 0xdb, 0xbb, 0xee, 0x14, 0x47, 0xeb, 0xb2, 0x29, 0x77, 0xce, 0xf2, 0x5e, 0xdb, - 0x34, 0xdd, 0x5c, 0x7d, 0x59, 0x80, 0xb2, 0x65, 0xdd, 0x32, 0x65, 0x11, 0x6b, 0x32, 0x95, 0x7d, - 0x44, 0x6a, 0x2e, 0xa0, 0x18, 0xe6, 0x79, 0x5b, 0x98, 0xb5, 0xb6, 0xdc, 0x48, 0x3f, 0x24, 0x65, - 0x3e, 0xe8, 0xc7, 0x27, 0x42, 0xbd, 0x03, 0x95, 0x7b, 0x0b, 0x16, 0x87, 0x0f, 0xfa, 0x6f, 0xad, - 0x85, 0x6e, 0x91, 0x35, 0xeb, 0x8c, 0x4f, 0x58, 0x8a, 0xa6, 0xec, 0xb8, 0x9f, 0x7b, 0x8b, 0x26, - 0x70, 0xc5, 0xba, 0xde, 0xb2, 0x14, 0x75, 0x61, 0x2f, 0x73, 0x1a, 0x90, 0x8a, 0x1e, 0x3e, 0x2e, - 0x12, 0x88, 0x07, 0x2a, 0xf3, 0x96, 0xec, 0xae, 0x03, 0xf6, 0x5e, 0x89, 0x04, 0xde, 0xa8, 0x8c, - 0xfe, 0x48, 0x36, 0x75, 0x44, 0x47, 0x70, 0x84, 0x53, 0x8c, 0x15, 0xb0, 0xe4, 0x1c, 0x5a, 0x77, - 0x84, 0x5c, 0xd7, 0x91, 0xbb, 0x80, 0xbd, 0x1d, 0x9b, 0x1e, 0x01, 0x4b, 0x0a, 0x76, 0xdd, 0x96, - 0xc8, 0xce, 0x7e, 0x01, 0x3e, 0x81, 0x5b, 0xbe, 0x0e, 0x77, 0xe3, 0x1c, 0x77, 0x1c, 0x73, 0x9f, - 0x50, 0x8d, 0x99, 0x72, 0x04, 0x75, 0xcc, 0xb2, 0x58, 0x01, 0xaa, 0xa1, 0x57, 0xb9, 0x0e, 0x4d, - 0x0f, 0xe8, 0x81, 0xcb, 0x89, 0x74, 0x8a, 0x1e, 0x16, 0x0d, 0xd4, 0x67, 0xa7, 0x06, 0x23, 0x85, - 0xdc, 0xab, 0x06, 0xa5, 0x7a, 0x35, 0xaa, 0x02, 0xf6, 0x5e, 0xb2, 0xd3, 0xc8, 0x1a, 0x69, 0x48, - 0xb4, 0x21, 0xee, 0xb2, 0x3c, 0x96, 0x2a, 0xed, 0x80, 0x57, 0x0b, 0x4a, 0xf5, 0x9b, 0x91, 0xbe, - 0x0f, 0xf6, 0x59, 0xde, 0xd6, 0xa6, 0xf1, 0x98, 0x2c, 0xed, 0xa7, 0xe8, 0x2d, 0x8f, 0xc7, 0x7c, - 0xa3, 0x4d, 0x9a, 0x0f, 0x4f, 0x63, 0x29, 0x44, 0x16, 0x03, 0x67, 0x87, 0x19, 0x24, 0xde, 0x4a, - 0x50, 0xaa, 0x2f, 0x46, 0x55, 0x3c, 0x6d, 0x0b, 0x91, 0xed, 0x59, 0xa3, 0xbe, 0xf0, 0x38, 0xa0, - 0xde, 0x4a, 0x6f, 0xd5, 0x5e, 0x78, 0x6e, 0x49, 0x3f, 0x26, 0xcb, 0x87, 0x42, 0x60, 0x8e, 0x8a, - 0xc9, 0x58, 0x82, 0x9e, 0x10, 0x1a, 0xcc, 0xd5, 0x97, 0xa2, 0xda, 0x99, 0xb9, 0xad, 0xad, 0x74, - 0x93, 0x10, 0x97, 0xa3, 0x8f, 0xfa, 0x9a, 0x51, 0xb5, 0xe4, 0x2c, 0x07, 0x09, 0x7d, 0x4a, 0xaa, - 0x7d, 0x96, 0xf2, 0xb8, 0x38, 0xfc, 0xde, 0xfa, 0xa5, 0xd7, 0x72, 0x45, 0x07, 0x1e, 0xb8, 0xb8, - 0xe6, 0x9f, 0x8b, 0xa4, 0x6a, 0x0f, 0xeb, 0x77, 0xf6, 0x69, 0xa4, 0x8c, 0x2c, 0xed, 0x03, 0x5a, - 0x1b, 0xbd, 0x3d, 0xd5, 0xfe, 0x3d, 0xfd, 0xb8, 0xf9, 0x67, 0xc0, 0xe7, 0x07, 0x3d, 0xac, 0x8f, - 0x5a, 0xab, 0xfe, 0xf2, 0x3e, 0x60, 0xa0, 0x27, 0x31, 0xb0, 0x9e, 0xdf, 0xff, 0xfe, 0xe7, 0x8f, - 0x1b, 0x35, 0x5a, 0x69, 0xb8, 0x07, 0x58, 0xcf, 0x2d, 0x45, 0x43, 0x61, 0x6b, 0xa2, 0x5e, 0x01, - 0x75, 0xf1, 0xe5, 0xf3, 0x67, 0x54, 0x1f, 0x3e, 0x1f, 0xb5, 0xd6, 0xfc, 0x55, 0x4d, 0x62, 0x8d, - 0xe3, 0x34, 0x9b, 0xf4, 0x5e, 0x41, 0x83, 0xc6, 0xd9, 0xf8, 0xe5, 0xfc, 0xc1, 0x7a, 0x4f, 0xdf, - 0x93, 0xea, 0xf8, 0x43, 0x99, 0x5f, 0x2a, 0xee, 0xfe, 0x58, 0x45, 0x53, 0xef, 0x6a, 0xf8, 0xd9, - 0xa8, 0xe5, 0xf9, 0xb7, 0x75, 0x05, 0xad, 0x2c, 0x9b, 0xac, 0x22, 0x37, 0x65, 0x6c, 0xd0, 0xb5, - 0x0b, 0x65, 0x64, 0x69, 0x8e, 0x34, 0x23, 0x95, 0x1d, 0x05, 0x0c, 0xc1, 0xb5, 0x76, 0x46, 0x0b, - 0x67, 0xb6, 0xf5, 0xd3, 0x51, 0xcb, 0xf7, 0x3d, 0x9b, 0x9a, 0x07, 0xba, 0x7f, 0x81, 0x0d, 0x0a, - 0xf4, 0xfb, 0x6a, 0x18, 0x57, 0xc3, 0x89, 0xfe, 0x7e, 0x5e, 0x7a, 0x4c, 0x65, 0xc1, 0xe6, 0xba, - 0x3c, 0xa3, 0x97, 0x33, 0xfb, 0xfb, 0x6c, 0xd4, 0xba, 0xef, 0xfb, 0x05, 0x9b, 0xad, 0x7f, 0x8a, - 0x6f, 0x2d, 0xac, 0x4d, 0x2a, 0xd4, 0x8c, 0x5d, 0x52, 0xb1, 0xdf, 0x11, 0x1f, 0xa8, 0xaf, 0x31, - 0x6a, 0x6d, 0xf8, 0xee, 0x13, 0x64, 0x42, 0x9f, 0x95, 0xe6, 0x4f, 0x49, 0xfb, 0xad, 0x54, 0x30, - 0x39, 0x6d, 0xf7, 0x0a, 0xd4, 0x19, 0xdf, 0x31, 0x33, 0x45, 0x7e, 0x35, 0x6a, 0xdd, 0xf1, 0x37, - 0x0a, 0xca, 0x09, 0x91, 0x86, 0x34, 0xf0, 0xaf, 0x1a, 0x24, 0x5d, 0x43, 0x46, 0x2a, 0xbb, 0x90, - 0xc1, 0x99, 0xd8, 0xcb, 0x46, 0xe9, 0x12, 0x7b, 0xf8, 0xc4, 0x88, 0xb6, 0x10, 0xd3, 0xa2, 0x6b, - 0x8f, 0x27, 0xcf, 0xcb, 0xaf, 0x05, 0xdb, 0xb5, 0x47, 0xe6, 0x32, 0xbe, 0x2f, 0x8c, 0xe2, 0x82, - 0x6f, 0x5a, 0xf1, 0xe6, 0xe3, 0xab, 0x14, 0xbf, 0x78, 0x44, 0x48, 0x47, 0xf4, 0x1d, 0xeb, 0x8b, - 0x8a, 0xbb, 0x2a, 0xda, 0x9a, 0xa3, 0x5d, 0xfa, 0x61, 0xd1, 0xda, 0xe5, 0xe1, 0xe1, 0xbc, 0xa1, - 0xfd, 0xe4, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0x5c, 0x73, 0x03, 0x6f, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_c60469d31810ca8e) } + +var fileDescriptor_service_c60469d31810ca8e = []byte{ + // 1242 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xeb, 0x6e, 0x1b, 0x45, + 0x14, 0x96, 0x9b, 0x36, 0x97, 0xf1, 0x25, 0xce, 0x24, 0x69, 0xb7, 0xdb, 0xa6, 0x5d, 0x8c, 0x28, + 0x56, 0xd5, 0xc4, 0xc2, 0x20, 0xb5, 0x45, 0x02, 0xe1, 0x26, 0x51, 0x14, 0x41, 0x8b, 0xb5, 0xb4, + 0xaa, 0x00, 0xa1, 0xd5, 0xc4, 0x7b, 0x62, 0xaf, 0xba, 0x9e, 0x19, 0x66, 0x8f, 0x13, 0x5b, 0x08, + 0x21, 0x78, 0x04, 0xf3, 0x9f, 0x07, 0xe0, 0x75, 0x78, 0x05, 0x78, 0x0f, 0x34, 0x97, 0x4d, 0xec, + 0xd8, 0x49, 0xd4, 0x5f, 0xf6, 0x9c, 0xcb, 0xf7, 0x9d, 0xef, 0xcc, 0x99, 0x99, 0x25, 0x1b, 0x1d, + 0xc1, 0x8f, 0x93, 0x6e, 0x23, 0x03, 0x75, 0x92, 0x74, 0x60, 0x47, 0x2a, 0x81, 0x82, 0x2e, 0x5a, + 0xab, 0x7f, 0xbf, 0x2b, 0x44, 0x37, 0x85, 0x06, 0x93, 0x49, 0x83, 0x71, 0x2e, 0x90, 0x61, 0x22, + 0x78, 0x66, 0xa3, 0xfc, 0x07, 0xce, 0x6b, 0x56, 0x47, 0x83, 0xe3, 0x46, 0x3c, 0x50, 0x26, 0xc0, + 0xf9, 0xef, 0x5d, 0xf4, 0x43, 0x5f, 0xe2, 0xc8, 0x39, 0x9f, 0x98, 0x9f, 0xce, 0x76, 0x17, 0xf8, + 0x76, 0x76, 0xca, 0xba, 0x5d, 0x50, 0x0d, 0x21, 0x0d, 0xfc, 0x2c, 0x55, 0xad, 0x49, 0xaa, 0x07, + 0x80, 0xaf, 0x81, 0x33, 0x8e, 0x21, 0xfc, 0x3c, 0x80, 0x0c, 0xe9, 0x03, 0x42, 0x92, 0x18, 0x38, + 0x26, 0xc7, 0x09, 0x28, 0xaf, 0x10, 0x14, 0xea, 0x2b, 0xe1, 0x84, 0xa5, 0xf6, 0x25, 0xd9, 0x38, + 0x00, 0x6c, 0xa5, 0x69, 0x9e, 0x96, 0x49, 0xc1, 0x33, 0xa0, 0x8f, 0xc8, 0xcd, 0x98, 0x21, 0xf3, + 0x0a, 0xc1, 0x42, 0xbd, 0xd8, 0xa4, 0x3b, 0x56, 0xeb, 0x8e, 0x8d, 0xda, 0x63, 0xc8, 0x42, 0xe3, + 0xaf, 0xfd, 0x44, 0xd6, 0xdf, 0xc8, 0x98, 0x21, 0xbc, 0x17, 0xed, 0x19, 0xfc, 0x8d, 0xa0, 0x70, + 0x25, 0xfc, 0xf7, 0x64, 0x75, 0x1f, 0x7b, 0xa0, 0x60, 0xd0, 0x6f, 0x75, 0x3a, 0x62, 0xc0, 0x91, + 0x7a, 0x64, 0x89, 0xc5, 0xb1, 0x82, 0x2c, 0x73, 0xb8, 0xf9, 0x92, 0x56, 0xc9, 0xc2, 0x3b, 0x18, + 0x19, 0xcc, 0x95, 0x50, 0xff, 0xa5, 0x3e, 0x59, 0x96, 0x2c, 0xcb, 0x4e, 0x85, 0x8a, 0xbd, 0x05, + 0x63, 0x3e, 0x5b, 0xd7, 0xb6, 0xc9, 0xd2, 0xd7, 0x30, 0x6a, 0xb3, 0x44, 0xe9, 0x44, 0x39, 0x38, + 0x72, 0x70, 0xfa, 0xaf, 0xb1, 0x9c, 0x60, 0x0e, 0x25, 0x4f, 0xb0, 0xf6, 0xdf, 0x0d, 0x42, 0xce, + 0xcb, 0xa3, 0xcf, 0x48, 0x11, 0xb0, 0x17, 0x31, 0x5b, 0x94, 0x49, 0x2d, 0x36, 0xef, 0xe4, 0x3a, + 0x2e, 0xd4, 0x1c, 0x12, 0xc0, 0x5e, 0x5e, 0xff, 0x53, 0xe2, 0xe9, 0xcc, 0x18, 0x8e, 0xd9, 0x20, + 0xc5, 0x1c, 0x21, 0xe2, 0xac, 0x0f, 0x8e, 0x6f, 0x13, 0xb0, 0xb7, 0x67, 0xdd, 0x2e, 0xe9, 0x15, + 0xeb, 0x03, 0x7d, 0x49, 0x3e, 0x54, 0xd0, 0x81, 0xe4, 0x04, 0x22, 0x38, 0x01, 0x9d, 0x22, 0x74, + 0x37, 0x3b, 0x66, 0x06, 0x22, 0xe0, 0xb1, 0x14, 0x09, 0x47, 0xa7, 0x33, 0x70, 0xa1, 0xfb, 0x3a, + 0xf2, 0xd5, 0x44, 0xe0, 0xbe, 0x8b, 0xa3, 0x0f, 0x49, 0xd1, 0x6e, 0x08, 0x8e, 0xa2, 0x24, 0xf6, + 0x6e, 0x4e, 0xee, 0x11, 0x8e, 0x0e, 0x63, 0xfa, 0x9c, 0x54, 0xb3, 0xa4, 0xcb, 0x13, 0xde, 0x8d, + 0xde, 0xc1, 0x28, 0x92, 0x2c, 0x51, 0xde, 0x2d, 0xa3, 0x73, 0x35, 0xd7, 0xe9, 0x1a, 0x18, 0x56, + 0x5c, 0x60, 0xde, 0xd0, 0xe7, 0xa4, 0x0a, 0xd8, 0x63, 0x03, 0xec, 0x9d, 0xa7, 0x2e, 0x5e, 0x92, + 0xea, 0x02, 0xdd, 0xba, 0xf6, 0xf7, 0x12, 0x21, 0xbb, 0x26, 0xc4, 0xf4, 0xf9, 0x03, 0x52, 0xca, + 0x50, 0x28, 0xd6, 0x85, 0x48, 0x32, 0xec, 0xb9, 0x3d, 0x2a, 0x3a, 0x5b, 0x9b, 0x61, 0x8f, 0xde, + 0x25, 0xcb, 0xb2, 0x29, 0x23, 0x29, 0x94, 0xdd, 0xb0, 0x5b, 0xe1, 0x92, 0x6c, 0xca, 0xb6, 0x50, + 0x48, 0x1f, 0x91, 0x55, 0xed, 0x82, 0x21, 0x82, 0xe2, 0x2c, 0x8d, 0x12, 0xe9, 0xda, 0x53, 0x96, + 0x4d, 0xb9, 0xef, 0xac, 0x87, 0x92, 0x7e, 0x4b, 0x6e, 0xeb, 0xb8, 0x8e, 0xe0, 0x1c, 0x3a, 0xa6, + 0x9d, 0x98, 0xf4, 0x41, 0x0c, 0xd0, 0xb4, 0xa5, 0xd8, 0xbc, 0xbb, 0x63, 0x4f, 0xe9, 0x4e, 0x7e, + 0x4a, 0x77, 0xf6, 0xdc, 0x29, 0x0e, 0x37, 0x64, 0x53, 0xee, 0x9e, 0xe5, 0xbd, 0xb6, 0x69, 0xba, + 0xb9, 0xfa, 0xb2, 0x00, 0x65, 0xcb, 0xba, 0x65, 0xca, 0x22, 0xd6, 0x64, 0x2a, 0xfb, 0x88, 0x54, + 0x5c, 0x40, 0x3e, 0xcc, 0x8b, 0xb6, 0x30, 0x6b, 0x6d, 0xb9, 0x91, 0x7e, 0x48, 0x8a, 0x7c, 0xd0, + 0x8f, 0x4e, 0x85, 0x7a, 0x07, 0x2a, 0xf3, 0x96, 0x2c, 0x0e, 0x1f, 0xf4, 0xdf, 0x5a, 0x0b, 0xdd, + 0x26, 0xeb, 0xd6, 0x19, 0x9d, 0xb2, 0x04, 0x4d, 0xd9, 0x51, 0x3f, 0xf3, 0x96, 0x4d, 0x60, 0xd5, + 0xba, 0xde, 0xb2, 0x04, 0x75, 0x61, 0x2f, 0x33, 0x1a, 0x90, 0x92, 0x1e, 0x3e, 0x2e, 0x62, 0x88, + 0x06, 0x2a, 0xf5, 0x56, 0xec, 0xae, 0x03, 0xf6, 0x5e, 0x89, 0x18, 0xde, 0xa8, 0x94, 0xfe, 0x48, + 0xb6, 0x74, 0x44, 0x47, 0x70, 0x84, 0x21, 0x46, 0x0a, 0x58, 0x7c, 0x0e, 0xad, 0x3b, 0x42, 0xae, + 0xeb, 0xc8, 0x5d, 0xc0, 0xde, 0xae, 0x4d, 0x0f, 0x81, 0xc5, 0x39, 0xbb, 0x6e, 0x4b, 0x68, 0x67, + 0x3f, 0x07, 0x9f, 0xc2, 0x2d, 0x5e, 0x87, 0xbb, 0x79, 0x8e, 0x3b, 0x89, 0x79, 0x40, 0xa8, 0xc6, + 0x4c, 0x38, 0x82, 0x3a, 0x61, 0x69, 0xa4, 0x00, 0xd5, 0xc8, 0x2b, 0x5d, 0x87, 0xa6, 0x07, 0xf4, + 0xd0, 0xe5, 0x84, 0x3a, 0x45, 0x0f, 0x8b, 0x06, 0xea, 0xb3, 0xa1, 0xc1, 0x48, 0x20, 0xf3, 0xca, + 0x41, 0xa1, 0x5e, 0x0e, 0xcb, 0x80, 0xbd, 0x97, 0x6c, 0x18, 0x5a, 0x23, 0xad, 0x11, 0x6d, 0x88, + 0xba, 0x2c, 0x8b, 0xa4, 0x4a, 0x3a, 0xe0, 0x55, 0x82, 0x42, 0xfd, 0x66, 0xa8, 0xef, 0x83, 0x03, + 0x96, 0xb5, 0xb5, 0x69, 0x32, 0x26, 0x4d, 0xfa, 0x09, 0x7a, 0xab, 0x93, 0x31, 0xdf, 0x68, 0x93, + 0xe6, 0xc3, 0x61, 0x24, 0x85, 0x48, 0x23, 0xe0, 0xec, 0x28, 0x85, 0xd8, 0xab, 0x06, 0x85, 0xfa, + 0x72, 0x58, 0xc6, 0x61, 0x5b, 0x88, 0x74, 0xdf, 0x1a, 0xf5, 0x85, 0xc7, 0x01, 0xf5, 0x56, 0x7a, + 0x6b, 0xf6, 0xc2, 0x73, 0x4b, 0xfa, 0x31, 0x59, 0x3d, 0x12, 0x02, 0x33, 0x54, 0x4c, 0x46, 0x12, + 0xf4, 0x84, 0xd0, 0x60, 0xa1, 0xbe, 0x12, 0x56, 0xce, 0xcc, 0x6d, 0x6d, 0xa5, 0x5b, 0x84, 0xb8, + 0x1c, 0x7d, 0xd4, 0xd7, 0x8d, 0xaa, 0x15, 0x67, 0x39, 0x8c, 0xe9, 0x53, 0x52, 0xee, 0xb3, 0x84, + 0x47, 0xf9, 0xe1, 0xf7, 0x36, 0x2e, 0xbd, 0x96, 0x4b, 0x3a, 0xf0, 0xd0, 0xc5, 0x35, 0xff, 0x5a, + 0x26, 0x65, 0x7b, 0x58, 0xbf, 0xb3, 0x4f, 0x23, 0x65, 0x64, 0xe5, 0x00, 0xd0, 0xda, 0xe8, 0xed, + 0x99, 0xf6, 0xef, 0xeb, 0xc7, 0xcd, 0x3f, 0x03, 0x3e, 0x3f, 0xe8, 0xb5, 0xfa, 0xb8, 0xb5, 0xe6, + 0xaf, 0x1e, 0x00, 0x06, 0x7a, 0x12, 0x03, 0xeb, 0xf9, 0xe3, 0x9f, 0x7f, 0xff, 0xbc, 0x51, 0xa1, + 0xa5, 0x86, 0x7b, 0x80, 0xf5, 0xdc, 0x52, 0x34, 0x14, 0xb6, 0x26, 0xea, 0xe5, 0x50, 0x17, 0x5f, + 0x3e, 0x7f, 0x4e, 0xf5, 0xb5, 0xe7, 0xe3, 0xd6, 0xba, 0xbf, 0xa6, 0x49, 0xac, 0x71, 0x92, 0x66, + 0x8b, 0xde, 0xcb, 0x69, 0xd0, 0x38, 0x1b, 0xbf, 0x9c, 0x3f, 0x58, 0xbf, 0xd2, 0x21, 0x29, 0x4f, + 0x3e, 0x94, 0xd9, 0xa5, 0xe2, 0xee, 0x4f, 0x54, 0x34, 0xf3, 0xae, 0xd6, 0x3e, 0x19, 0xb7, 0x3c, + 0xff, 0xb6, 0xae, 0xa0, 0x95, 0xa6, 0xd3, 0x55, 0x64, 0xa6, 0x8c, 0x2a, 0xad, 0x4c, 0x97, 0x41, + 0x53, 0x52, 0xda, 0x55, 0xc0, 0x10, 0x5c, 0x57, 0xe7, 0x74, 0x6f, 0x6e, 0x47, 0x3f, 0x1b, 0xb7, + 0x7c, 0xdf, 0xb3, 0xa9, 0x59, 0xa0, 0x5b, 0x17, 0xd8, 0xa0, 0x40, 0x3f, 0xad, 0x86, 0x6c, 0xad, + 0x36, 0xd5, 0xda, 0xcf, 0x0b, 0x8f, 0xa9, 0xcc, 0xd9, 0x5c, 0x83, 0xe7, 0xb4, 0x71, 0x6e, 0x6b, + 0x9f, 0x8d, 0x5b, 0xf7, 0x7d, 0x3f, 0x67, 0xb3, 0xa5, 0xcf, 0xf0, 0xad, 0xd7, 0x2e, 0x88, 0xd3, + 0x8c, 0x5d, 0x52, 0xb2, 0x9f, 0x10, 0xef, 0xa9, 0xaf, 0x31, 0x6e, 0x6d, 0xfa, 0xee, 0xeb, 0x63, + 0x4a, 0x9f, 0x95, 0xe6, 0xcf, 0x48, 0xfb, 0xbd, 0x90, 0x33, 0x39, 0x6d, 0xf7, 0x72, 0xd4, 0x39, + 0x9f, 0x30, 0x73, 0x45, 0x7e, 0x35, 0x6e, 0xdd, 0xf1, 0x37, 0x73, 0xca, 0x29, 0x91, 0x86, 0x34, + 0xf0, 0xaf, 0x9a, 0x21, 0x5d, 0x43, 0x4a, 0x4a, 0x7b, 0x90, 0xc2, 0x99, 0xd8, 0xcb, 0xa6, 0xe8, + 0x12, 0x7b, 0xed, 0x89, 0x11, 0x6d, 0x21, 0x66, 0x45, 0x57, 0x1e, 0x4f, 0x1f, 0x95, 0xdf, 0x72, + 0xb6, 0x6b, 0x4f, 0xcb, 0x65, 0x7c, 0x5f, 0x18, 0xc5, 0x39, 0xdf, 0xac, 0xe2, 0xad, 0xc7, 0x57, + 0x29, 0x7e, 0xf1, 0x88, 0x90, 0x8e, 0xe8, 0x3b, 0xd6, 0x17, 0x25, 0x77, 0x4b, 0xb4, 0x35, 0x47, + 0xbb, 0xf0, 0xc3, 0xb2, 0xb5, 0xcb, 0xa3, 0xa3, 0x45, 0x43, 0xfb, 0xe9, 0xff, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xaa, 0x2a, 0x45, 0x3e, 0x6a, 0x0b, 0x00, 0x00, } diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go index cddd80be6..82aef331d 100644 --- a/protobufs/gen/go/config/service.pb.gw.go +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -487,7 +487,7 @@ var ( pattern_ConfigService_GetTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) - pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"config", "tenant", "list"}, "")) + pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenant"}, "")) pattern_ConfigService_CreateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 78575a2a5..7e15ed97d 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/list":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 20e800380..5acfe8351 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -98,6 +98,21 @@ } }, "/config/tenant": { + "get": { + "description": "Get All Tenant Configs", + "operationId": "GetAllTenants", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configGetAllTenantResponse" + } + } + }, + "tags": [ + "ConfigService" + ] + }, "post": { "description": "Creates tenant config data", "operationId": "CreateTenant", @@ -124,23 +139,6 @@ ] } }, - "/config/tenant/list": { - "get": { - "description": "Get All Tenant Configs", - "operationId": "GetAllTenants", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configGetAllTenantResponse" - } - } - }, - "tags": [ - "ConfigService" - ] - } - }, "/config/tenant/{identifier}": { "get": { "description": "Get Tenant Config", diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index db7efd984..3683ecbfd 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -4,6 +4,7 @@ package storage import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" "github.com/syndtr/goleveldb/leveldb" ) @@ -12,7 +13,7 @@ var db *leveldb.DB var configdb *leveldb.DB func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { - cfg := context[bootstrap.BootstrappedConfig].(Config) + cfg := context[bootstrap.BootstrappedConfig].(config.Configuration) crs := GetRandomTestStoragePath() cfg.SetDefault("configStorage.path", crs) diff --git a/testworld/config_test.go b/testworld/config_test.go new file mode 100644 index 000000000..e3046b7cb --- /dev/null +++ b/testworld/config_test.go @@ -0,0 +1,29 @@ +// +build testworld + +package testworld + +import ( + "net/http" + "testing" +) + +func TestConfig_Happy(t *testing.T) { + t.Parallel() + charlie := doctorFord.getHostTestSuite(t, "Charlie") + + // check charlies node config + res := getNodeConfig(charlie.httpExpect, http.StatusOK) + tenantID := res.Value("main_identity").Path("$.identity_id").String().NotEmpty() + tenantID.Equal(charlie.id.String()) + + // check charlies main tenant config + res = getTenantConfig(charlie.httpExpect, http.StatusOK, charlie.id.String()) + tenantID2 := res.Value("identity_id").String().NotEmpty() + tenantID2.Equal(charlie.id.String()) + + // check charlies all tenant configs + res = getAllTenantConfigs(charlie.httpExpect, http.StatusOK) + tenants := res.Value("data").Array() + tenants.Length().Equal(1) + tenants.Element(0).Path("$.identity_id").String().NotEmpty().Equal(charlie.id.String()) +} diff --git a/testworld/httputils.go b/testworld/httputils.go index d6a17acdf..225fa01f6 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -83,6 +83,32 @@ func getProof(e *httpexpect.Expect, httpStatus int, documentID string, payload m return resp.JSON().Object() } +func getNodeConfig(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { + resp := e.GET("/config/node"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + Expect().Status(httpStatus) + return resp.JSON().Object() +} + +func getTenantConfig(e *httpexpect.Expect, httpStatus int, identifier string) *httpexpect.Object { + resp := e.GET("/config/tenant/"+identifier). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + Expect().Status(httpStatus) + return resp.JSON().Object() +} + +func getAllTenantConfigs(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { + resp := e.GET("/config/tenant"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + Expect().Status(httpStatus) + return resp.JSON().Object() +} + +// TODO add rest of the endpoints for config + func createInsecureClient() *http.Client { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, From fb1db871505c7364e8e6d813089529b1a0f438ff Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 2 Jan 2019 14:24:07 +0100 Subject: [PATCH 107/220] REST fix /config/tenant => /config/tenants (#605) * REST fix /config/tenant => /config/tenants * REST fix /config/tenant => /config/tenants --- protobufs/config/service.proto | 10 +- protobufs/gen/go/config/service.pb.go | 178 +++++++++--------- protobufs/gen/go/config/service.pb.gw.go | 10 +- protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 4 +- testworld/httputils.go | 4 +- 6 files changed, 104 insertions(+), 104 deletions(-) diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index f30e632f9..5d7605499 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -24,7 +24,7 @@ service ConfigService { } rpc GetTenant(GetTenantRequest) returns (TenantData) { option (google.api.http) = { - get: "/config/tenant/{identifier}" + get: "/config/tenants/{identifier}" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Get Tenant Config" @@ -32,7 +32,7 @@ service ConfigService { } rpc GetAllTenants(google.protobuf.Empty) returns (GetAllTenantResponse) { option (google.api.http) = { - get: "/config/tenant" + get: "/config/tenants" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Get All Tenant Configs" @@ -49,7 +49,7 @@ service ConfigService { } rpc CreateTenant(TenantData) returns (TenantData) { option (google.api.http) = { - post: "/config/tenant" + post: "/config/tenants" body: "*" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { @@ -67,7 +67,7 @@ service ConfigService { } rpc UpdateTenant(UpdateTenantRequest) returns (TenantData) { option (google.api.http) = { - put: "/config/tenant/{identifier}" + put: "/config/tenants/{identifier}" body: "*" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { @@ -84,7 +84,7 @@ service ConfigService { } rpc DeleteTenant(GetTenantRequest) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/config/tenant/{identifier}" + delete: "/config/tenants/{identifier}" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Deletes tenant config" diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 3f54e730c..7149b7b6d 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -38,7 +38,7 @@ func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } func (*GetTenantRequest) ProtoMessage() {} func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{0} + return fileDescriptor_service_48f740854e8728dc, []int{0} } func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } func (*GetAllTenantResponse) ProtoMessage() {} func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{1} + return fileDescriptor_service_48f740854e8728dc, []int{1} } func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) @@ -115,7 +115,7 @@ func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } func (*UpdateTenantRequest) ProtoMessage() {} func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{2} + return fileDescriptor_service_48f740854e8728dc, []int{2} } func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) @@ -162,7 +162,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{3} + return fileDescriptor_service_48f740854e8728dc, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -215,7 +215,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{4} + return fileDescriptor_service_48f740854e8728dc, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -265,7 +265,7 @@ func (m *TenantData) Reset() { *m = TenantData{} } func (m *TenantData) String() string { return proto.CompactTextString(m) } func (*TenantData) ProtoMessage() {} func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{5} + return fileDescriptor_service_48f740854e8728dc, []int{5} } func (m *TenantData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TenantData.Unmarshal(m, b) @@ -357,7 +357,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_c60469d31810ca8e, []int{6} + return fileDescriptor_service_48f740854e8728dc, []int{6} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -863,86 +863,86 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_c60469d31810ca8e) } - -var fileDescriptor_service_c60469d31810ca8e = []byte{ - // 1242 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xeb, 0x6e, 0x1b, 0x45, - 0x14, 0x96, 0x9b, 0x36, 0x97, 0xf1, 0x25, 0xce, 0x24, 0x69, 0xb7, 0xdb, 0xa6, 0x5d, 0x8c, 0x28, - 0x56, 0xd5, 0xc4, 0xc2, 0x20, 0xb5, 0x45, 0x02, 0xe1, 0x26, 0x51, 0x14, 0x41, 0x8b, 0xb5, 0xb4, - 0xaa, 0x00, 0xa1, 0xd5, 0xc4, 0x7b, 0x62, 0xaf, 0xba, 0x9e, 0x19, 0x66, 0x8f, 0x13, 0x5b, 0x08, - 0x21, 0x78, 0x04, 0xf3, 0x9f, 0x07, 0xe0, 0x75, 0x78, 0x05, 0x78, 0x0f, 0x34, 0x97, 0x4d, 0xec, - 0xd8, 0x49, 0xd4, 0x5f, 0xf6, 0x9c, 0xcb, 0xf7, 0x9d, 0xef, 0xcc, 0x99, 0x99, 0x25, 0x1b, 0x1d, - 0xc1, 0x8f, 0x93, 0x6e, 0x23, 0x03, 0x75, 0x92, 0x74, 0x60, 0x47, 0x2a, 0x81, 0x82, 0x2e, 0x5a, - 0xab, 0x7f, 0xbf, 0x2b, 0x44, 0x37, 0x85, 0x06, 0x93, 0x49, 0x83, 0x71, 0x2e, 0x90, 0x61, 0x22, - 0x78, 0x66, 0xa3, 0xfc, 0x07, 0xce, 0x6b, 0x56, 0x47, 0x83, 0xe3, 0x46, 0x3c, 0x50, 0x26, 0xc0, - 0xf9, 0xef, 0x5d, 0xf4, 0x43, 0x5f, 0xe2, 0xc8, 0x39, 0x9f, 0x98, 0x9f, 0xce, 0x76, 0x17, 0xf8, - 0x76, 0x76, 0xca, 0xba, 0x5d, 0x50, 0x0d, 0x21, 0x0d, 0xfc, 0x2c, 0x55, 0xad, 0x49, 0xaa, 0x07, - 0x80, 0xaf, 0x81, 0x33, 0x8e, 0x21, 0xfc, 0x3c, 0x80, 0x0c, 0xe9, 0x03, 0x42, 0x92, 0x18, 0x38, - 0x26, 0xc7, 0x09, 0x28, 0xaf, 0x10, 0x14, 0xea, 0x2b, 0xe1, 0x84, 0xa5, 0xf6, 0x25, 0xd9, 0x38, - 0x00, 0x6c, 0xa5, 0x69, 0x9e, 0x96, 0x49, 0xc1, 0x33, 0xa0, 0x8f, 0xc8, 0xcd, 0x98, 0x21, 0xf3, - 0x0a, 0xc1, 0x42, 0xbd, 0xd8, 0xa4, 0x3b, 0x56, 0xeb, 0x8e, 0x8d, 0xda, 0x63, 0xc8, 0x42, 0xe3, - 0xaf, 0xfd, 0x44, 0xd6, 0xdf, 0xc8, 0x98, 0x21, 0xbc, 0x17, 0xed, 0x19, 0xfc, 0x8d, 0xa0, 0x70, - 0x25, 0xfc, 0xf7, 0x64, 0x75, 0x1f, 0x7b, 0xa0, 0x60, 0xd0, 0x6f, 0x75, 0x3a, 0x62, 0xc0, 0x91, - 0x7a, 0x64, 0x89, 0xc5, 0xb1, 0x82, 0x2c, 0x73, 0xb8, 0xf9, 0x92, 0x56, 0xc9, 0xc2, 0x3b, 0x18, - 0x19, 0xcc, 0x95, 0x50, 0xff, 0xa5, 0x3e, 0x59, 0x96, 0x2c, 0xcb, 0x4e, 0x85, 0x8a, 0xbd, 0x05, - 0x63, 0x3e, 0x5b, 0xd7, 0xb6, 0xc9, 0xd2, 0xd7, 0x30, 0x6a, 0xb3, 0x44, 0xe9, 0x44, 0x39, 0x38, - 0x72, 0x70, 0xfa, 0xaf, 0xb1, 0x9c, 0x60, 0x0e, 0x25, 0x4f, 0xb0, 0xf6, 0xdf, 0x0d, 0x42, 0xce, - 0xcb, 0xa3, 0xcf, 0x48, 0x11, 0xb0, 0x17, 0x31, 0x5b, 0x94, 0x49, 0x2d, 0x36, 0xef, 0xe4, 0x3a, - 0x2e, 0xd4, 0x1c, 0x12, 0xc0, 0x5e, 0x5e, 0xff, 0x53, 0xe2, 0xe9, 0xcc, 0x18, 0x8e, 0xd9, 0x20, - 0xc5, 0x1c, 0x21, 0xe2, 0xac, 0x0f, 0x8e, 0x6f, 0x13, 0xb0, 0xb7, 0x67, 0xdd, 0x2e, 0xe9, 0x15, - 0xeb, 0x03, 0x7d, 0x49, 0x3e, 0x54, 0xd0, 0x81, 0xe4, 0x04, 0x22, 0x38, 0x01, 0x9d, 0x22, 0x74, - 0x37, 0x3b, 0x66, 0x06, 0x22, 0xe0, 0xb1, 0x14, 0x09, 0x47, 0xa7, 0x33, 0x70, 0xa1, 0xfb, 0x3a, - 0xf2, 0xd5, 0x44, 0xe0, 0xbe, 0x8b, 0xa3, 0x0f, 0x49, 0xd1, 0x6e, 0x08, 0x8e, 0xa2, 0x24, 0xf6, - 0x6e, 0x4e, 0xee, 0x11, 0x8e, 0x0e, 0x63, 0xfa, 0x9c, 0x54, 0xb3, 0xa4, 0xcb, 0x13, 0xde, 0x8d, - 0xde, 0xc1, 0x28, 0x92, 0x2c, 0x51, 0xde, 0x2d, 0xa3, 0x73, 0x35, 0xd7, 0xe9, 0x1a, 0x18, 0x56, - 0x5c, 0x60, 0xde, 0xd0, 0xe7, 0xa4, 0x0a, 0xd8, 0x63, 0x03, 0xec, 0x9d, 0xa7, 0x2e, 0x5e, 0x92, - 0xea, 0x02, 0xdd, 0xba, 0xf6, 0xf7, 0x12, 0x21, 0xbb, 0x26, 0xc4, 0xf4, 0xf9, 0x03, 0x52, 0xca, - 0x50, 0x28, 0xd6, 0x85, 0x48, 0x32, 0xec, 0xb9, 0x3d, 0x2a, 0x3a, 0x5b, 0x9b, 0x61, 0x8f, 0xde, - 0x25, 0xcb, 0xb2, 0x29, 0x23, 0x29, 0x94, 0xdd, 0xb0, 0x5b, 0xe1, 0x92, 0x6c, 0xca, 0xb6, 0x50, - 0x48, 0x1f, 0x91, 0x55, 0xed, 0x82, 0x21, 0x82, 0xe2, 0x2c, 0x8d, 0x12, 0xe9, 0xda, 0x53, 0x96, - 0x4d, 0xb9, 0xef, 0xac, 0x87, 0x92, 0x7e, 0x4b, 0x6e, 0xeb, 0xb8, 0x8e, 0xe0, 0x1c, 0x3a, 0xa6, - 0x9d, 0x98, 0xf4, 0x41, 0x0c, 0xd0, 0xb4, 0xa5, 0xd8, 0xbc, 0xbb, 0x63, 0x4f, 0xe9, 0x4e, 0x7e, - 0x4a, 0x77, 0xf6, 0xdc, 0x29, 0x0e, 0x37, 0x64, 0x53, 0xee, 0x9e, 0xe5, 0xbd, 0xb6, 0x69, 0xba, - 0xb9, 0xfa, 0xb2, 0x00, 0x65, 0xcb, 0xba, 0x65, 0xca, 0x22, 0xd6, 0x64, 0x2a, 0xfb, 0x88, 0x54, - 0x5c, 0x40, 0x3e, 0xcc, 0x8b, 0xb6, 0x30, 0x6b, 0x6d, 0xb9, 0x91, 0x7e, 0x48, 0x8a, 0x7c, 0xd0, - 0x8f, 0x4e, 0x85, 0x7a, 0x07, 0x2a, 0xf3, 0x96, 0x2c, 0x0e, 0x1f, 0xf4, 0xdf, 0x5a, 0x0b, 0xdd, - 0x26, 0xeb, 0xd6, 0x19, 0x9d, 0xb2, 0x04, 0x4d, 0xd9, 0x51, 0x3f, 0xf3, 0x96, 0x4d, 0x60, 0xd5, - 0xba, 0xde, 0xb2, 0x04, 0x75, 0x61, 0x2f, 0x33, 0x1a, 0x90, 0x92, 0x1e, 0x3e, 0x2e, 0x62, 0x88, - 0x06, 0x2a, 0xf5, 0x56, 0xec, 0xae, 0x03, 0xf6, 0x5e, 0x89, 0x18, 0xde, 0xa8, 0x94, 0xfe, 0x48, - 0xb6, 0x74, 0x44, 0x47, 0x70, 0x84, 0x21, 0x46, 0x0a, 0x58, 0x7c, 0x0e, 0xad, 0x3b, 0x42, 0xae, - 0xeb, 0xc8, 0x5d, 0xc0, 0xde, 0xae, 0x4d, 0x0f, 0x81, 0xc5, 0x39, 0xbb, 0x6e, 0x4b, 0x68, 0x67, - 0x3f, 0x07, 0x9f, 0xc2, 0x2d, 0x5e, 0x87, 0xbb, 0x79, 0x8e, 0x3b, 0x89, 0x79, 0x40, 0xa8, 0xc6, - 0x4c, 0x38, 0x82, 0x3a, 0x61, 0x69, 0xa4, 0x00, 0xd5, 0xc8, 0x2b, 0x5d, 0x87, 0xa6, 0x07, 0xf4, - 0xd0, 0xe5, 0x84, 0x3a, 0x45, 0x0f, 0x8b, 0x06, 0xea, 0xb3, 0xa1, 0xc1, 0x48, 0x20, 0xf3, 0xca, - 0x41, 0xa1, 0x5e, 0x0e, 0xcb, 0x80, 0xbd, 0x97, 0x6c, 0x18, 0x5a, 0x23, 0xad, 0x11, 0x6d, 0x88, - 0xba, 0x2c, 0x8b, 0xa4, 0x4a, 0x3a, 0xe0, 0x55, 0x82, 0x42, 0xfd, 0x66, 0xa8, 0xef, 0x83, 0x03, - 0x96, 0xb5, 0xb5, 0x69, 0x32, 0x26, 0x4d, 0xfa, 0x09, 0x7a, 0xab, 0x93, 0x31, 0xdf, 0x68, 0x93, - 0xe6, 0xc3, 0x61, 0x24, 0x85, 0x48, 0x23, 0xe0, 0xec, 0x28, 0x85, 0xd8, 0xab, 0x06, 0x85, 0xfa, - 0x72, 0x58, 0xc6, 0x61, 0x5b, 0x88, 0x74, 0xdf, 0x1a, 0xf5, 0x85, 0xc7, 0x01, 0xf5, 0x56, 0x7a, - 0x6b, 0xf6, 0xc2, 0x73, 0x4b, 0xfa, 0x31, 0x59, 0x3d, 0x12, 0x02, 0x33, 0x54, 0x4c, 0x46, 0x12, - 0xf4, 0x84, 0xd0, 0x60, 0xa1, 0xbe, 0x12, 0x56, 0xce, 0xcc, 0x6d, 0x6d, 0xa5, 0x5b, 0x84, 0xb8, - 0x1c, 0x7d, 0xd4, 0xd7, 0x8d, 0xaa, 0x15, 0x67, 0x39, 0x8c, 0xe9, 0x53, 0x52, 0xee, 0xb3, 0x84, - 0x47, 0xf9, 0xe1, 0xf7, 0x36, 0x2e, 0xbd, 0x96, 0x4b, 0x3a, 0xf0, 0xd0, 0xc5, 0x35, 0xff, 0x5a, - 0x26, 0x65, 0x7b, 0x58, 0xbf, 0xb3, 0x4f, 0x23, 0x65, 0x64, 0xe5, 0x00, 0xd0, 0xda, 0xe8, 0xed, - 0x99, 0xf6, 0xef, 0xeb, 0xc7, 0xcd, 0x3f, 0x03, 0x3e, 0x3f, 0xe8, 0xb5, 0xfa, 0xb8, 0xb5, 0xe6, - 0xaf, 0x1e, 0x00, 0x06, 0x7a, 0x12, 0x03, 0xeb, 0xf9, 0xe3, 0x9f, 0x7f, 0xff, 0xbc, 0x51, 0xa1, - 0xa5, 0x86, 0x7b, 0x80, 0xf5, 0xdc, 0x52, 0x34, 0x14, 0xb6, 0x26, 0xea, 0xe5, 0x50, 0x17, 0x5f, - 0x3e, 0x7f, 0x4e, 0xf5, 0xb5, 0xe7, 0xe3, 0xd6, 0xba, 0xbf, 0xa6, 0x49, 0xac, 0x71, 0x92, 0x66, - 0x8b, 0xde, 0xcb, 0x69, 0xd0, 0x38, 0x1b, 0xbf, 0x9c, 0x3f, 0x58, 0xbf, 0xd2, 0x21, 0x29, 0x4f, - 0x3e, 0x94, 0xd9, 0xa5, 0xe2, 0xee, 0x4f, 0x54, 0x34, 0xf3, 0xae, 0xd6, 0x3e, 0x19, 0xb7, 0x3c, - 0xff, 0xb6, 0xae, 0xa0, 0x95, 0xa6, 0xd3, 0x55, 0x64, 0xa6, 0x8c, 0x2a, 0xad, 0x4c, 0x97, 0x41, - 0x53, 0x52, 0xda, 0x55, 0xc0, 0x10, 0x5c, 0x57, 0xe7, 0x74, 0x6f, 0x6e, 0x47, 0x3f, 0x1b, 0xb7, - 0x7c, 0xdf, 0xb3, 0xa9, 0x59, 0xa0, 0x5b, 0x17, 0xd8, 0xa0, 0x40, 0x3f, 0xad, 0x86, 0x6c, 0xad, - 0x36, 0xd5, 0xda, 0xcf, 0x0b, 0x8f, 0xa9, 0xcc, 0xd9, 0x5c, 0x83, 0xe7, 0xb4, 0x71, 0x6e, 0x6b, - 0x9f, 0x8d, 0x5b, 0xf7, 0x7d, 0x3f, 0x67, 0xb3, 0xa5, 0xcf, 0xf0, 0xad, 0xd7, 0x2e, 0x88, 0xd3, - 0x8c, 0x5d, 0x52, 0xb2, 0x9f, 0x10, 0xef, 0xa9, 0xaf, 0x31, 0x6e, 0x6d, 0xfa, 0xee, 0xeb, 0x63, - 0x4a, 0x9f, 0x95, 0xe6, 0xcf, 0x48, 0xfb, 0xbd, 0x90, 0x33, 0x39, 0x6d, 0xf7, 0x72, 0xd4, 0x39, - 0x9f, 0x30, 0x73, 0x45, 0x7e, 0x35, 0x6e, 0xdd, 0xf1, 0x37, 0x73, 0xca, 0x29, 0x91, 0x86, 0x34, - 0xf0, 0xaf, 0x9a, 0x21, 0x5d, 0x43, 0x4a, 0x4a, 0x7b, 0x90, 0xc2, 0x99, 0xd8, 0xcb, 0xa6, 0xe8, - 0x12, 0x7b, 0xed, 0x89, 0x11, 0x6d, 0x21, 0x66, 0x45, 0x57, 0x1e, 0x4f, 0x1f, 0x95, 0xdf, 0x72, - 0xb6, 0x6b, 0x4f, 0xcb, 0x65, 0x7c, 0x5f, 0x18, 0xc5, 0x39, 0xdf, 0xac, 0xe2, 0xad, 0xc7, 0x57, - 0x29, 0x7e, 0xf1, 0x88, 0x90, 0x8e, 0xe8, 0x3b, 0xd6, 0x17, 0x25, 0x77, 0x4b, 0xb4, 0x35, 0x47, - 0xbb, 0xf0, 0xc3, 0xb2, 0xb5, 0xcb, 0xa3, 0xa3, 0x45, 0x43, 0xfb, 0xe9, 0xff, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xaa, 0x2a, 0x45, 0x3e, 0x6a, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_48f740854e8728dc) } + +var fileDescriptor_service_48f740854e8728dc = []byte{ + // 1243 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xeb, 0x6e, 0x13, 0x47, + 0x14, 0x96, 0x09, 0xe4, 0x32, 0xb6, 0x73, 0x99, 0x24, 0xb0, 0x2c, 0x21, 0x2c, 0x5b, 0x95, 0x5a, + 0x88, 0xc4, 0x92, 0x5b, 0x89, 0xc2, 0x0f, 0x24, 0x93, 0x44, 0x51, 0xd4, 0x42, 0xad, 0x2d, 0x08, + 0xb5, 0x55, 0xb5, 0x9a, 0x78, 0x4f, 0xec, 0x15, 0xeb, 0x99, 0x61, 0xf6, 0x6c, 0x12, 0xab, 0xaa, + 0x54, 0xf1, 0x08, 0xee, 0x2b, 0xf4, 0x57, 0x5f, 0xa7, 0xaf, 0xd0, 0xbe, 0x47, 0x35, 0x97, 0x4d, + 0x9c, 0xd8, 0x21, 0xe2, 0x97, 0x3d, 0xe7, 0xf2, 0x7d, 0xe7, 0x3b, 0x73, 0x66, 0x66, 0xc9, 0x5a, + 0x57, 0xf0, 0xa3, 0xb4, 0xd7, 0xcc, 0x41, 0x1d, 0xa7, 0x5d, 0xd8, 0x96, 0x4a, 0xa0, 0xa0, 0xb3, + 0xd6, 0xea, 0x6f, 0xf4, 0x84, 0xe8, 0x65, 0xd0, 0x64, 0x32, 0x6d, 0x32, 0xce, 0x05, 0x32, 0x4c, + 0x05, 0xcf, 0x6d, 0x94, 0xbf, 0xe9, 0xbc, 0x66, 0x75, 0x58, 0x1c, 0x35, 0x93, 0x42, 0x99, 0x00, + 0xe7, 0xbf, 0x77, 0xd9, 0x0f, 0x03, 0x89, 0x43, 0xe7, 0x7c, 0x62, 0x7e, 0xba, 0x5b, 0x3d, 0xe0, + 0x5b, 0xf9, 0x09, 0xeb, 0xf5, 0x40, 0x35, 0x85, 0x34, 0xf0, 0x93, 0x54, 0x61, 0x8b, 0x2c, 0xef, + 0x03, 0xbe, 0x01, 0xce, 0x38, 0x46, 0xf0, 0xa1, 0x80, 0x1c, 0xe9, 0x26, 0x21, 0x69, 0x02, 0x1c, + 0xd3, 0xa3, 0x14, 0x94, 0x57, 0x09, 0x2a, 0x8d, 0x85, 0x68, 0xcc, 0x12, 0xbe, 0x20, 0x6b, 0xfb, + 0x80, 0xed, 0x2c, 0x2b, 0xd3, 0x72, 0x29, 0x78, 0x0e, 0xf4, 0x11, 0xb9, 0x99, 0x30, 0x64, 0x5e, + 0x25, 0x98, 0x69, 0x54, 0x5b, 0x74, 0xdb, 0x6a, 0xdd, 0xb6, 0x51, 0xbb, 0x0c, 0x59, 0x64, 0xfc, + 0xe1, 0xaf, 0x64, 0xf5, 0xad, 0x4c, 0x18, 0xc2, 0x67, 0xd1, 0x9e, 0xc1, 0xdf, 0x08, 0x2a, 0x9f, + 0x84, 0xff, 0x89, 0x2c, 0xed, 0x61, 0x1f, 0x14, 0x14, 0x83, 0x76, 0xb7, 0x2b, 0x0a, 0x8e, 0xd4, + 0x23, 0x73, 0x2c, 0x49, 0x14, 0xe4, 0xb9, 0xc3, 0x2d, 0x97, 0x74, 0x99, 0xcc, 0xbc, 0x87, 0xa1, + 0xc1, 0x5c, 0x88, 0xf4, 0x5f, 0xea, 0x93, 0x79, 0xc9, 0xf2, 0xfc, 0x44, 0xa8, 0xc4, 0x9b, 0x31, + 0xe6, 0xb3, 0x75, 0xb8, 0x45, 0xe6, 0xbe, 0x83, 0x61, 0x87, 0xa5, 0x4a, 0x27, 0xca, 0xe2, 0xd0, + 0xc1, 0xe9, 0xbf, 0xc6, 0x72, 0x8c, 0x25, 0x94, 0x3c, 0xc6, 0xf0, 0xbf, 0x1b, 0x84, 0x9c, 0x97, + 0x47, 0xbf, 0x25, 0x55, 0xc0, 0x7e, 0xcc, 0x6c, 0x51, 0x26, 0xb5, 0xda, 0xba, 0x53, 0xea, 0xb8, + 0x54, 0x73, 0x44, 0x00, 0xfb, 0x65, 0xfd, 0x4f, 0x89, 0xa7, 0x33, 0x13, 0x38, 0x62, 0x45, 0x86, + 0x25, 0x42, 0xcc, 0xd9, 0x00, 0x1c, 0xdf, 0x3a, 0x60, 0x7f, 0xd7, 0xba, 0x5d, 0xd2, 0x6b, 0x36, + 0x00, 0xfa, 0x8a, 0x7c, 0xa1, 0xa0, 0x0b, 0xe9, 0x31, 0xc4, 0x70, 0x0c, 0x3a, 0x45, 0xe8, 0x6e, + 0x76, 0xcd, 0x0c, 0xc4, 0xc0, 0x13, 0x29, 0x52, 0x8e, 0x4e, 0x67, 0xe0, 0x42, 0xf7, 0x74, 0xe4, + 0xeb, 0xb1, 0xc0, 0x3d, 0x17, 0x47, 0x1f, 0x90, 0xaa, 0xdd, 0x10, 0x1c, 0xc6, 0x69, 0xe2, 0xdd, + 0x1c, 0xdf, 0x23, 0x1c, 0x1e, 0x24, 0xf4, 0x19, 0x59, 0xce, 0xd3, 0x1e, 0x4f, 0x79, 0x2f, 0x7e, + 0x0f, 0xc3, 0x58, 0xb2, 0x54, 0x79, 0xb7, 0x8c, 0xce, 0xa5, 0x52, 0xa7, 0x6b, 0x60, 0xb4, 0xe8, + 0x02, 0xcb, 0x86, 0x3e, 0x23, 0xcb, 0x80, 0x7d, 0x56, 0x60, 0xff, 0x3c, 0x75, 0xf6, 0x8a, 0x54, + 0x17, 0xe8, 0xd6, 0xe1, 0xdf, 0x73, 0x84, 0xec, 0x98, 0x10, 0xd3, 0xe7, 0x87, 0xa4, 0x96, 0xa3, + 0x50, 0xac, 0x07, 0xb1, 0x64, 0xd8, 0x77, 0x7b, 0x54, 0x75, 0xb6, 0x0e, 0xc3, 0x3e, 0xbd, 0x4b, + 0xe6, 0x65, 0x4b, 0xc6, 0x52, 0x28, 0xbb, 0x61, 0xb7, 0xa2, 0x39, 0xd9, 0x92, 0x1d, 0xa1, 0x90, + 0x3e, 0x22, 0x4b, 0xda, 0x05, 0xa7, 0x08, 0x8a, 0xb3, 0x2c, 0x4e, 0xa5, 0x6b, 0x4f, 0x5d, 0xb6, + 0xe4, 0x9e, 0xb3, 0x1e, 0x48, 0xfa, 0x03, 0xb9, 0xad, 0xe3, 0xba, 0x82, 0x73, 0xe8, 0x9a, 0x76, + 0x62, 0x3a, 0x00, 0x51, 0xa0, 0x69, 0x4b, 0xb5, 0x75, 0x77, 0xdb, 0x9e, 0xd2, 0xed, 0xf2, 0x94, + 0x6e, 0xef, 0xba, 0x53, 0x1c, 0xad, 0xc9, 0x96, 0xdc, 0x39, 0xcb, 0x7b, 0x63, 0xd3, 0x74, 0x73, + 0xf5, 0x65, 0x01, 0xca, 0x96, 0x75, 0xcb, 0x94, 0x45, 0xac, 0xc9, 0x54, 0xf6, 0x25, 0x59, 0x74, + 0x01, 0xe5, 0x30, 0xcf, 0xda, 0xc2, 0xac, 0xb5, 0xed, 0x46, 0xfa, 0x01, 0xa9, 0xf2, 0x62, 0x10, + 0x9f, 0x08, 0xf5, 0x1e, 0x54, 0xee, 0xcd, 0x59, 0x1c, 0x5e, 0x0c, 0xde, 0x59, 0x0b, 0xdd, 0x22, + 0xab, 0xd6, 0x19, 0x9f, 0xb0, 0x14, 0x4d, 0xd9, 0xf1, 0x20, 0xf7, 0xe6, 0x4d, 0xe0, 0xb2, 0x75, + 0xbd, 0x63, 0x29, 0xea, 0xc2, 0x5e, 0xe5, 0x34, 0x20, 0x35, 0x3d, 0x7c, 0x5c, 0x24, 0x10, 0x17, + 0x2a, 0xf3, 0x16, 0xec, 0xae, 0x03, 0xf6, 0x5f, 0x8b, 0x04, 0xde, 0xaa, 0x8c, 0xfe, 0x42, 0xee, + 0xeb, 0x88, 0xae, 0xe0, 0x08, 0xa7, 0x18, 0x2b, 0x60, 0xc9, 0x39, 0xb4, 0xee, 0x08, 0xb9, 0xae, + 0x23, 0x77, 0x01, 0xfb, 0x3b, 0x36, 0x3d, 0x02, 0x96, 0x94, 0xec, 0xba, 0x2d, 0x91, 0x9d, 0xfd, + 0x12, 0xfc, 0x02, 0x6e, 0xf5, 0x3a, 0xdc, 0xf5, 0x73, 0xdc, 0x71, 0xcc, 0x7d, 0x42, 0x35, 0x66, + 0xca, 0x11, 0xd4, 0x31, 0xcb, 0x62, 0x05, 0xa8, 0x86, 0x5e, 0xed, 0x3a, 0x34, 0x3d, 0xa0, 0x07, + 0x2e, 0x27, 0xd2, 0x29, 0x7a, 0x58, 0x34, 0xd0, 0x80, 0x9d, 0x1a, 0x8c, 0x14, 0x72, 0xaf, 0x1e, + 0x54, 0x1a, 0xf5, 0xa8, 0x0e, 0xd8, 0x7f, 0xc5, 0x4e, 0x23, 0x6b, 0xa4, 0x21, 0xd1, 0x86, 0xb8, + 0xc7, 0xf2, 0x58, 0xaa, 0xb4, 0x0b, 0xde, 0x62, 0x50, 0x69, 0xdc, 0x8c, 0xf4, 0x7d, 0xb0, 0xcf, + 0xf2, 0x8e, 0x36, 0x8d, 0xc7, 0x64, 0xe9, 0x20, 0x45, 0x6f, 0x69, 0x3c, 0xe6, 0x7b, 0x6d, 0xd2, + 0x7c, 0x78, 0x1a, 0x4b, 0x21, 0xb2, 0x18, 0x38, 0x3b, 0xcc, 0x20, 0xf1, 0x96, 0x83, 0x4a, 0x63, + 0x3e, 0xaa, 0xe3, 0x69, 0x47, 0x88, 0x6c, 0xcf, 0x1a, 0xf5, 0x85, 0xc7, 0x01, 0xf5, 0x56, 0x7a, + 0x2b, 0xf6, 0xc2, 0x73, 0x4b, 0xfa, 0x15, 0x59, 0x3a, 0x14, 0x02, 0x73, 0x54, 0x4c, 0xc6, 0x12, + 0xf4, 0x84, 0xd0, 0x60, 0xa6, 0xb1, 0x10, 0x2d, 0x9e, 0x99, 0x3b, 0xda, 0x4a, 0xef, 0x13, 0xe2, + 0x72, 0xf4, 0x51, 0x5f, 0x35, 0xaa, 0x16, 0x9c, 0xe5, 0x20, 0xa1, 0x4f, 0x49, 0x7d, 0xc0, 0x52, + 0x1e, 0x97, 0x87, 0xdf, 0x5b, 0xbb, 0xf2, 0x5a, 0xae, 0xe9, 0xc0, 0x03, 0x17, 0xd7, 0xfa, 0x6b, + 0x9e, 0xd4, 0xed, 0x61, 0xfd, 0xd1, 0x3e, 0x8d, 0x94, 0x91, 0x85, 0x7d, 0x40, 0x6b, 0xa3, 0xb7, + 0x27, 0xda, 0xbf, 0xa7, 0x1f, 0x37, 0xff, 0x0c, 0xf8, 0xfc, 0xa0, 0x87, 0x8d, 0x51, 0x7b, 0xc5, + 0x5f, 0xda, 0x07, 0x0c, 0xf4, 0x24, 0x06, 0xd6, 0xf3, 0xf1, 0x9f, 0x7f, 0xff, 0xbc, 0xb1, 0x48, + 0x6b, 0x4d, 0xf7, 0x00, 0xeb, 0xb9, 0xa5, 0x85, 0xa1, 0xb0, 0x35, 0x51, 0xaf, 0x84, 0xba, 0xfc, + 0xf2, 0xf9, 0x53, 0xaa, 0x0f, 0x9f, 0x8f, 0xda, 0xab, 0xfe, 0x8a, 0x26, 0xb1, 0xc6, 0x71, 0x9a, + 0x4d, 0xba, 0x51, 0xd2, 0xa0, 0x71, 0xe6, 0xcd, 0xdf, 0xce, 0x5f, 0xac, 0xdf, 0xe9, 0x90, 0xd4, + 0xc7, 0x5f, 0xca, 0xfc, 0x4a, 0x75, 0x1b, 0x63, 0x25, 0x4d, 0x3c, 0xac, 0x61, 0x6b, 0xd4, 0xf6, + 0xfc, 0xdb, 0xba, 0x84, 0x76, 0x96, 0x5d, 0x2c, 0x23, 0x37, 0x75, 0xac, 0xd0, 0xa5, 0x4b, 0x75, + 0xd0, 0x8c, 0xd4, 0x76, 0x14, 0x30, 0x04, 0xd7, 0xd7, 0x29, 0xfd, 0x9b, 0xda, 0xd3, 0x6f, 0x46, + 0x6d, 0xdf, 0xf7, 0x6c, 0x6a, 0x1e, 0xe8, 0xe6, 0x05, 0x36, 0x28, 0xd0, 0x8f, 0xab, 0x65, 0x0b, + 0x2f, 0x34, 0xf7, 0x79, 0xe5, 0x31, 0xfd, 0x50, 0xb2, 0xb9, 0x16, 0x4f, 0x69, 0xe4, 0xd4, 0xe6, + 0x3e, 0x1b, 0xb5, 0x37, 0x7c, 0xbf, 0x64, 0xb3, 0xb5, 0x4f, 0xf0, 0xad, 0x85, 0x97, 0xd5, 0x69, + 0xca, 0x1e, 0xa9, 0xd9, 0xaf, 0x88, 0xcf, 0x14, 0xd8, 0x1c, 0xb5, 0xd7, 0x7d, 0xf7, 0x01, 0x72, + 0x41, 0xa0, 0xd5, 0xe6, 0x4f, 0x68, 0xfb, 0x58, 0x29, 0x99, 0x9c, 0xb8, 0x7b, 0x25, 0xea, 0x94, + 0xaf, 0x98, 0xa9, 0x2a, 0xdb, 0xa3, 0xf6, 0x1d, 0x7f, 0xbd, 0xa4, 0xbc, 0xa0, 0xd2, 0x90, 0x3e, + 0xf4, 0x3f, 0x39, 0x46, 0xba, 0x88, 0x8c, 0xd4, 0x76, 0x21, 0x83, 0x33, 0xb5, 0x57, 0x0d, 0xd2, + 0x15, 0xf6, 0xf0, 0x89, 0x51, 0x6d, 0x21, 0x26, 0x55, 0x2f, 0x3e, 0xbe, 0x78, 0x5c, 0xfe, 0xa8, + 0x94, 0x74, 0xd7, 0x1e, 0x99, 0xab, 0x08, 0x5f, 0x18, 0xcd, 0x25, 0xe1, 0xa4, 0xe6, 0xcd, 0xc7, + 0x9f, 0xd4, 0xfc, 0xf2, 0x11, 0x21, 0x5d, 0x31, 0x70, 0xb4, 0x2f, 0x6b, 0xee, 0xae, 0xe8, 0x68, + 0x92, 0x4e, 0xe5, 0xe7, 0x79, 0x6b, 0x97, 0x87, 0x87, 0xb3, 0x86, 0xf7, 0xeb, 0xff, 0x03, 0x00, + 0x00, 0xff, 0xff, 0xd9, 0x4e, 0xef, 0x2d, 0x70, 0x0b, 0x00, 0x00, } diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go index 82aef331d..1f2c8d225 100644 --- a/protobufs/gen/go/config/service.pb.gw.go +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -485,21 +485,21 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM var ( pattern_ConfigService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_GetTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) + pattern_ConfigService_GetTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) - pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenant"}, "")) + pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) pattern_ConfigService_CreateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenant"}, "")) + pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) pattern_ConfigService_UpdateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) + pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) pattern_ConfigService_DeleteConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_DeleteTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenant", "identifier"}, "")) + pattern_ConfigService_DeleteTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) ) var ( diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 7e15ed97d..df5e349a9 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenant":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenant/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 5acfe8351..1c0ac785a 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -97,7 +97,7 @@ ] } }, - "/config/tenant": { + "/config/tenants": { "get": { "description": "Get All Tenant Configs", "operationId": "GetAllTenants", @@ -139,7 +139,7 @@ ] } }, - "/config/tenant/{identifier}": { + "/config/tenants/{identifier}": { "get": { "description": "Get Tenant Config", "operationId": "GetTenant", diff --git a/testworld/httputils.go b/testworld/httputils.go index 225fa01f6..1827b1e1f 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -92,7 +92,7 @@ func getNodeConfig(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { } func getTenantConfig(e *httpexpect.Expect, httpStatus int, identifier string) *httpexpect.Object { - resp := e.GET("/config/tenant/"+identifier). + resp := e.GET("/config/tenants/"+identifier). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). Expect().Status(httpStatus) @@ -100,7 +100,7 @@ func getTenantConfig(e *httpexpect.Expect, httpStatus int, identifier string) *h } func getAllTenantConfigs(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { - resp := e.GET("/config/tenant"). + resp := e.GET("/config/tenants"). WithHeader("accept", "application/json"). WithHeader("Content-Type", "application/json"). Expect().Status(httpStatus) From 56c76c6e6a4ab459e008ff86bccd0aeb3f00e77b Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 3 Jan 2019 14:56:10 +0100 Subject: [PATCH 108/220] Async APIs (#598) Fixes #497 #498 #499 I started using commom.Address for tenant id since that is a requirement for transactions. Note: This will break the functional tests. --- api/bootstrapper_test.go | 3 +- api/server_test.go | 2 +- bootstrap/bootstrapper.go | 2 + bootstrap/bootstrappers/bootstrapper.go | 3 + .../testingbootstrap/testing_bootstrap.go | 5 + common/common.go | 2 +- coredocument/bootstrapper.go | 38 +++++ coredocument/bootstrapper_test.go | 14 ++ coredocument/test_bootstrapper.go | 11 ++ documents/anchor_task.go | 137 ++++++++++++++++ documents/anchor_task_test.go | 87 ++++++++++ documents/bootstrapper.go | 39 +++++ documents/bootstrapper_test.go | 10 +- documents/genericdoc/service.go | 49 ++---- documents/genericdoc/service_test.go | 34 ++-- documents/invoice/bootstrapper.go | 28 ++-- documents/invoice/handler.go | 6 +- documents/invoice/handler_test.go | 31 ++-- documents/invoice/model_test.go | 5 +- documents/invoice/service.go | 116 +++++++------ documents/invoice/service_test.go | 97 +++++------ documents/model_test.go | 4 + documents/purchaseorder/bootstrapper.go | 24 +-- documents/purchaseorder/handler.go | 6 +- documents/purchaseorder/handler_test.go | 34 ++-- documents/purchaseorder/model_test.go | 3 + documents/purchaseorder/service.go | 107 ++++++------ documents/purchaseorder/service_test.go | 90 ++++------- documents/test/anchor_test.go | 6 +- documents/test_bootstrapper.go | 8 + nft/bootstrapper.go | 27 +++- nft/bootstrapper_test.go | 21 +++ nft/ethereum_payment_obligation.go | 90 ++++++----- nft/ethereum_payment_obligation_test.go | 31 ++-- nft/handler.go | 20 ++- nft/handler_test.go | 42 +++-- nft/minting_confirmation_task.go | 78 +++++---- nft/minting_confirmation_task_test.go | 14 +- nft/payment_obligation.go | 11 +- nft/payment_obligation_integration_test.go | 29 ++-- p2p/bootstrapper.go | 7 +- p2p/bootstrapper_test.go | 4 +- p2p/receiver/handler_test.go | 7 +- p2p/server_test.go | 10 +- protobufs/gen/go/invoice/service.pb.go | 147 +++++++++-------- protobufs/gen/go/nft/service.pb.go | 67 ++++---- protobufs/gen/go/purchaseorder/service.pb.go | 153 +++++++++--------- protobufs/gen/go/transactions/service.pb.go | 56 +++---- .../gen/go/transactions/service.pb.gw.go | 2 +- protobufs/gen/swagger.json | 2 +- .../gen/swagger/invoice/service.swagger.json | 3 + .../gen/swagger/nft/service.swagger.json | 3 + .../purchaseorder/service.swagger.json | 3 + .../swagger/transactions/service.swagger.json | 2 +- protobufs/invoice/service.proto | 1 + protobufs/nft/service.proto | 1 + protobufs/purchaseorder/service.proto | 1 + protobufs/transactions/service.proto | 2 +- queue/server.go | 5 + testingutils/utils.go | 12 ++ testworld/document_consensus_test.go | 8 + testworld/httputils.go | 27 ++++ testworld/nft_test.go | 2 + testworld/park_test.go | 2 + testworld/proof_test.go | 2 + transactions/base_task.go | 53 ++++++ transactions/base_task_test.go | 53 ++++++ transactions/service.go | 46 +++++- transactions/service_test.go | 31 +++- 69 files changed, 1364 insertions(+), 712 deletions(-) create mode 100644 coredocument/bootstrapper.go create mode 100644 coredocument/bootstrapper_test.go create mode 100644 coredocument/test_bootstrapper.go create mode 100644 documents/anchor_task.go create mode 100644 documents/anchor_task_test.go create mode 100644 transactions/base_task.go create mode 100644 transactions/base_task_test.go diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index facccab19..a5b5f3922 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -5,9 +5,8 @@ package api import ( "testing" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/testingutils/config" diff --git a/api/server_test.go b/api/server_test.go index 03526a6e4..a1a3f0f1d 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -73,7 +73,7 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil, nil)) + registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil, nil, nil)) capi := apiServer{config: cfg} ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) startErr := make(chan error) diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 5bb8bac1b..61af54681 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -6,9 +6,11 @@ package bootstrap const ( BootstrappedConfig string = "BootstrappedConfig" BootstrappedP2PServer string = "BootstrappedP2PServer" + BootstrappedP2PClient string = "BootstrappedP2PClient" BootstrappedAPIServer string = "BootstrappedAPIServer" BootstrappedQueueServer string = "BootstrappedQueueServer" NodeObjRegistry string = "NodeObjRegistry" + BootstrappedCoreDocProc string = "BootstrappedCoreDocProc" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 31687dc3a..e1254559f 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -6,6 +6,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" @@ -45,6 +46,8 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { api.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, + coredocument.Bootstrapper{}, + documents.PostBootstrapper{}, &nft.Bootstrapper{}, } } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index b40a8bf21..ff6abc54e 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" @@ -18,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/transactions" logging "github.com/ipfs/go-log" ) @@ -27,6 +29,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + transactions.Bootstrapper{}, &configstore.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, @@ -36,6 +39,8 @@ var bootstappers = []bootstrap.TestBootstrapper{ p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, + coredocument.Bootstrapper{}, + documents.PostBootstrapper{}, &nft.Bootstrapper{}, &queue.Starter{}, } diff --git a/common/common.go b/common/common.go index 4db660451..d447030e6 100644 --- a/common/common.go +++ b/common/common.go @@ -8,6 +8,6 @@ var ( TenantKey struct{} // DummyIdentity to be used until we have identity coming from auth header - // TODO(ved): get rid of this once we have multitenancy enabled/ + // TODO(ved): get rid of this once we have multitenancy enabled DummyIdentity = common.Address([20]byte{1}) ) diff --git a/coredocument/bootstrapper.go b/coredocument/bootstrapper.go new file mode 100644 index 000000000..03770ba6e --- /dev/null +++ b/coredocument/bootstrapper.go @@ -0,0 +1,38 @@ +package coredocument + +import ( + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" +) + +// Bootstrapper to initialise processor +type Bootstrapper struct{} + +// Bootstrap adds processor to the context. +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + cfg, ok := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + if !ok { + return errors.New("config hasn't been initialized") + } + + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return errors.New("anchor repository not initialised") + } + + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + + p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(client) + if !ok { + return errors.New("p2p client not initialised") + } + + ctx[bootstrap.BootstrappedCoreDocProc] = DefaultProcessor(idService, p2pClient, anchorRepo, cfg) + return nil +} diff --git a/coredocument/bootstrapper_test.go b/coredocument/bootstrapper_test.go new file mode 100644 index 000000000..a7a657ff2 --- /dev/null +++ b/coredocument/bootstrapper_test.go @@ -0,0 +1,14 @@ +// +build unit + +package coredocument + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) + assert.Error(t, err, "Should throw an error because of empty context") +} diff --git a/coredocument/test_bootstrapper.go b/coredocument/test_bootstrapper.go new file mode 100644 index 000000000..f6e0eb6f9 --- /dev/null +++ b/coredocument/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build integration unit + +package coredocument + +func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { + return b.Bootstrap(context) +} + +func (Bootstrapper) TestTearDown() error { + return nil +} diff --git a/documents/anchor_task.go b/documents/anchor_task.go new file mode 100644 index 000000000..3b5efe664 --- /dev/null +++ b/documents/anchor_task.go @@ -0,0 +1,137 @@ +package documents + +import ( + "context" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/gocelery" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + logging "github.com/ipfs/go-log" + "github.com/satori/go.uuid" +) + +const ( + modelIDParam = "modelID" + tenantIDParam = "tenantID" + documentAnchorTaskName = "Document Anchoring" +) + +var log = logging.Logger("anchor_task") + +type documentAnchorTask struct { + transactions.BaseTask + + id []byte + tenantID common.Address + + // state + config config.Configuration + processor anchorProcessor + modelGetFunc func(tenantID, id []byte) (Model, error) + modelSaveFunc func(tenantID, id []byte, model Model) error +} + +// TaskTypeName returns the name of the task. +func (d *documentAnchorTask) TaskTypeName() string { + return documentAnchorTaskName +} + +// ParseKwargs parses the kwargs. +func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { + err := d.ParseTransactionID(kwargs) + if err != nil { + return err + } + + modelID, ok := kwargs[modelIDParam].(string) + if !ok { + return errors.New("missing model ID") + } + + d.id, err = hexutil.Decode(modelID) + if err != nil { + return errors.New("invalid model ID") + } + + tenantID, ok := kwargs[tenantIDParam].(string) + if !ok { + return errors.New("missing tenant ID") + } + + d.tenantID = common.HexToAddress(tenantID) + return nil +} + +// Copy returns a new task with state. +func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { + return &documentAnchorTask{ + BaseTask: transactions.BaseTask{TxService: d.TxService}, + config: d.config, + processor: d.processor, + modelGetFunc: d.modelGetFunc, + modelSaveFunc: d.modelSaveFunc, + }, nil +} + +// RunTask anchors the document. +func (d *documentAnchorTask) RunTask() (res interface{}, err error) { + log.Infof("starting anchor task: %v\n", d.TxID.String()) + defer func() { + if err == nil { + log.Infof("anchor task successful: %v\n", d.TxID.String()) + } else { + log.Infof("anchor task failed: %v\n", err) + } + + err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) + }() + + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), d.config) + if err != nil { + return false, errors.New("failed to get context header: %v", err) + } + + model, err := d.modelGetFunc(d.tenantID[:], d.id) + if err != nil { + return false, errors.New("failed to get model: %v", err) + } + + if _, err = AnchorDocument(ctxh, model, d.processor, func(id []byte, model Model) error { + return d.modelSaveFunc(d.tenantID[:], id, model) + }); err != nil { + return false, errors.New("failed to anchor document: %v", err) + } + + return true, nil +} + +// taskQueuer can be implemented by any queueing system +type taskQueuer interface { + EnqueueJob(taskTypeName string, params map[string]interface{}) (queue.TaskResult, error) +} + +// InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. +func InitDocumentAnchorTask(tq taskQueuer, txService transactions.Service, tenantID common.Address, modelID []byte) (uuid.UUID, error) { + tx, err := txService.CreateTransaction(tenantID, documentAnchorTaskName) + if err != nil { + return uuid.Nil, err + } + + params := map[string]interface{}{ + transactions.TxIDParam: tx.ID.String(), + modelIDParam: hexutil.Encode(modelID), + tenantIDParam: tenantID, + } + + _, err = tq.EnqueueJob(documentAnchorTaskName, params) + if err != nil { + return uuid.Nil, err + } + + return tx.ID, nil +} diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go new file mode 100644 index 000000000..fb6618720 --- /dev/null +++ b/documents/anchor_task_test.go @@ -0,0 +1,87 @@ +// +build unit + +package documents + +import ( + "testing" + + cc "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/assert" +) + +func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { + tests := []struct { + name string + kwargs map[string]interface{} + err string + }{ + { + name: "nil kwargs", + err: "missing transaction ID", + }, + + { + kwargs: map[string]interface{}{ + transactions.TxIDParam: "some string", + }, + err: "invalid transaction ID", + }, + + // missing model ID + { + kwargs: map[string]interface{}{ + transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + }, + err: "missing model ID", + }, + + // missing tenantID + { + kwargs: map[string]interface{}{ + transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + modelIDParam: hexutil.Encode(utils.RandomSlice(32)), + }, + + err: "missing tenant ID", + }, + + // all good + { + name: "success", + kwargs: map[string]interface{}{ + transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + modelIDParam: hexutil.Encode(utils.RandomSlice(32)), + tenantIDParam: cc.DummyIdentity, + }, + }, + } + + for _, c := range tests { + name := c.name + if name == "" { + name = c.err + } + + t.Run(name, func(t *testing.T) { + d, err := utils.SimulateJSONDecodeForGocelery(c.kwargs) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + task := new(documentAnchorTask) + err = task.ParseKwargs(d) + if c.err == "" { + assert.Equal(t, task.TxID.String(), c.kwargs[transactions.TxIDParam]) + assert.Equal(t, hexutil.Encode(task.id), c.kwargs[modelIDParam]) + assert.Equal(t, task.tenantID, c.kwargs[tenantIDParam]) + return + } + + assert.EqualError(t, err, c.err) + }) + } +} diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 229c8d675..f45e592e6 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -1,12 +1,18 @@ package documents import ( + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/transactions" ) const ( // BootstrappedRegistry is the key to ServiceRegistry in Bootstrap context BootstrappedRegistry = "BootstrappedRegistry" + // BootstrappedDocumentRepository is the key to the database repository of documents BootstrappedDocumentRepository = "BootstrappedDocumentRepository" ) @@ -24,3 +30,36 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { ctx[BootstrappedDocumentRepository] = NewDBRepository(ldb) return nil } + +// PostBootstrapper to run the post after all bootstrappers. +type PostBootstrapper struct{} + +// Bootstrap register task to the queue. +func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue not initialised") + } + + coreDocProc, ok := ctx[bootstrap.BootstrappedCoreDocProc].(anchorProcessor) + if !ok { + return errors.New("coredoc processor not initialised") + } + + repo, ok := ctx[BootstrappedDocumentRepository].(Repository) + if !ok { + return errors.New("document repository not initialised") + } + + task := &documentAnchorTask{ + BaseTask: transactions.BaseTask{ + TxService: ctx[transactions.BootstrappedService].(transactions.Service), + }, + config: ctx[bootstrap.BootstrappedConfig].(config.Configuration), + processor: coreDocProc, + modelGetFunc: repo.Get, + modelSaveFunc: repo.Update, + } + queueSrv.RegisterTaskType(documentAnchorTaskName, task) + return nil +} diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 05ad7ddfd..296b9d151 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -5,7 +5,11 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -14,7 +18,11 @@ func TestBootstrapper_Bootstrap(t *testing.T) { randomPath := storage.GetRandomTestStoragePath() db, err := storage.NewLevelDBStorage(randomPath) assert.Nil(t, err) - ctx[storage.BootstrappedDB] = storage.NewLevelDBRepository(db) + repo := storage.NewLevelDBRepository(db) + ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} + ctx[storage.BootstrappedDB] = repo + ctx[bootstrap.BootstrappedQueueServer] = new(queue.Server) + ctx[transactions.BootstrappedService] = transactions.NewService(transactions.NewRepository(repo)) err = Bootstrapper{}.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRegistry]) diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 761329011..dc6ca7cb7 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -5,25 +5,22 @@ import ( "context" "time" - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/crypto" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes" - - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/notification" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" ) @@ -157,11 +154,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } + tenantID := common.DummyIdentity.Bytes() // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { @@ -190,13 +183,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - err = s.repo.Update(tenantID, doc.CurrentVersion, model) + err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -217,21 +204,11 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C } func (s service) Exists(documentID []byte) bool { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return false - } - return s.repo.Exists(tenantID, documentID) + return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) } func (s service) getVersion(documentID, version []byte) (documents.Model, error) { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - model, err := s.repo.Get(tenantID, version) + model, err := s.repo.Get(common.DummyIdentity.Bytes(), version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index f761ded07..ef13623a4 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -8,31 +8,31 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/stretchr/testify/mock" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var testRepoGlobal documents.Repository var ( centIDBytes = utils.RandomSlice(identity.CentIDLength) + tenantID = common.DummyIdentity.Bytes() key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -62,12 +62,10 @@ func TestService_ReceiveAnchoredDocument(t *testing.T) { } func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) repo := testRepo() idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(c, repo, &mockAnchorRepo{}, &idService), idService + return DefaultService(nil, repo, &mockAnchorRepo{}, &idService), idService } type mockAnchorRepo struct { @@ -129,7 +127,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, } if !skipSave { - err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -167,7 +165,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv if err != nil { return nil, err } - err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -209,7 +207,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) _, err = service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) @@ -300,7 +298,7 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { }, } - err := testRepo().Create(centIDBytes, version, inv) + err := testRepo().Create(tenantID, version, inv) currentVersion = version version = next assert.Nil(t, err) @@ -330,7 +328,7 @@ func TestService_GetVersion_successful(t *testing.T) { }, } - err := testRepo().Create(centIDBytes, currentVersion, inv) + err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) mod, err := service.GetVersion(documentIdentifier, currentVersion) @@ -359,7 +357,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { }, } - err = testRepo().Create(centIDBytes, documentIdentifier, inv) + err = testRepo().Create(tenantID, documentIdentifier, inv) assert.Nil(t, err) _, err = service.GetCurrentVersion(documentIdentifier) @@ -384,7 +382,7 @@ func TestService_GetVersion_error(t *testing.T) { CurrentVersion: currentVersion, }, } - err = testRepo().Create(centIDBytes, currentVersion, inv) + err = testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) //random version @@ -424,7 +422,7 @@ func TestService_Exists(t *testing.T) { }, } - err = testRepo().Create(centIDBytes, documentIdentifier, inv) + err = testRepo().Create(tenantID, documentIdentifier, inv) exists := service.Exists(documentIdentifier) assert.True(t, exists, "document should exist") diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 30191c79c..9bb8ec3da 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,16 +1,15 @@ package invoice import ( - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -24,11 +23,6 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) - if !ok { - return errors.New("p2p client not initialised") - } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("service registry not initialised") @@ -50,8 +44,22 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } repo.Register(&Invoice{}) + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue server not initialised") + } + + txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + if !ok { + return errors.New("transaction service not initialised") + } + // register service - srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService( + cfg, + repo, + anchorRepo, + idService, queueSrv, txService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return errors.New("failed to register invoice service: %v", err) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 08551d740..b30ec14a3 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -55,7 +55,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr } // validate and persist - doc, err = h.service.Create(ctxHeader, doc) + doc, txID, err := h.service.Create(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not create document") @@ -67,6 +67,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr return nil, centerrors.Wrap(err, "could not derive response") } + resp.Header.TransactionId = txID.String() return resp, nil } @@ -85,7 +86,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi return nil, centerrors.Wrap(err, "could not derive update payload") } - doc, err = h.service.Update(ctxHeader, doc) + doc, txID, err := h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not update document") @@ -97,6 +98,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi return nil, centerrors.Wrap(err, "could not derive response") } + resp.Header.TransactionId = txID.String() return resp, nil } diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 84a793b88..ab5371f58 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -28,10 +29,11 @@ func (m *mockService) DeriveFromCreatePayload(ctx context.Context, payload *clie return model, args.Error(1) } -func (m *mockService) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (m *mockService) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { args := m.Called(ctx, inv) model, _ := args.Get(0).(documents.Model) - return model, args.Error(1) + txID, _ := uuid.FromString(args.Get(1).(string)) + return model, txID, args.Error(2) } func (m *mockService) GetCurrentVersion(identifier []byte) (documents.Model, error) { @@ -58,10 +60,11 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx context.Context, inv documents.Model) (documents.Model, error) { - args := m.Called(ctx, inv) +func (m *mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, doc) doc1, _ := args.Get(0).(documents.Model) - return doc1, args.Error(1) + txID, _ := uuid.FromString(args.Get(1).(string)) + return doc1, txID, args.Error(2) } func (m *mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) { @@ -89,7 +92,7 @@ func TestGRPCHandler_Create_create_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(new(Invoice), nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(nil, errors.New("create failed")).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}} _, err := h.Create(context.Background(), payload) srv.AssertExpectations(t) @@ -120,7 +123,7 @@ func TestGRPCHandler_Create_DeriveInvoiceResponse_fail(t *testing.T) { srv := h.service.(*mockService) model := new(Invoice) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(model, nil).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(model, uuid.Nil.String(), nil).Once() srv.On("DeriveInvoiceResponse", mock.Anything).Return(nil, errors.New("derive response failed")) payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{Currency: "EUR"}} _, err := h.Create(context.Background(), payload) @@ -133,10 +136,11 @@ func TestGrpcHandler_Create(t *testing.T) { h := getHandler() srv := h.service.(*mockService) model := new(Invoice) + txID := uuid.Must(uuid.NewV4()) payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}, Collaborators: []string{"0x010203040506"}} - response := &clientinvoicepb.InvoiceResponse{} + response := &clientinvoicepb.InvoiceResponse{Header: &clientinvoicepb.ResponseHeader{}} srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(model, nil).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(model, txID.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(response, nil) res, err := h.Create(context.Background(), payload) srv.AssertExpectations(t) @@ -242,7 +246,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, errors.New("update error")).Once() + srv.On("Update", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -259,7 +263,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { assert.Nil(t, err) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(nil, errors.New("derive response error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) @@ -275,10 +279,11 @@ func TestGrpcHandler_Update(t *testing.T) { ctx := context.Background() ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) assert.Nil(t, err) + txID := uuid.Must(uuid.NewV4()) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} - resp := &clientinvoicepb.InvoiceResponse{} + resp := &clientinvoicepb.InvoiceResponse{Header: new(clientinvoicepb.ResponseHeader)} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, txID.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(resp, nil).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index ccf77df80..a6d0d3e33 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -9,14 +9,13 @@ import ( "reflect" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -27,6 +26,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" @@ -46,6 +46,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &storage.Bootstrapper{}, &queue.Bootstrapper{}, + transactions.Bootstrapper{}, &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, diff --git a/documents/invoice/service.go b/documents/invoice/service.go index b7e932beb..4eb24ba34 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -5,25 +5,27 @@ import ( "context" "time" - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" + "github.com/satori/go.uuid" ) var srvLog = logging.Logger("invoice-service") @@ -39,10 +41,10 @@ type Service interface { DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) // Create validates and persists invoice Model and returns a Updated model - Create(ctx context.Context, inv documents.Model) (documents.Model, error) + Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) // Update validates and updates the invoice model and return the updated model - Update(ctx context.Context, inv documents.Model) (documents.Model, error) + Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) // DeriveInvoiceData returns the invoice data as client data DeriveInvoiceData(inv documents.Model) (*clientinvoicepb.InvoiceData, error) @@ -57,15 +59,29 @@ type service struct { // TODO [multi-tenancy] replace this with config service config documents.Config repo documents.Repository - coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository identityService identity.Service + queueSrv queue.TaskQueuer + txService transactions.Service } -// DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{config: config, repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} +// DefaultService returns the default implementation of the service. +func DefaultService( + config config.Configuration, + repo documents.Repository, + anchorRepository anchors.AnchorRepository, + identityService identity.Service, + queueSrv queue.TaskQueuer, + txService transactions.Service) Service { + return service{ + config: config, + repo: repo, + notifier: notification.NewWebhookSender(config), + anchorRepository: anchorRepository, + identityService: identityService, + queueSrv: queueSrv, + txService: txService} } // CreateProofs creates proofs for the latest version document given the fields @@ -159,14 +175,8 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(tenantID, inv.CoreDocument.CurrentVersion, inv) + err = s.repo.Create(common.DummyIdentity.Bytes(), inv.CoreDocument.CurrentVersion, inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -175,53 +185,56 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { inv, err := s.calculateDataRoot(nil, inv, CreateValidator()) if err != nil { - return nil, err + return nil, uuid.Nil, err } - inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.updater) + cd, err := inv.PackCoreDocument() if err != nil { - return nil, err + return nil, uuid.Nil, err } - return inv, nil -} - -// updater wraps logic related to updating documents so that it can be executed as a closure -func (s service) updater(id []byte, model documents.Model) error { - // get tenant ID - tenantID, err := s.config.GetIdentityID() + txID, err := documents.InitDocumentAnchorTask( + s.queueSrv, + s.txService, + common.DummyIdentity, + cd.CurrentVersion) if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, err } - return s.repo.Update(tenantID, id, model) + + return inv, txID, nil } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, error) { +func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { cd, err := inv.PackCoreDocument() if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(cd.DocumentIdentifier) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } inv, err = s.calculateDataRoot(old, inv, UpdateValidator()) if err != nil { - return nil, err + return nil, uuid.Nil, err } - inv, err = documents.AnchorDocument(ctx, inv, s.coreDocProcessor, s.updater) + txID, err := documents.InitDocumentAnchorTask( + s.queueSrv, + s.txService, + common.DummyIdentity, + cd.CurrentVersion) if err != nil { - return nil, err + return nil, uuid.Nil, err } - return inv, nil + return inv, txID, nil } // GetVersion returns an invoice for a given version @@ -254,12 +267,7 @@ func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err } func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, err error) { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - doc, err := s.repo.Get(tenantID, version) + doc, err := s.repo.Get(common.DummyIdentity.Bytes(), version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -391,12 +399,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - + tenantID := common.DummyIdentity.Bytes() // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) @@ -425,13 +428,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - err = s.repo.Update(tenantID, doc.CurrentVersion, model) + err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -453,10 +450,5 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C // Exists checks if an invoice exists func (s service) Exists(documentID []byte) bool { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return false - } - return s.repo.Exists(tenantID, documentID) + return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 3b24069c2..17c37383b 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -7,10 +7,14 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/common" + + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/gocelery" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -19,8 +23,8 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" @@ -29,6 +33,7 @@ import ( var ( centIDBytes = utils.RandomSlice(identity.CentIDLength) + tenantID = common.DummyIdentity.Bytes() key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -47,7 +52,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func TestDefaultService(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil).Once() - srv := DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, nil, nil) + srv := DefaultService(c, testRepo(), nil, nil, nil, nil) assert.NotNil(t, srv, "must be non-nil") } @@ -56,7 +61,14 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { c.On("GetIdentityID").Return(centIDBytes, nil) idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, &idService) + queueSrv := new(testingutils.MockQueue) + queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) + return idService, DefaultService( + c, + testRepo(), + &mockAnchorRepo{}, &idService, + queueSrv, + ctx[transactions.BootstrappedService].(transactions.Service)) } func createMockDocument() (*Invoice, error) { @@ -71,7 +83,7 @@ func createMockDocument() (*Invoice, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(centIDBytes, documentIdentifier, inv1) + err := testRepo().Create(tenantID, documentIdentifier, inv1) return inv1, err } @@ -140,7 +152,7 @@ func TestService_GetLastVersion(t *testing.T) { }, } - err = testRepo().Create(centIDBytes, doc.CoreDocument.NextVersion, inv2) + err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, inv2) assert.Nil(t, err) mod2, err := invSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -161,7 +173,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(centIDBytes, currentVersion, inv) + err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -180,7 +192,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(centIDBytes, currentVersion, inv) + err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) mod, err := invSrv.GetVersion(documentIdentifier, currentVersion) @@ -203,7 +215,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(centIDBytes, documentIdentifier, inv) + err := testRepo().Create(tenantID, documentIdentifier, inv) assert.Nil(t, err) exists := invSrv.Exists(documentIdentifier) @@ -221,41 +233,20 @@ func TestService_Create(t *testing.T) { invSrv := srv.(service) // calculate data root fails - m, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) + m, _, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") - // anchor fails + // anchor success po, err := invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() - invSrv.coreDocProcessor = proc - m, err = invSrv.Create(ctxh, po) - proc.AssertExpectations(t) - assert.Nil(t, m) - assert.Error(t, err) - assert.Contains(t, err.Error(), "anchoring failed") - - // success - po, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) - assert.Nil(t, err) - proc = &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(nil).Once() - proc.On("RequestSignatures", ctxh, po).Return(nil).Once() - proc.On("PrepareForAnchoring", po).Return(nil).Once() - proc.On("AnchorDocument", po).Return(nil).Once() - proc.On("SendDocument", ctxh, po).Return(nil).Once() - invSrv.coreDocProcessor = proc - m, err = invSrv.Create(ctxh, po) - proc.AssertExpectations(t) + m, _, err = invSrv.Create(ctxh, po) assert.Nil(t, err) - newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) } func TestService_DeriveInvoiceData(t *testing.T) { @@ -331,7 +322,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) @@ -442,7 +433,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { } if !skipSave { - err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -480,7 +471,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { if err != nil { return nil, err } - err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -527,7 +518,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(centIDBytes, id, old) + err = testRepo().Create(tenantID, id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ Sender: "0x010101010101", @@ -579,7 +570,7 @@ func TestService_Update(t *testing.T) { // pack failed model := &mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, err = invSrv.Update(ctxh, model) + _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -588,7 +579,7 @@ func TestService_Update(t *testing.T) { model = &mockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = invSrv.Update(ctxh, model) + _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -601,12 +592,12 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) inv.(*Invoice).CoreDocument = cd - testRepo().Create(centIDBytes, cd.CurrentVersion, inv) + testRepo().Create(tenantID, cd.CurrentVersion, inv) // calculate data root fails model = &mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = invSrv.Update(ctxh, model) + _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -626,24 +617,14 @@ func TestService_Update(t *testing.T) { newData, err := invSrv.DeriveInvoiceData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() - proc.On("RequestSignatures", ctxh, newInv).Return(nil).Once() - proc.On("PrepareForAnchoring", newInv).Return(nil).Once() - proc.On("AnchorDocument", newInv).Return(nil).Once() - proc.On("SendDocument", ctxh, newInv).Return(nil).Once() - invSrv.coreDocProcessor = proc - inv, err = invSrv.Update(ctxh, newInv) - proc.AssertExpectations(t) + inv, _, err = invSrv.Update(ctxh, newInv) assert.Nil(t, err) assert.NotNil(t, inv) - newCD, err := inv.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.PreviousVersion)) - + assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(tenantID, newCD.PreviousVersion)) newData, err = invSrv.DeriveInvoiceData(inv) assert.Nil(t, err) assert.Equal(t, data, newData) @@ -678,7 +659,7 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - err = invSrv.repo.Create(centIDBytes, inv.(*Invoice).CoreDocument.CurrentVersion, inv) + err = invSrv.repo.Create(tenantID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) assert.Nil(t, err) inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) assert.Nil(t, inv) diff --git a/documents/model_test.go b/documents/model_test.go index 5c1164847..b180e0a91 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -9,7 +9,9 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/transactions" ) var ctx = map[string]interface{}{} @@ -19,6 +21,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + transactions.Bootstrapper{}, + &queue.Bootstrapper{}, &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index fa50503fd..fd66b0cad 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,16 +1,15 @@ package purchaseorder import ( - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -23,11 +22,6 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - p2pClient, ok := ctx[p2p.BootstrappedP2PClient].(p2p.Client) - if !ok { - return errors.New("p2p client not initialised") - } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("service registry not initialised") @@ -49,8 +43,18 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } repo.Register(&PurchaseOrder{}) + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue server not initialised") + } + + txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + if !ok { + return errors.New("transaction service not initialised") + } + // register service - srv := DefaultService(cfg, repo, coredocument.DefaultProcessor(idService, p2pClient, anchorRepo, cfg), anchorRepo, idService) + srv := DefaultService(cfg, repo, anchorRepo, idService, queueSrv, txService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 4beb731ab..15384d12d 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -56,7 +56,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc } // validate, persist, and anchor - doc, err = h.service.Create(ctxh, doc) + doc, txID, err := h.service.Create(ctxh, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not create document") @@ -68,6 +68,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc return nil, centerrors.Wrap(err, "could not derive response") } + resp.Header.TransactionId = txID.String() return resp, nil } @@ -86,7 +87,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. return nil, centerrors.Wrap(err, "could not derive update payload") } - doc, err = h.service.Update(ctxHeader, doc) + doc, txID, err := h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not update document") @@ -98,6 +99,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. return nil, centerrors.Wrap(err, "could not derive response") } + resp.Header.TransactionId = txID.String() return resp, nil } diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 4339998bf..872f5070c 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,14 +6,14 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -23,16 +23,18 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx context.Context, po documents.Model) (documents.Model, error) { - args := m.Called(ctx, po) +func (m mockService) Create(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) - return model, args.Error(1) + txID, _ := uuid.FromString(args.Get(1).(string)) + return model, txID, args.Error(2) } -func (m mockService) Update(ctx context.Context, po documents.Model) (documents.Model, error) { - args := m.Called(ctx, po) +func (m mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, doc) model, _ := args.Get(0).(documents.Model) - return model, args.Error(1) + txID, _ := uuid.FromString(args.Get(1).(string)) + return model, txID, args.Error(2) } func (m mockService) DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) { @@ -91,7 +93,7 @@ func TestGRPCHandler_Create(t *testing.T) { // create fails srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(nil, errors.New("create failed")).Once() + srv.On("Create", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -101,7 +103,7 @@ func TestGRPCHandler_Create(t *testing.T) { // derive response fails srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(model, nil).Once() + srv.On("Create", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -111,9 +113,9 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "derive response fails") // success - eresp := &clientpopb.PurchaseOrderResponse{} + eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(model, nil).Once() + srv.On("Create", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -147,7 +149,7 @@ func TestGrpcHandler_Update(t *testing.T) { // create fails srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, errors.New("update failed")).Once() + srv.On("Update", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -157,7 +159,7 @@ func TestGrpcHandler_Update(t *testing.T) { // derive response fails srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -167,9 +169,9 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "derive response fails") // success - eresp := &clientpopb.PurchaseOrderResponse{} + eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, nil).Once() + srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Update(ctx, req) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index b4aa8cedf..d4943f67a 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -27,6 +27,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" @@ -46,11 +47,13 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &storage.Bootstrapper{}, &queue.Bootstrapper{}, + transactions.Bootstrapper{}, &identity.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, + &queue.Starter{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index dd56fa746..dc45ed6a8 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -5,25 +5,27 @@ import ( "context" "time" - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" + "github.com/satori/go.uuid" ) var srvLog = logging.Logger("po-service") @@ -39,10 +41,10 @@ type Service interface { DeriveFromUpdatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderUpdatePayload) (documents.Model, error) // Create validates and persists purchase order and returns a Updated model - Create(ctx context.Context, po documents.Model) (documents.Model, error) + Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) // Update validates and updates the purchase order and return the updated model - Update(ctx context.Context, po documents.Model) (documents.Model, error) + Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) // DerivePurchaseOrderData returns the purchase order data as client data DerivePurchaseOrderData(po documents.Model) (*clientpopb.PurchaseOrderData, error) @@ -57,15 +59,30 @@ type service struct { // TODO [multi-tenancy] replace this with config service config documents.Config repo documents.Repository - coreDocProcessor coredocument.Processor notifier notification.Sender anchorRepository anchors.AnchorRepository identityService identity.Service + queueSrv queue.TaskQueuer + txService transactions.Service } // DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo documents.Repository, processor coredocument.Processor, anchorRepository anchors.AnchorRepository, identityService identity.Service) Service { - return service{config: config, repo: repo, coreDocProcessor: processor, notifier: notification.NewWebhookSender(config), anchorRepository: anchorRepository, identityService: identityService} +func DefaultService( + config config.Configuration, + repo documents.Repository, + anchorRepository anchors.AnchorRepository, + identityService identity.Service, + queueSrv queue.TaskQueuer, + txService transactions.Service) Service { + return service{ + config: config, + repo: repo, + notifier: notification.NewWebhookSender(config), + anchorRepository: anchorRepository, + identityService: identityService, + queueSrv: queueSrv, + txService: txService, + } } // DeriveFromCoreDocument takes a core document and returns a purchase order @@ -98,14 +115,8 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(tenantID, po.CoreDocument.CurrentVersion, po) + err = s.repo.Create(common.DummyIdentity.Bytes(), po.CoreDocument.CurrentVersion, po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -114,53 +125,48 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, error) { +func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { po, err := s.calculateDataRoot(nil, po, CreateValidator()) if err != nil { - return nil, err + return nil, uuid.Nil, err } - po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.updater) + cd, err := po.PackCoreDocument() if err != nil { - return nil, err + return nil, uuid.Nil, err } - return po, nil -} - -// updater wraps logic related to updating documents so that it can be executed as a closure -func (s service) updater(id []byte, model documents.Model) error { - // get tenant ID - tenantID, err := s.config.GetIdentityID() + txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, common.DummyIdentity, cd.CurrentVersion) if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, err } - return s.repo.Update(tenantID, id, model) + + return po, txID, nil } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, error) { +func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { cd, err := po.PackCoreDocument() if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(cd.DocumentIdentifier) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } po, err = s.calculateDataRoot(old, po, UpdateValidator()) if err != nil { - return nil, err + return nil, uuid.Nil, err } - po, err = documents.AnchorDocument(ctx, po, s.coreDocProcessor, s.updater) + txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, common.DummyIdentity, cd.CurrentVersion) if err != nil { - return nil, err + return nil, uuid.Nil, err } - return po, nil + return po, txID, nil } // DeriveFromCreatePayload derives purchase order from create payload @@ -271,12 +277,7 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P } func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *PurchaseOrder, err error) { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - doc, err := s.repo.Get(tenantID, version) + doc, err := s.repo.Get(common.DummyIdentity.Bytes(), version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -390,12 +391,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - + tenantID := common.DummyIdentity.Bytes() // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(tenantID, cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { err = s.repo.Create(tenantID, cd.DocumentIdentifier, model) @@ -426,13 +422,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - err = s.repo.Update(tenantID, doc.CurrentVersion, model) + err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -454,10 +444,5 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C // Exists checks if an purchase order exists func (s service) Exists(documentID []byte) bool { - // get tenant ID - tenantID, err := s.config.GetIdentityID() - if err != nil { - return false - } - return s.repo.Exists(tenantID, documentID) + return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 0c3b7e090..513aa02d6 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -7,27 +7,30 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) var ( + tenantID = common.DummyIdentity.Bytes() centIDBytes = utils.RandomSlice(identity.CentIDLength) key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} @@ -49,20 +52,23 @@ func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { c.On("GetIdentityID").Return(centIDBytes, nil) idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return idService, DefaultService(c, testRepo(), &testingcoredocument.MockCoreDocumentProcessor{}, &mockAnchorRepo{}, idService) + queueSrv := new(testingutils.MockQueue) + queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) + txService := ctx[transactions.BootstrappedService].(transactions.Service) + return idService, DefaultService(c, testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService) } func TestService_Update(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + _, poSrv := getServiceWithMockedLayers() ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) assert.Nil(t, err) // pack failed model := &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, err = poSrv.Update(ctxh, model) + _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -71,7 +77,7 @@ func TestService_Update(t *testing.T) { model = &testingdocuments.MockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = poSrv.Update(ctxh, model) + _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -84,12 +90,12 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) po.(*PurchaseOrder).CoreDocument = cd - testRepo().Create(centIDBytes, cd.CurrentVersion, po) + testRepo().Create(tenantID, cd.CurrentVersion, po) // calculate data root fails model = &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, err = poSrv.Update(ctxh, model) + _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -109,23 +115,15 @@ func TestService_Update(t *testing.T) { newData, err := poSrv.DerivePurchaseOrderData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", newInv).Return(nil).Once() - proc.On("RequestSignatures", ctxh, newInv).Return(nil).Once() - proc.On("PrepareForAnchoring", newInv).Return(nil).Once() - proc.On("AnchorDocument", newInv).Return(nil).Once() - proc.On("SendDocument", ctxh, newInv).Return(nil).Once() - poSrv.coreDocProcessor = proc - po, err = poSrv.Update(ctxh, newInv) - proc.AssertExpectations(t) + po, _, err = poSrv.Update(ctxh, newInv) assert.Nil(t, err) assert.NotNil(t, po) newCD, err := po.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(tenantID, newCD.PreviousVersion)) newData, err = poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -174,7 +172,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(centIDBytes, id, old) + err = testRepo().Create(tenantID, id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "0x010203040506", @@ -276,10 +274,10 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + _, poSrv := getServiceWithMockedLayers() // calculate data root fails - m, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) + m, _, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -287,34 +285,14 @@ func TestService_Create(t *testing.T) { // anchor fails po, err := poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - proc := &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(errors.New("anchoring failed")).Once() - poSrv.coreDocProcessor = proc - m, err = poSrv.Create(ctxh, po) - proc.AssertExpectations(t) - assert.Nil(t, m) - assert.Error(t, err) - assert.Contains(t, err.Error(), "anchoring failed") - - // success - po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) - assert.Nil(t, err) - proc = &testingcoredocument.MockCoreDocumentProcessor{} - proc.On("PrepareForSignatureRequests", po).Return(nil).Once() - proc.On("RequestSignatures", ctxh, po).Return(nil).Once() - proc.On("PrepareForAnchoring", po).Return(nil).Once() - proc.On("AnchorDocument", po).Return(nil).Once() - proc.On("SendDocument", ctxh, po).Return(nil).Once() - poSrv.coreDocProcessor = proc - m, err = poSrv.Create(ctxh, po) - proc.AssertExpectations(t) + m, _, err = poSrv.Create(ctxh, po) assert.Nil(t, err) assert.NotNil(t, m) newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(centIDBytes, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(centIDBytes, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) } func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, error) { @@ -365,7 +343,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er } if !skipSave { - err = testRepo().Create(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -410,7 +388,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(centIDBytes, i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) @@ -464,7 +442,7 @@ func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseO if err != nil { return nil, err } - err = testRepo().Create(centIDBytes, model.CoreDocument.CurrentVersion, model) + err = testRepo().Create(tenantID, model.CoreDocument.CurrentVersion, model) if err != nil { return nil, err } @@ -576,7 +554,7 @@ func createMockDocument() (*PurchaseOrder, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(centIDBytes, documentIdentifier, model) + err := testRepo().Create(tenantID, documentIdentifier, model) return model, err } @@ -603,7 +581,7 @@ func TestService_GetCurrentVersion(t *testing.T) { }, } - err = testRepo().Create(centIDBytes, doc.CoreDocument.NextVersion, po2) + err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, po2) assert.Nil(t, err) mod2, err := poSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) @@ -627,7 +605,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(centIDBytes, currentVersion, po) + err := testRepo().Create(tenantID, currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(utils.RandomSlice(32), currentVersion) @@ -649,7 +627,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(centIDBytes, currentVersion, po) + err := testRepo().Create(tenantID, currentVersion, po) assert.Nil(t, err) mod, err := poSrv.GetVersion(documentIdentifier, currentVersion) @@ -672,7 +650,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(centIDBytes, documentIdentifier, po) + err := testRepo().Create(tenantID, documentIdentifier, po) assert.Nil(t, err) exists := poSrv.Exists(documentIdentifier) @@ -727,7 +705,7 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - err = poSrv.repo.Create(centIDBytes, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) + err = poSrv.repo.Create(tenantID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) assert.Nil(t, err) po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) assert.Nil(t, po) diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index 94a23fbb4..ce311efa0 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -5,14 +5,12 @@ package documents_test import ( "context" "errors" - "testing" - - "github.com/centrifuge/go-centrifuge/contextutil" - "os" + "testing" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 52eaf998f..0be76299d 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -22,3 +22,11 @@ func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { func (Bootstrapper) TestTearDown() error { return nil } + +func (b PostBootstrapper) TestBootstrap(ctx map[string]interface{}) error { + return b.Bootstrap(ctx) +} + +func (PostBootstrapper) TestTearDown() error { + return nil +} diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index dba1ecf93..ca06bffc1 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -1,7 +1,10 @@ package nft import ( + "context" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" @@ -42,9 +45,29 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - ctx[BootstrappedPayObService] = newEthereumPaymentObligation(registry, idService, ethereum.GetClient(), cfg, queueSrv, setupMintListener, bindContract) + txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + if !ok { + return errors.New("transactions repository not initialised") + } + + client := ethereum.GetClient() + ctx[BootstrappedPayObService] = newEthereumPaymentObligation( + registry, + idService, + client, + cfg, queueSrv, + bindContract, + txService, func() (uint64, error) { + h, err := client.GetEthClient().HeaderByNumber(context.Background(), nil) + if err != nil { + return 0, err + } + + return h.Number.Uint64(), nil + }) + // queue task - task := newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext) + task := newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext, txService) queueSrv.RegisterTaskType(task.TaskTypeName(), task) return nil } diff --git a/nft/bootstrapper_test.go b/nft/bootstrapper_test.go index 1b6cb7fdc..0c0e3f84e 100644 --- a/nft/bootstrapper_test.go +++ b/nft/bootstrapper_test.go @@ -3,11 +3,32 @@ package nft import ( + "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) +var ctx = map[string]interface{}{} + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &storage.Bootstrapper{}, + transactions.Bootstrapper{}, + } + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + func TestBootstrapper_Bootstrap(t *testing.T) { err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) assert.Error(t, err, "Should throw an error because of empty context") diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index fb0d2c026..1f0e94fa6 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -1,9 +1,9 @@ package nft import ( - "context" "encoding/hex" "math/big" + "time" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" @@ -11,15 +11,14 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - - "time" - logging "github.com/ipfs/go-log" + "github.com/satori/go.uuid" ) var log = logging.Logger("nft") @@ -44,25 +43,34 @@ type ethereumPaymentObligation struct { registry *documents.ServiceRegistry identityService identity.Service ethClient ethereum.Client + // TODO [multi-tenancy] replace this with config service - config Config - queue *queue.Server - setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error) - bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) + config Config + queue queue.TaskQueuer + bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) + txService transactions.Service + blockHeightFunc func() (height uint64, err error) } // newEthereumPaymentObligation creates ethereumPaymentObligation given the parameters -func newEthereumPaymentObligation(registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, config Config, - queue *queue.Server, - setupMintListener func(config Config, queue *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error), bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error)) *ethereumPaymentObligation { +func newEthereumPaymentObligation( + registry *documents.ServiceRegistry, + identityService identity.Service, + ethClient ethereum.Client, + config Config, + queue queue.TaskQueuer, + bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error), + txService transactions.Service, + blockHeightFunc func() (uint64, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ - registry: registry, - identityService: identityService, - ethClient: ethClient, - config: config, - setupMintListener: setupMintListener, - bindContract: bindContract, - queue: queue, + registry: registry, + identityService: identityService, + ethClient: ethClient, + config: config, + bindContract: bindContract, + queue: queue, + txService: txService, + blockHeightFunc: blockHeightFunc, } } @@ -109,7 +117,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, deposi } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) { +func (s *ethereumPaymentObligation) MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { requestData, err := s.prepareMintRequest(documentID, depositAddress, proofFields) if err != nil { @@ -122,14 +130,13 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, } contract, err := s.bindContract(common.HexToAddress(registryAddress), s.ethClient) - if err != nil { return nil, err } - watch, err := s.setupMintListener(s.config, s.queue, requestData.TokenID, registryAddress) + txID, err := s.queueTask(tenantID, requestData.TokenID, registryAddress) if err != nil { - return nil, err + return nil, errors.New("failed to queue task: %v", err) } err = s.sendMintTransaction(contract, opts, requestData) @@ -137,36 +144,31 @@ func (s *ethereumPaymentObligation) MintNFT(documentID []byte, registryAddress, return nil, err } - return watch, nil + return &MintNFTResponse{ + TransactionID: txID.String(), + TokenID: requestData.TokenID.String(), + }, nil } -// setUpMintEventListener sets up the listened for the "PaymentObligationMinted" event to notify the upstream code -// about successful minting of an NFt -func setupMintListener(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (confirmations chan *watchTokenMinted, err error) { - confirmations = make(chan *watchTokenMinted) - conn := ethereum.GetClient() - - h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) +func (s *ethereumPaymentObligation) queueTask(tenantID common.Address, tokenID *big.Int, registryAddress string) (txID uuid.UUID, err error) { + height, err := s.blockHeightFunc() if err != nil { - return nil, err + return txID, err } - asyncRes, err := qs.EnqueueJob(mintingConfirmationTaskName, map[string]interface{}{ - tokenIDParam: hex.EncodeToString(tokenID.Bytes()), - queue.BlockHeightParam: h.Number.Uint64(), - registryAddressParam: registryAddress, - }) + tx, err := s.txService.CreateTransaction(tenantID, "Mint NFT") if err != nil { - return nil, err + return txID, err } - go waitAndRouteNFTApprovedEvent(config.GetEthereumContextWaitTimeout(), asyncRes, tokenID, confirmations) - return confirmations, nil -} + _, err = s.queue.EnqueueJob(mintingConfirmationTaskName, map[string]interface{}{ + transactions.TxIDParam: tx.ID.String(), + tenantIDParam: tenantID.String(), + tokenIDParam: hex.EncodeToString(tokenID.Bytes()), + queue.BlockHeightParam: height, + registryAddressParam: registryAddress, + }) -// waitAndRouteNFTApprovedEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteNFTApprovedEvent(timeout time.Duration, asyncRes queue.TaskResult, tokenID *big.Int, confirmations chan<- *watchTokenMinted) { - _, err := asyncRes.Get(timeout) - confirmations <- &watchTokenMinted{tokenID, err} + return tx.ID, err } // sendMintTransaction sends the actual transaction to mint the NFT diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index b194fa56f..8509ccc19 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -6,19 +6,20 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" - "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/gocelery" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -136,14 +137,14 @@ func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address func TestPaymentObligationService(t *testing.T) { tests := []struct { name string - mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig) + mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue) request *nftpb.NFTMintRequest err error result string }{ { "happypath", - func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig) { + func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue) { coreDoc := coredocument.New() coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) @@ -162,8 +163,9 @@ func TestPaymentObligationService(t *testing.T) { ).Return(&types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") - - return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock + queueSrv := new(testingutils.MockQueue) + queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) + return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv }, &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, nil, @@ -171,20 +173,20 @@ func TestPaymentObligationService(t *testing.T) { }, } + txService := ctx[transactions.BootstrappedService].(transactions.Service) + registry := documents.NewServiceRegistry() for _, test := range tests { t.Run(test.name, func(t *testing.T) { // get mocks - docService, paymentOb, idService, ethClient, mockCfg := test.mocker() + docService, paymentOb, idService, ethClient, mockCfg, queueSrv := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) - confirmations := make(chan *watchTokenMinted) - service := newEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, nil, func(config Config, qs *queue.Server, tokenID *big.Int, registryAddress string) (chan *watchTokenMinted, error) { - return confirmations, nil - }, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + service := newEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, queueSrv, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil - }) - _, err := service.MintNFT(decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + }, txService, func() (uint64, error) { return 10, nil }) + tenantID := common.Address([20]byte{1, 2}) + _, err := service.MintNFT(tenantID, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { @@ -195,6 +197,7 @@ func TestPaymentObligationService(t *testing.T) { idService.AssertExpectations(t) ethClient.AssertExpectations(t) mockCfg.AssertExpectations(t) + queueSrv.AssertExpectations(t) }) } } diff --git a/nft/handler.go b/nft/handler.go index a68f62b72..87ad6d388 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -3,11 +3,11 @@ package nft import ( "context" - "github.com/ethereum/go-ethereum/common" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" ) @@ -33,21 +33,25 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ } identifier, err := hexutil.Decode(request.Identifier) if err != nil { - return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) + return nil, centerrors.New(code.Unknown, err.Error()) } - confirmation, err := g.service.MintNFT(identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) + tenantID := ccommon.DummyIdentity + resp, err := g.service.MintNFT(tenantID, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) if err != nil { - return &nftpb.NFTMintResponse{}, centerrors.New(code.Unknown, err.Error()) + return nil, centerrors.New(code.Unknown, err.Error()) } - watchToken := <-confirmation - return &nftpb.NFTMintResponse{TokenId: watchToken.TokenID.String()}, watchToken.Err + + return &nftpb.NFTMintResponse{ + TokenId: resp.TokenID, + TransactionId: resp.TransactionID, + }, nil } func validateParameters(request *nftpb.NFTMintRequest) error { if !common.IsHexAddress(request.RegistryAddress) { - return centerrors.New(code.Unknown, "RegistryAddress is not a valid Ethereum address") + return centerrors.New(code.Unknown, "registryAddress is not a valid Ethereum address") } if !common.IsHexAddress(request.DepositAddress) { diff --git a/nft/handler_test.go b/nft/handler_test.go index 1f59b3249..8da9bd7c6 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -4,44 +4,41 @@ package nft import ( "context" - "testing" - "math/big" + "testing" + ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) -type MockPaymentObligationService struct { +type mockPaymentObligationService struct { mock.Mock } -func (m *MockPaymentObligationService) MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) { - args := m.Called(documentID, registryAddress, depositAddress, proofFields) - return args.Get(0).(chan *watchTokenMinted), args.Error(1) +func (m *mockPaymentObligationService) MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { + args := m.Called(tenantID, documentID, registryAddress, depositAddress, proofFields) + resp, _ := args.Get(0).(*MintNFTResponse) + return resp, args.Error(1) } func TestNFTMint_success(t *testing.T) { nftMintRequest := getTestSetupData() - mockService := &MockPaymentObligationService{} + mockService := &mockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) - confirmations := make(chan *watchTokenMinted) - mockService. - On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return(confirmations, nil) - tokID := big.NewInt(1) - go func() { - confirmations <- &watchTokenMinted{tokID, nil} - }() + nftResponse := &MintNFTResponse{TokenID: tokID.String()} + mockService. + On("MintNFT", ccommon.DummyIdentity, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + Return(nftResponse, nil) handler := grpcHandler{mockService} nftMintResponse, err := handler.MintNFT(context.Background(), nftMintRequest) - mockService.AssertExpectations(t) assert.Nil(t, err, "mint nft should be successful") assert.Equal(t, tokID.String(), nftMintResponse.TokenId, "TokenID should have a dummy value") @@ -50,19 +47,18 @@ func TestNFTMint_success(t *testing.T) { func TestNFTMint_InvalidIdentifier(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.Identifier = "32321" - handler := grpcHandler{&MockPaymentObligationService{}} + handler := grpcHandler{&mockPaymentObligationService{}} _, err := handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid identifier should throw an error") } func TestNFTMint_ServiceError(t *testing.T) { nftMintRequest := getTestSetupData() - mockService := &MockPaymentObligationService{} + mockService := &mockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) - confirmations := make(chan *watchTokenMinted) mockService. - On("MintNFT", docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return(confirmations, errors.New("service error")) + On("MintNFT", ccommon.DummyIdentity, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + Return(nil, errors.New("service error")) handler := grpcHandler{mockService} _, err := handler.MintNFT(context.Background(), nftMintRequest) @@ -73,13 +69,13 @@ func TestNFTMint_ServiceError(t *testing.T) { func TestNFTMint_InvalidAddresses(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.RegistryAddress = "0x1234" - handler := grpcHandler{&MockPaymentObligationService{}} + handler := grpcHandler{&mockPaymentObligationService{}} _, err := handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid registry address should throw an error") nftMintRequest = getTestSetupData() nftMintRequest.DepositAddress = "abc" - handler = grpcHandler{&MockPaymentObligationService{}} + handler = grpcHandler{&mockPaymentObligationService{}} _, err = handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid deposit address should throw an error") } diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 2469ccb8e..9bba7b775 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -18,6 +19,7 @@ const ( mintingConfirmationTaskName string = "MintingConfirmationTaskName" tokenIDParam string = "TokenIDParam" registryAddressParam string = "RegistryAddressParam" + tenantIDParam string = "Tenant ID" ) // paymentObligationMintedFilterer filters the approved NFTs @@ -29,23 +31,28 @@ type paymentObligationMintedFilterer interface { // mintingConfirmationTask confirms the minting of a payment obligation NFT type mintingConfirmationTask struct { + transactions.BaseTask + //task parameter - TokenID string - BlockHeight uint64 - RegistryAddress string - Timeout time.Duration + tenantID common.Address + tokenID string + blockHeight uint64 + registryAddress string + timeout time.Duration //state - EthContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) } func newMintingConfirmationTask( timeout time.Duration, ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), + txService transactions.Service, ) *mintingConfirmationTask { return &mintingConfirmationTask{ - Timeout: timeout, - EthContextInitializer: ethContextInitializer, + timeout: timeout, + ethContextInitializer: ethContextInitializer, + BaseTask: transactions.BaseTask{TxService: txService}, } } @@ -57,39 +64,49 @@ func (nftc *mintingConfirmationTask) TaskTypeName() string { // Copy returns a new instance of mintingConfirmationTask func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { return &mintingConfirmationTask{ - nftc.TokenID, - nftc.BlockHeight, - nftc.RegistryAddress, - nftc.Timeout, - nftc.EthContextInitializer, + timeout: nftc.timeout, + ethContextInitializer: nftc.ethContextInitializer, + BaseTask: transactions.BaseTask{TxService: nftc.TxService}, }, nil } // ParseKwargs - define a method to parse CentID func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + err = nftc.ParseTransactionID(kwargs) + if err != nil { + return err + } + + tenantID, ok := kwargs[tenantIDParam].(string) + if !ok { + return errors.New("missing tenant ID") + } + + nftc.tenantID = common.HexToAddress(tenantID) + // parse TokenID tokenID, ok := kwargs[tokenIDParam] if !ok { return errors.New("undefined kwarg " + tokenIDParam) } - nftc.TokenID, ok = tokenID.(string) + nftc.tokenID, ok = tokenID.(string) if !ok { return errors.New("malformed kwarg [%s]", tokenIDParam) } - // parse BlockHeight - nftc.BlockHeight, err = queue.ParseBlockHeight(kwargs) + // parse blockHeight + nftc.blockHeight, err = queue.ParseBlockHeight(kwargs) if err != nil { return err } - //parse RegistryAddress + //parse registryAddress registryAddress, ok := kwargs[registryAddressParam] if !ok { return errors.New("undefined kwarg " + registryAddressParam) } - nftc.RegistryAddress, ok = registryAddress.(string) + nftc.registryAddress, ok = registryAddress.(string) if !ok { return errors.New("malformed kwarg [%s]", registryAddressParam) } @@ -101,28 +118,35 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) if err != nil { return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } - nftc.Timeout = td + nftc.timeout = td } return nil } // RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. -func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.TokenID) - - ethContext, _ := nftc.EthContextInitializer(nftc.Timeout) +func (nftc *mintingConfirmationTask) RunTask() (resp interface{}, err error) { + log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.tokenID) + ethContext, cancelF := nftc.ethContextInitializer(nftc.timeout) + defer cancelF() fOpts := &bind.FilterOpts{ Context: ethContext, - Start: nftc.BlockHeight, + Start: nftc.blockHeight, } - var filter paymentObligationMintedFilterer - var err error + defer func() { + if err != nil { + log.Infof("failed to mint NFT: %v\n", err) + } else { + log.Infof("NFT minted successfully: %v\n", nftc.tokenID) + } - filter, err = bindContract(common.HexToAddress(nftc.RegistryAddress), ethereum.GetClient()) + err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) + }() + var filter paymentObligationMintedFilterer + filter, err = bindContract(common.HexToAddress(nftc.registryAddress), ethereum.GetClient()) if err != nil { return nil, err } @@ -135,7 +159,7 @@ func (nftc *mintingConfirmationTask) RunTask() (interface{}, error) { err = utils.LookForEvent(iter) if err == nil { - log.Infof("Received filtered event NFT minted for token [%s] \n", nftc.TokenID) + log.Infof("Received filtered event NFT minted for token [%s] \n", nftc.tokenID) return iter.Event, nil } diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go index 075bdf828..b8996b3c5 100644 --- a/nft/minting_confirmation_task_test.go +++ b/nft/minting_confirmation_task_test.go @@ -6,8 +6,11 @@ import ( "encoding/hex" "testing" + "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -16,8 +19,11 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { tokenId := hex.EncodeToString(utils.RandomSlice(256)) blockHeight := uint64(12) registryAddress := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" + txID := uuid.Must(uuid.NewV4()).String() kwargs := map[string]interface{}{ + transactions.TxIDParam: txID, + tenantIDParam: common.DummyIdentity.String(), tokenIDParam: tokenId, queue.BlockHeightParam: blockHeight, registryAddressParam: registryAddress, @@ -28,9 +34,11 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { err = task.ParseKwargs(decoded) assert.Nil(t, err, "parsing should be successful") - assert.Equal(t, tokenId, task.TokenID, "tokenId should be parsed correctly") - assert.Equal(t, blockHeight, task.BlockHeight, "blockHeight should be parsed correctly") - assert.Equal(t, registryAddress, task.RegistryAddress, "registryAddress should be parsed correctly") + assert.Equal(t, common.DummyIdentity, task.tenantID) + assert.Equal(t, txID, task.TxID.String()) + assert.Equal(t, tokenId, task.tokenID, "tokenId should be parsed correctly") + assert.Equal(t, blockHeight, task.blockHeight, "blockHeight should be parsed correctly") + assert.Equal(t, registryAddress, task.registryAddress, "registryAddress should be parsed correctly") } diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index b833a7fd1..a6e731f30 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -1,15 +1,16 @@ package nft -import "math/big" +import "github.com/ethereum/go-ethereum/common" // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(documentID []byte, registryAddress, depositAddress string, proofFields []string) (<-chan *watchTokenMinted, error) + MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) } -type watchTokenMinted struct { - TokenID *big.Int - Err error +// MintNFTResponse holds tokenID and transaction ID. +type MintNFTResponse struct { + TokenID string + TransactionID string } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 561dd6ee5..5cf6192d9 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,28 +8,29 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/stretchr/testify/assert" - cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/log" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/stretchr/testify/assert" ) var registry *documents.ServiceRegistry var cfg config.Configuration var idService identity.Service var payOb nft.PaymentObligation +var txService transactions.Service func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") @@ -38,6 +39,7 @@ func TestMain(m *testing.M) { idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) + txService = ctx[transactions.BootstrappedService].(transactions.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -66,21 +68,22 @@ func TestPaymentObligationService_mint(t *testing.T) { }, }) assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, err := invoiceService.Create(contextHeader, model) + modelUpdated, txID, err := invoiceService.Create(contextHeader, model) + err = txService.WaitForTransaction(ccommon.DummyIdentity, txID) + assert.Nil(t, err) // get ID ID, err := modelUpdated.ID() assert.Nil(t, err, "should not error out when getting invoice ID") // call mint // assert no error - confirmations, err := payOb.MintNFT( + resp, err := payOb.MintNFT( + ccommon.DummyIdentity, ID, cfg.GetContractAddress("paymentObligation").String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, ) assert.Nil(t, err, "should not error out when minting an invoice") - tokenConfirm := <-confirmations - assert.Nil(t, tokenConfirm.Err, "should not error out when minting an invoice") - assert.NotNil(t, tokenConfirm.TokenID, "token id should be present") + assert.NotNil(t, resp.TokenID, "token id should be present") } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index e8ddee7cb..a554401c0 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -8,11 +8,6 @@ import ( "github.com/centrifuge/go-centrifuge/p2p/receiver" ) -// Bootstrapped constants that are used as key in bootstrap context -const ( - BootstrappedP2PClient string = "BootstrappedP2PClient" -) - // Bootstrapper implements Bootstrapper with p2p details type Bootstrapper struct{} @@ -32,6 +27,6 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return receiver.New(cfg, registry) }} ctx[bootstrap.BootstrappedP2PServer] = srv - ctx[BootstrappedP2PClient] = srv + ctx[bootstrap.BootstrappedP2PClient] = srv return nil } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 7a9ed22d4..9c9b08170 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -30,7 +30,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { _, ok := m[bootstrap.BootstrappedP2PServer].(node.Server) assert.True(t, ok) - assert.NotNil(t, m[BootstrappedP2PClient]) - _, ok = m[BootstrappedP2PClient].(Client) + assert.NotNil(t, m[bootstrap.BootstrappedP2PClient]) + _, ok = m[bootstrap.BootstrappedP2PClient].(Client) assert.True(t, ok) } diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index b7bfe36e7..72d1ba48f 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -4,11 +4,10 @@ package receiver import ( "context" + "os" "strconv" "testing" - "os" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -19,8 +18,10 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" @@ -39,6 +40,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &queue.Bootstrapper{}, + transactions.Bootstrapper{}, documents.Bootstrapper{}, } ctx := make(map[string]interface{}) diff --git a/p2p/server_test.go b/p2p/server_test.go index 6c01bee2d..790424827 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,14 +10,14 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/p2p/receiver" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" - - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/transactions" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" ) @@ -31,6 +31,8 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &queue.Bootstrapper{}, + transactions.Bootstrapper{}, documents.Bootstrapper{}, } ctx := make(map[string]interface{}) diff --git a/protobufs/gen/go/invoice/service.pb.go b/protobufs/gen/go/invoice/service.pb.go index 335478575..faca5b352 100644 --- a/protobufs/gen/go/invoice/service.pb.go +++ b/protobufs/gen/go/invoice/service.pb.go @@ -37,7 +37,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{0} + return fileDescriptor_service_3d2a42d875b08717, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{1} + return fileDescriptor_service_3d2a42d875b08717, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -122,7 +122,7 @@ func (m *InvoiceCreatePayload) Reset() { *m = InvoiceCreatePayload{} } func (m *InvoiceCreatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceCreatePayload) ProtoMessage() {} func (*InvoiceCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{2} + return fileDescriptor_service_3d2a42d875b08717, []int{2} } func (m *InvoiceCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceCreatePayload.Unmarshal(m, b) @@ -169,7 +169,7 @@ func (m *InvoiceUpdatePayload) Reset() { *m = InvoiceUpdatePayload{} } func (m *InvoiceUpdatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceUpdatePayload) ProtoMessage() {} func (*InvoiceUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{3} + return fileDescriptor_service_3d2a42d875b08717, []int{3} } func (m *InvoiceUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceUpdatePayload.Unmarshal(m, b) @@ -222,7 +222,7 @@ func (m *InvoiceResponse) Reset() { *m = InvoiceResponse{} } func (m *InvoiceResponse) String() string { return proto.CompactTextString(m) } func (*InvoiceResponse) ProtoMessage() {} func (*InvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{4} + return fileDescriptor_service_3d2a42d875b08717, []int{4} } func (m *InvoiceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceResponse.Unmarshal(m, b) @@ -262,6 +262,7 @@ type ResponseHeader struct { VersionId string `protobuf:"bytes,2,opt,name=version_id,json=versionId,proto3" json:"version_id,omitempty"` State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` Collaborators []string `protobuf:"bytes,4,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + TransactionId string `protobuf:"bytes,5,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -271,7 +272,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{5} + return fileDescriptor_service_3d2a42d875b08717, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -319,6 +320,13 @@ func (m *ResponseHeader) GetCollaborators() []string { return nil } +func (m *ResponseHeader) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + type InvoiceData struct { InvoiceStatus string `protobuf:"bytes,25,opt,name=invoice_status,json=invoiceStatus,proto3" json:"invoice_status,omitempty"` // invoice number or reference number @@ -362,7 +370,7 @@ func (m *InvoiceData) Reset() { *m = InvoiceData{} } func (m *InvoiceData) String() string { return proto.CompactTextString(m) } func (*InvoiceData) ProtoMessage() {} func (*InvoiceData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_1b382e1e9695134b, []int{6} + return fileDescriptor_service_3d2a42d875b08717, []int{6} } func (m *InvoiceData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceData.Unmarshal(m, b) @@ -731,66 +739,67 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ Metadata: "invoice/service.proto", } -func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_1b382e1e9695134b) } - -var fileDescriptor_service_1b382e1e9695134b = []byte{ - // 925 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4f, 0x6f, 0xdb, 0xc6, - 0x13, 0x85, 0x6c, 0x47, 0x7f, 0x46, 0x92, 0x1d, 0x6f, 0xe4, 0x78, 0x4d, 0x24, 0x3f, 0x33, 0xfa, - 0xa5, 0x85, 0x9a, 0x26, 0x22, 0xe0, 0xa2, 0x28, 0x5a, 0xa0, 0x07, 0xc7, 0x01, 0x5c, 0x1f, 0x1a, - 0x18, 0x74, 0xdb, 0x43, 0x2e, 0xc2, 0x8a, 0x1c, 0x29, 0x0b, 0x88, 0x5c, 0x96, 0x5c, 0xba, 0x56, - 0x82, 0x5c, 0x8a, 0xa2, 0xa7, 0x9e, 0xdc, 0x7e, 0xb3, 0x7e, 0x85, 0x7e, 0x86, 0x9e, 0x8b, 0xfd, - 0x43, 0x8a, 0x92, 0x0c, 0xbb, 0x3d, 0x11, 0xfb, 0xe6, 0xed, 0xcc, 0x1b, 0xee, 0xec, 0x5b, 0xd8, - 0xe3, 0xf1, 0xa5, 0xe0, 0x01, 0x7a, 0x19, 0xa6, 0x97, 0x3c, 0xc0, 0x61, 0x92, 0x0a, 0x29, 0x48, - 0xc3, 0xc2, 0xce, 0xa3, 0xa9, 0x10, 0xd3, 0x19, 0x7a, 0x2c, 0xe1, 0x1e, 0x8b, 0x63, 0x21, 0x99, - 0xe4, 0x22, 0xce, 0x0c, 0xcd, 0x39, 0xb4, 0x51, 0xbd, 0x1a, 0xe7, 0x13, 0x4f, 0xf2, 0x08, 0x33, - 0xc9, 0xa2, 0xc4, 0x12, 0x9e, 0xeb, 0x4f, 0xf0, 0x62, 0x8a, 0xf1, 0x8b, 0xec, 0x27, 0x36, 0x9d, - 0x62, 0xea, 0x89, 0x44, 0xa7, 0x58, 0x4f, 0xd7, 0x7f, 0x0e, 0x70, 0x8a, 0xd2, 0xc7, 0x1f, 0x73, - 0xcc, 0x24, 0xf9, 0x1f, 0x00, 0x0f, 0x31, 0x96, 0x7c, 0xc2, 0x31, 0xa5, 0x35, 0xb7, 0x36, 0x68, - 0xf9, 0x15, 0xa4, 0xff, 0x2d, 0xec, 0x9e, 0xa2, 0xfc, 0x01, 0xd3, 0x8c, 0x8b, 0xf8, 0x5f, 0x6e, - 0x22, 0x14, 0x1a, 0x97, 0x66, 0x07, 0xdd, 0xd0, 0xc1, 0x62, 0xd9, 0x9f, 0x40, 0xef, 0xcc, 0x34, - 0x7d, 0x92, 0x22, 0x93, 0x78, 0xce, 0xe6, 0x33, 0xc1, 0x42, 0xf2, 0x14, 0xba, 0x81, 0x98, 0xcd, - 0xd8, 0x58, 0xa4, 0x4c, 0x8a, 0x34, 0xa3, 0x35, 0x77, 0x73, 0xd0, 0xf2, 0x97, 0x41, 0x32, 0x80, - 0xad, 0x90, 0x49, 0xa6, 0x93, 0xb6, 0x8f, 0x7a, 0x43, 0xfb, 0xff, 0x86, 0x36, 0xe5, 0x2b, 0x26, - 0x99, 0xaf, 0x19, 0xfd, 0x5f, 0x6b, 0x65, 0xa1, 0xef, 0x93, 0xb0, 0x52, 0xe8, 0x2e, 0xe9, 0x6b, - 0x42, 0x36, 0x6e, 0x13, 0xb2, 0x79, 0xa7, 0x90, 0x19, 0xec, 0x58, 0xd0, 0xc7, 0x2c, 0x11, 0x71, - 0x86, 0xc4, 0x83, 0xfa, 0x5b, 0x64, 0xa1, 0x2d, 0xdf, 0x3e, 0xda, 0x2f, 0xb7, 0x17, 0x94, 0x6f, - 0x74, 0xd8, 0xb7, 0xb4, 0xff, 0xd0, 0xf6, 0x6f, 0x35, 0xd8, 0x5e, 0x4e, 0x42, 0x0e, 0xa1, 0x1d, - 0x8a, 0x20, 0x8f, 0x30, 0x96, 0x23, 0x1e, 0x16, 0x1d, 0x17, 0xd0, 0x59, 0x48, 0x1e, 0x03, 0xd8, - 0xd3, 0x51, 0x71, 0x73, 0x5e, 0x2d, 0x8b, 0x9c, 0x85, 0xa4, 0x07, 0xf7, 0x32, 0xc9, 0x24, 0xea, - 0x5e, 0x5b, 0xbe, 0x59, 0xac, 0xff, 0xa6, 0xad, 0x1b, 0x7e, 0x53, 0xff, 0xef, 0x3a, 0xb4, 0x2b, - 0x22, 0xc9, 0x47, 0xb0, 0x6d, 0xb5, 0x8f, 0x54, 0x9a, 0x3c, 0xa3, 0x07, 0x3a, 0x69, 0xd7, 0xa2, - 0x17, 0x1a, 0xac, 0xd2, 0xe2, 0x3c, 0x1a, 0x97, 0xe7, 0x54, 0xd0, 0x5e, 0x6b, 0x50, 0x75, 0x96, - 0x61, 0x1c, 0x62, 0x3a, 0x8a, 0x59, 0x54, 0xe8, 0x03, 0x03, 0xbd, 0x66, 0x11, 0x92, 0xff, 0x43, - 0xd7, 0x12, 0x32, 0x99, 0x22, 0x4a, 0xba, 0xa5, 0x29, 0x1d, 0x03, 0x5e, 0x68, 0xac, 0x92, 0x25, - 0xe0, 0x72, 0x4e, 0xef, 0x55, 0xb3, 0x9c, 0x70, 0x39, 0x57, 0x6a, 0x2c, 0xe1, 0x1d, 0x4f, 0x02, - 0x11, 0x22, 0xad, 0x1b, 0x35, 0x06, 0x7d, 0x63, 0xc0, 0x0a, 0x2d, 0x10, 0x79, 0x2c, 0xd3, 0x39, - 0x6d, 0x54, 0x69, 0x27, 0x06, 0x54, 0xb4, 0x14, 0x03, 0x9e, 0x70, 0x75, 0x1e, 0x5a, 0x77, 0xd3, - 0xd0, 0x4a, 0x54, 0x4b, 0xff, 0x04, 0xee, 0x2f, 0x68, 0x56, 0x7d, 0x4b, 0x13, 0x77, 0x4a, 0xdc, - 0x36, 0xb0, 0x94, 0x51, 0xf7, 0x00, 0x2b, 0x19, 0x75, 0x1b, 0x9f, 0xc2, 0xee, 0x82, 0x56, 0x74, - 0xd2, 0xd6, 0xcc, 0x45, 0xa9, 0xa2, 0x99, 0x25, 0x72, 0xd1, 0x4f, 0x67, 0x85, 0x5c, 0xb4, 0xe4, - 0x40, 0x33, 0xc8, 0xd3, 0x14, 0xe3, 0x60, 0x4e, 0xbb, 0x9a, 0x53, 0xae, 0xc9, 0x13, 0xe8, 0x4c, - 0x53, 0x91, 0x65, 0x23, 0x16, 0x29, 0x36, 0xdd, 0x76, 0x6b, 0x83, 0x4d, 0xbf, 0xad, 0xb1, 0x63, - 0x0d, 0xa9, 0xf9, 0x8b, 0x51, 0x16, 0x84, 0x1d, 0x4d, 0x68, 0xc5, 0x28, 0x17, 0x61, 0xc9, 0xae, - 0x8a, 0xf0, 0x7d, 0x13, 0x96, 0xec, 0xca, 0x86, 0x0f, 0xa0, 0xa9, 0xc2, 0xa9, 0x9a, 0xd0, 0x5d, - 0x1d, 0x6c, 0x48, 0x76, 0xe5, 0xab, 0x19, 0x7d, 0x04, 0xad, 0x52, 0x2b, 0x25, 0x66, 0xae, 0x4b, - 0x80, 0x3c, 0x84, 0xba, 0x39, 0x19, 0xfa, 0x40, 0x87, 0xec, 0x4a, 0xcd, 0x7b, 0xc2, 0xe6, 0x88, - 0xb4, 0x67, 0xe6, 0x5d, 0x2f, 0x94, 0xa3, 0x05, 0x22, 0x52, 0x37, 0x86, 0xee, 0x19, 0x47, 0xb3, - 0x4b, 0xf2, 0x39, 0x34, 0xc3, 0x1c, 0x47, 0xca, 0x63, 0xe8, 0x43, 0x7d, 0x41, 0x9d, 0xa1, 0x31, - 0xec, 0x61, 0x61, 0xd8, 0xc3, 0xef, 0x0a, 0xc3, 0xf6, 0x1b, 0x61, 0xae, 0xae, 0x02, 0x92, 0xaf, - 0xa1, 0xa3, 0xb6, 0x8c, 0x02, 0x6d, 0x83, 0x21, 0xdd, 0xbf, 0x73, 0x6b, 0x5b, 0xf1, 0x8d, 0x6b, - 0xea, 0x4b, 0x8b, 0x57, 0x32, 0x65, 0x23, 0x6d, 0x0c, 0xd4, 0x34, 0xa7, 0x11, 0x75, 0xd1, 0x8e, - 0x7e, 0xd9, 0x82, 0x9d, 0x57, 0xf6, 0x8a, 0x5f, 0x98, 0x37, 0x87, 0x44, 0x50, 0x37, 0xbb, 0xc9, - 0xe3, 0x55, 0x07, 0x59, 0xf2, 0x62, 0x87, 0xae, 0x86, 0x0b, 0x47, 0xe9, 0x3f, 0xbb, 0x3e, 0xee, - 0x39, 0xc4, 0xb0, 0x33, 0x97, 0xc5, 0xae, 0x25, 0xfe, 0xfc, 0xe7, 0x5f, 0xbf, 0x6f, 0x74, 0xfb, - 0x4d, 0xcf, 0xae, 0xbf, 0xaa, 0x3d, 0x23, 0xef, 0xa0, 0x6e, 0x9c, 0x77, 0xbd, 0xdc, 0x92, 0x23, - 0xdf, 0x52, 0xee, 0x0b, 0x5d, 0xce, 0xb0, 0xd7, 0xca, 0x39, 0xce, 0x5e, 0x51, 0xce, 0x7b, 0xbf, - 0x30, 0xf0, 0x0f, 0xaa, 0xf6, 0x1f, 0x35, 0xfd, 0xc6, 0xd9, 0x57, 0x8b, 0x38, 0x65, 0x85, 0xb5, - 0xa7, 0xec, 0x96, 0xea, 0xe7, 0xd7, 0xc7, 0x1f, 0x3b, 0x4f, 0x4f, 0x51, 0xba, 0xcc, 0xcd, 0x12, - 0x0c, 0xf8, 0x84, 0x07, 0xae, 0xf5, 0x45, 0x57, 0x4c, 0x56, 0xf5, 0x3c, 0x21, 0x87, 0x37, 0xea, - 0xf1, 0xde, 0xdb, 0x3d, 0x1f, 0x88, 0x80, 0xcd, 0x53, 0x94, 0xe4, 0x41, 0x55, 0xce, 0xdd, 0x3a, - 0xbe, 0xbc, 0x3e, 0x3e, 0x70, 0xf6, 0x95, 0x0e, 0xf9, 0x16, 0x5d, 0x73, 0xb3, 0xe4, 0x52, 0xe9, - 0x7d, 0x72, 0xf3, 0xaf, 0x78, 0x39, 0x80, 0x76, 0x20, 0xa2, 0x22, 0xf3, 0xcb, 0x8e, 0x1d, 0x85, - 0x73, 0x35, 0x5c, 0xe7, 0xb5, 0x37, 0x2d, 0x1b, 0x48, 0xc6, 0xe3, 0xba, 0x1e, 0xb8, 0xcf, 0xfe, - 0x09, 0x00, 0x00, 0xff, 0xff, 0x02, 0x88, 0x47, 0xdf, 0xaa, 0x08, 0x00, 0x00, +func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_3d2a42d875b08717) } + +var fileDescriptor_service_3d2a42d875b08717 = []byte{ + // 939 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0x1b, 0x45, + 0x1b, 0x96, 0x93, 0xd4, 0x3f, 0xaf, 0xed, 0xa4, 0x99, 0x3a, 0xcd, 0x66, 0xd5, 0x7e, 0xd9, 0xfa, + 0x2b, 0xc8, 0x94, 0xd6, 0x96, 0x82, 0x10, 0x02, 0x89, 0x83, 0x34, 0x95, 0x42, 0x0e, 0xa8, 0xa2, + 0x0d, 0x70, 0xd0, 0x13, 0x6b, 0xbc, 0xfb, 0xda, 0x1d, 0xc9, 0x3b, 0xb3, 0xcc, 0x8c, 0x43, 0xdc, + 0xaa, 0x27, 0x08, 0x71, 0x01, 0x81, 0x3b, 0xe1, 0x52, 0xb8, 0x05, 0xae, 0x81, 0x63, 0x34, 0x3f, + 0xeb, 0xdf, 0x28, 0x81, 0xa3, 0xd5, 0x3c, 0xef, 0xf3, 0xfe, 0x3c, 0xf3, 0xf3, 0x2c, 0xec, 0x31, + 0x7e, 0x29, 0x58, 0x82, 0x3d, 0x85, 0xf2, 0x92, 0x25, 0xd8, 0xcd, 0xa5, 0xd0, 0x82, 0x54, 0x3c, + 0x1c, 0x3e, 0x1a, 0x09, 0x31, 0x1a, 0x63, 0x8f, 0xe6, 0xac, 0x47, 0x39, 0x17, 0x9a, 0x6a, 0x26, + 0xb8, 0x72, 0xb4, 0xf0, 0xd0, 0x47, 0xed, 0x6a, 0x30, 0x19, 0xf6, 0x34, 0xcb, 0x50, 0x69, 0x9a, + 0xe5, 0x9e, 0xf0, 0xdc, 0x7e, 0x92, 0x17, 0x23, 0xe4, 0x2f, 0xd4, 0x4f, 0x74, 0x34, 0x42, 0xd9, + 0x13, 0xb9, 0x2d, 0xb1, 0x5e, 0xae, 0xfd, 0x1c, 0xe0, 0x14, 0x75, 0x8c, 0x3f, 0x4e, 0x50, 0x69, + 0xf2, 0x3f, 0x00, 0x96, 0x22, 0xd7, 0x6c, 0xc8, 0x50, 0x06, 0xa5, 0xa8, 0xd4, 0xa9, 0xc5, 0x0b, + 0x48, 0xfb, 0x5b, 0xd8, 0x3d, 0x45, 0xfd, 0x03, 0x4a, 0xc5, 0x04, 0xff, 0x97, 0x49, 0x24, 0x80, + 0xca, 0xa5, 0xcb, 0x08, 0x36, 0x6c, 0xb0, 0x58, 0xb6, 0x87, 0xd0, 0x3a, 0x73, 0xa2, 0x4f, 0x24, + 0x52, 0x8d, 0xe7, 0x74, 0x3a, 0x16, 0x34, 0x25, 0x4f, 0xa1, 0x99, 0x88, 0xf1, 0x98, 0x0e, 0x84, + 0xa4, 0x5a, 0x48, 0x15, 0x94, 0xa2, 0xcd, 0x4e, 0x2d, 0x5e, 0x06, 0x49, 0x07, 0xb6, 0x52, 0xaa, + 0xa9, 0x2d, 0x5a, 0x3f, 0x6a, 0x75, 0xfd, 0xfe, 0x75, 0x7d, 0xc9, 0x57, 0x54, 0xd3, 0xd8, 0x32, + 0xda, 0xbf, 0x96, 0x66, 0x8d, 0xbe, 0xcf, 0xd3, 0x85, 0x46, 0x77, 0x8d, 0xbe, 0x36, 0xc8, 0xc6, + 0x6d, 0x83, 0x6c, 0xde, 0x39, 0xc8, 0x18, 0x76, 0x3c, 0x18, 0xa3, 0xca, 0x05, 0x57, 0x48, 0x7a, + 0x50, 0x7e, 0x8b, 0x34, 0xf5, 0xed, 0xeb, 0x47, 0xfb, 0xb3, 0xf4, 0x82, 0xf2, 0x8d, 0x0d, 0xc7, + 0x9e, 0xf6, 0x1f, 0x64, 0xff, 0x51, 0x82, 0xed, 0xe5, 0x22, 0xe4, 0x10, 0xea, 0xa9, 0x48, 0x26, + 0x19, 0x72, 0xdd, 0x67, 0x69, 0xa1, 0xb8, 0x80, 0xce, 0x52, 0xf2, 0x18, 0xc0, 0x9f, 0x8e, 0x89, + 0xbb, 0xf3, 0xaa, 0x79, 0xe4, 0x2c, 0x25, 0x2d, 0xb8, 0xa7, 0x34, 0xd5, 0x68, 0xb5, 0xd6, 0x62, + 0xb7, 0x58, 0xdf, 0xa6, 0xad, 0x9b, 0xb6, 0xe9, 0x23, 0xd8, 0xd6, 0x92, 0x72, 0x45, 0x13, 0xed, + 0xcb, 0xdf, 0xb3, 0x45, 0x9a, 0x0b, 0xe8, 0x59, 0xda, 0xfe, 0xbb, 0x0c, 0xf5, 0x05, 0x2d, 0x26, + 0xcd, 0x4b, 0xec, 0x9b, 0x6e, 0x13, 0x15, 0x1c, 0xb8, 0x34, 0x8f, 0x5e, 0x58, 0x70, 0x91, 0xc6, + 0x27, 0xd9, 0x60, 0x76, 0x9c, 0x05, 0xed, 0xb5, 0x05, 0xcd, 0x06, 0x28, 0xe4, 0x29, 0xca, 0x3e, + 0xa7, 0x59, 0x21, 0x03, 0x1c, 0xf4, 0x9a, 0x66, 0x48, 0xfe, 0x0f, 0x4d, 0x4f, 0x50, 0x5a, 0x22, + 0xea, 0x60, 0xcb, 0x52, 0x1a, 0x0e, 0xbc, 0xb0, 0xd8, 0x42, 0x95, 0x84, 0xe9, 0xa9, 0xd7, 0xe1, + 0xab, 0x9c, 0x30, 0x3d, 0x35, 0xd3, 0x78, 0xc2, 0x3b, 0x96, 0x27, 0x22, 0xc5, 0xa0, 0xec, 0xa6, + 0x71, 0xe8, 0x1b, 0x07, 0x2e, 0xd0, 0x12, 0x31, 0xe1, 0x5a, 0x4e, 0x83, 0xca, 0x22, 0xed, 0xc4, + 0x81, 0x86, 0x26, 0x31, 0x61, 0x39, 0x33, 0xc7, 0x66, 0xe7, 0xae, 0x3a, 0xda, 0x0c, 0xb5, 0xa3, + 0x7f, 0x02, 0xf7, 0xe7, 0x34, 0x3f, 0x7d, 0xcd, 0x12, 0x77, 0x66, 0xb8, 0x17, 0xb0, 0x54, 0xd1, + 0x6a, 0x80, 0x95, 0x8a, 0x56, 0xc6, 0xa7, 0xb0, 0x3b, 0xa7, 0x15, 0x4a, 0xea, 0x96, 0x39, 0x6f, + 0x55, 0x88, 0x59, 0x22, 0x17, 0x7a, 0x1a, 0x2b, 0xe4, 0x42, 0x52, 0x08, 0xd5, 0x64, 0x22, 0x25, + 0xf2, 0x64, 0x1a, 0x34, 0x2d, 0x67, 0xb6, 0x26, 0x4f, 0xa0, 0x31, 0x92, 0x42, 0xa9, 0x3e, 0xcd, + 0x0c, 0x3b, 0xd8, 0x8e, 0x4a, 0x9d, 0xcd, 0xb8, 0x6e, 0xb1, 0x63, 0x0b, 0x99, 0x6b, 0xca, 0x51, + 0x17, 0x84, 0x1d, 0x4b, 0xa8, 0x71, 0xd4, 0xf3, 0xb0, 0xa6, 0x57, 0x45, 0xf8, 0xbe, 0x0b, 0x6b, + 0x7a, 0xe5, 0xc3, 0x07, 0x50, 0x35, 0x61, 0x69, 0x2e, 0xf2, 0xae, 0x0d, 0x56, 0x34, 0xbd, 0x8a, + 0xcd, 0x55, 0x7e, 0x04, 0xb5, 0xd9, 0xac, 0x01, 0x71, 0xd7, 0x7f, 0x06, 0x90, 0x87, 0x50, 0x76, + 0x27, 0x13, 0x3c, 0xb0, 0x21, 0xbf, 0x32, 0xcf, 0x22, 0xa7, 0x53, 0xc4, 0xa0, 0xe5, 0x9e, 0x85, + 0x5d, 0x18, 0xe3, 0x4b, 0x44, 0x66, 0x1e, 0x56, 0xb0, 0xe7, 0x8c, 0xcf, 0x2f, 0xc9, 0xe7, 0x50, + 0x4d, 0x27, 0xd8, 0x37, 0x56, 0x14, 0x3c, 0xb4, 0xef, 0x38, 0xec, 0x3a, 0x5f, 0xef, 0x16, 0xbe, + 0xde, 0xfd, 0xae, 0xf0, 0xf5, 0xb8, 0x92, 0x4e, 0xcc, 0x53, 0x40, 0xf2, 0x35, 0x34, 0x4c, 0x4a, + 0x3f, 0xb1, 0x6e, 0x99, 0x06, 0xfb, 0x77, 0xa6, 0xd6, 0x0d, 0xdf, 0x99, 0xab, 0x7d, 0xdb, 0x78, + 0xa5, 0x25, 0xed, 0x5b, 0xff, 0x08, 0x9c, 0x38, 0x8b, 0x98, 0x87, 0x76, 0xf4, 0xcb, 0x16, 0xec, + 0xbc, 0xf2, 0x4e, 0x70, 0xe1, 0x7e, 0x4d, 0x24, 0x83, 0xb2, 0xcb, 0x26, 0x8f, 0x57, 0x8d, 0x66, + 0xc9, 0xb2, 0xc3, 0x60, 0x35, 0x5c, 0x18, 0x4f, 0xfb, 0xd9, 0xf5, 0x71, 0x2b, 0x24, 0x8e, 0xad, + 0x22, 0xca, 0x23, 0x4f, 0xfc, 0xf9, 0xcf, 0xbf, 0x7e, 0xdb, 0x68, 0xb6, 0xab, 0x3d, 0xbf, 0xfe, + 0xaa, 0xf4, 0x8c, 0xbc, 0x83, 0xb2, 0x33, 0xe8, 0xf5, 0x76, 0x4b, 0xc6, 0x7d, 0x4b, 0xbb, 0x2f, + 0x6c, 0x3b, 0xc7, 0x5e, 0x6b, 0x17, 0x86, 0x7b, 0x45, 0xbb, 0xde, 0xfb, 0xb9, 0xcf, 0x7f, 0x30, + 0xbd, 0x7f, 0x2f, 0xd9, 0x5f, 0xa1, 0xff, 0xb9, 0x91, 0x70, 0xd6, 0x61, 0xed, 0x8f, 0x77, 0x4b, + 0xf7, 0xf3, 0xeb, 0xe3, 0x8f, 0xc3, 0xa7, 0xa7, 0xa8, 0x23, 0x1a, 0xa9, 0x1c, 0x13, 0x36, 0x64, + 0x49, 0xe4, 0xed, 0x33, 0x12, 0xc3, 0xd5, 0x79, 0x9e, 0x90, 0xc3, 0x1b, 0xe7, 0xe9, 0xbd, 0xf7, + 0x39, 0x1f, 0x88, 0x80, 0xcd, 0x53, 0xd4, 0xe4, 0xc1, 0xe2, 0x38, 0x77, 0xcf, 0xf1, 0xe5, 0xf5, + 0xf1, 0x41, 0xb8, 0x6f, 0xe6, 0xd0, 0x6f, 0x31, 0x72, 0x2f, 0x4b, 0x2f, 0xb5, 0xde, 0x27, 0x37, + 0x6f, 0xc5, 0xcb, 0x0e, 0xd4, 0x13, 0x91, 0x15, 0x95, 0x5f, 0x36, 0xfc, 0x55, 0x38, 0x37, 0x97, + 0xeb, 0xbc, 0xf4, 0xa6, 0xe6, 0x03, 0xf9, 0x60, 0x50, 0xb6, 0x17, 0xee, 0xb3, 0x7f, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x0c, 0x8d, 0xd7, 0x8a, 0xd1, 0x08, 0x00, 0x00, } diff --git a/protobufs/gen/go/nft/service.pb.go b/protobufs/gen/go/nft/service.pb.go index e16a63f6d..2cf544291 100644 --- a/protobufs/gen/go/nft/service.pb.go +++ b/protobufs/gen/go/nft/service.pb.go @@ -41,7 +41,7 @@ func (m *NFTMintRequest) Reset() { *m = NFTMintRequest{} } func (m *NFTMintRequest) String() string { return proto.CompactTextString(m) } func (*NFTMintRequest) ProtoMessage() {} func (*NFTMintRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_b4e252768b910acc, []int{0} + return fileDescriptor_service_66d4e2152d82b027, []int{0} } func (m *NFTMintRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintRequest.Unmarshal(m, b) @@ -91,6 +91,7 @@ func (m *NFTMintRequest) GetProofFields() []string { type NFTMintResponse struct { TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -100,7 +101,7 @@ func (m *NFTMintResponse) Reset() { *m = NFTMintResponse{} } func (m *NFTMintResponse) String() string { return proto.CompactTextString(m) } func (*NFTMintResponse) ProtoMessage() {} func (*NFTMintResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_b4e252768b910acc, []int{1} + return fileDescriptor_service_66d4e2152d82b027, []int{1} } func (m *NFTMintResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintResponse.Unmarshal(m, b) @@ -127,6 +128,13 @@ func (m *NFTMintResponse) GetTokenId() string { return "" } +func (m *NFTMintResponse) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + func init() { proto.RegisterType((*NFTMintRequest)(nil), "nft.NFTMintRequest") proto.RegisterType((*NFTMintResponse)(nil), "nft.NFTMintResponse") @@ -204,31 +212,32 @@ var _NFTService_serviceDesc = grpc.ServiceDesc{ Metadata: "nft/service.proto", } -func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_b4e252768b910acc) } - -var fileDescriptor_service_b4e252768b910acc = []byte{ - // 361 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x6e, 0xda, 0x40, - 0x14, 0x86, 0x65, 0x68, 0x4b, 0x19, 0x10, 0x50, 0xb7, 0x0b, 0x6a, 0x55, 0xd5, 0xd4, 0x8b, 0x96, - 0x56, 0x80, 0xa5, 0x76, 0xd7, 0x1d, 0xb4, 0xb2, 0xd4, 0x45, 0x2d, 0x44, 0xbd, 0xea, 0x06, 0x19, - 0xfb, 0x8d, 0x35, 0x0a, 0x7e, 0xe3, 0xcc, 0x3c, 0x82, 0xb2, 0x8d, 0x94, 0x0b, 0x24, 0x87, 0xc8, - 0x81, 0x72, 0x85, 0x1c, 0x24, 0xf2, 0x18, 0x50, 0x50, 0x56, 0xa3, 0xf9, 0xf4, 0xcd, 0xd3, 0x3f, - 0xff, 0x63, 0x6f, 0x50, 0x50, 0x60, 0x40, 0x5f, 0xc8, 0x14, 0xa6, 0xa5, 0x56, 0xa4, 0xdc, 0x26, - 0x0a, 0xf2, 0x3e, 0xe4, 0x4a, 0xe5, 0x1b, 0x08, 0x92, 0x52, 0x06, 0x09, 0xa2, 0xa2, 0x84, 0xa4, - 0x42, 0x53, 0x2b, 0xde, 0xd8, 0x1e, 0xe9, 0x24, 0x07, 0x9c, 0x98, 0x5d, 0x92, 0xe7, 0xa0, 0x03, - 0x55, 0x5a, 0xe3, 0xb9, 0xed, 0xdf, 0x39, 0xac, 0x17, 0x85, 0xf1, 0x5f, 0x89, 0xb4, 0x84, 0xf3, - 0x2d, 0x18, 0x72, 0x3f, 0x32, 0x26, 0x33, 0x40, 0x92, 0x42, 0x82, 0x1e, 0x3a, 0xdc, 0x19, 0xb5, - 0x97, 0x4f, 0x88, 0xfb, 0x95, 0x0d, 0x34, 0xe4, 0xd2, 0x90, 0xbe, 0x5c, 0x25, 0x59, 0xa6, 0xc1, - 0x98, 0x61, 0xc3, 0x5a, 0xfd, 0x03, 0x9f, 0xd5, 0xd8, 0xfd, 0xc2, 0xfa, 0x19, 0x94, 0xca, 0x48, - 0x3a, 0x9a, 0x4d, 0x6b, 0xf6, 0xf6, 0xf8, 0x20, 0x7e, 0x62, 0xdd, 0x52, 0x2b, 0x25, 0x56, 0x42, - 0xc2, 0x26, 0x33, 0xc3, 0x17, 0xbc, 0x39, 0x6a, 0x2f, 0x3b, 0x96, 0x85, 0x16, 0xf9, 0x63, 0xd6, - 0x3f, 0x06, 0x35, 0xa5, 0x42, 0x03, 0xee, 0x7b, 0xf6, 0x9a, 0xd4, 0x19, 0xe0, 0x4a, 0x66, 0xfb, - 0x9c, 0x2d, 0x7b, 0xff, 0x93, 0x7d, 0xbf, 0x76, 0x18, 0x8b, 0xc2, 0xf8, 0x5f, 0xdd, 0x9e, 0xbb, - 0x63, 0xad, 0xea, 0x65, 0x14, 0xc6, 0xee, 0xdb, 0x29, 0x0a, 0x9a, 0x9e, 0xfe, 0xd9, 0x7b, 0x77, - 0x0a, 0xeb, 0xf9, 0xfe, 0xec, 0x66, 0x36, 0xf2, 0x3e, 0x57, 0x88, 0x27, 0xc8, 0xa3, 0x30, 0xe6, - 0x42, 0xab, 0x82, 0x27, 0xfc, 0x17, 0x20, 0x69, 0x29, 0xb6, 0x39, 0xf0, 0xdf, 0x2a, 0xdd, 0x16, - 0x80, 0x74, 0x75, 0xff, 0x70, 0xdb, 0x18, 0xf8, 0x9d, 0xc0, 0x26, 0x08, 0x0a, 0x89, 0xf4, 0xd3, - 0xf9, 0x36, 0xe7, 0xac, 0x95, 0xaa, 0xa2, 0x9a, 0x3e, 0xef, 0xee, 0xc3, 0x2c, 0xaa, 0xe2, 0x17, - 0xce, 0xff, 0x97, 0x28, 0xa8, 0x5c, 0xaf, 0x5f, 0xd9, 0x45, 0xfc, 0x78, 0x0c, 0x00, 0x00, 0xff, - 0xff, 0x82, 0x2c, 0xea, 0x0e, 0xee, 0x01, 0x00, 0x00, +func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_66d4e2152d82b027) } + +var fileDescriptor_service_66d4e2152d82b027 = []byte{ + // 377 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x8e, 0xd3, 0x30, + 0x14, 0x40, 0x95, 0x29, 0x50, 0xc6, 0x33, 0xb4, 0x83, 0x61, 0x51, 0x22, 0x84, 0x4c, 0x24, 0xa0, + 0x20, 0xa6, 0x91, 0x60, 0xc7, 0xae, 0x03, 0x8a, 0x34, 0x0b, 0xa2, 0x51, 0x9b, 0x15, 0x9b, 0xca, + 0x8d, 0xbf, 0x23, 0x8b, 0xe6, 0x3b, 0xd8, 0xbf, 0x54, 0x6c, 0x91, 0xb8, 0x00, 0x1c, 0x82, 0x03, + 0x71, 0x05, 0x0e, 0x82, 0xe2, 0xb4, 0x55, 0x2b, 0x56, 0x51, 0x9e, 0x9e, 0xec, 0xe7, 0xff, 0xd9, + 0x7d, 0xd4, 0x94, 0x7a, 0x70, 0x5f, 0x4d, 0x09, 0x93, 0xc6, 0x59, 0xb2, 0xbc, 0x87, 0x9a, 0xe2, + 0xc7, 0x95, 0xb5, 0xd5, 0x0a, 0x52, 0xd9, 0x98, 0x54, 0x22, 0x5a, 0x92, 0x64, 0x2c, 0xfa, 0x4e, + 0x89, 0x5f, 0x87, 0x4f, 0x79, 0x59, 0x01, 0x5e, 0xfa, 0x8d, 0xac, 0x2a, 0x70, 0xa9, 0x6d, 0x82, + 0xf1, 0xbf, 0x9d, 0xfc, 0x8e, 0xd8, 0x20, 0xcf, 0x8a, 0x8f, 0x06, 0x69, 0x06, 0x5f, 0xd6, 0xe0, + 0x89, 0x3f, 0x61, 0xcc, 0x28, 0x40, 0x32, 0xda, 0x80, 0x1b, 0x45, 0x22, 0x1a, 0x9f, 0xce, 0x0e, + 0x08, 0x7f, 0xc9, 0x2e, 0x1c, 0x54, 0xc6, 0x93, 0xfb, 0xb6, 0x90, 0x4a, 0x39, 0xf0, 0x7e, 0x74, + 0x12, 0xac, 0xe1, 0x8e, 0x4f, 0x3b, 0xcc, 0x5f, 0xb0, 0xa1, 0x82, 0xc6, 0x7a, 0x43, 0x7b, 0xb3, + 0x17, 0xcc, 0xc1, 0x16, 0xef, 0xc4, 0xa7, 0xec, 0xbc, 0x71, 0xd6, 0xea, 0x85, 0x36, 0xb0, 0x52, + 0x7e, 0x74, 0x4b, 0xf4, 0xc6, 0xa7, 0xb3, 0xb3, 0xc0, 0xb2, 0x80, 0x92, 0x39, 0x1b, 0xee, 0x43, + 0x7d, 0x63, 0xd1, 0x03, 0x7f, 0xc4, 0xee, 0x92, 0xfd, 0x0c, 0xb8, 0x30, 0x6a, 0xdb, 0xd9, 0x0f, + 0xff, 0xd7, 0x8a, 0x3f, 0x63, 0x03, 0x72, 0x12, 0xbd, 0x2c, 0xdb, 0xd7, 0xb6, 0x42, 0x97, 0x78, + 0xef, 0x80, 0x5e, 0xab, 0x37, 0x3f, 0x22, 0xc6, 0xf2, 0xac, 0x98, 0x77, 0x43, 0xe6, 0x1b, 0xd6, + 0x6f, 0x2f, 0xc8, 0xb3, 0x82, 0x3f, 0x98, 0xa0, 0xa6, 0xc9, 0xf1, 0x68, 0xe2, 0x87, 0xc7, 0xb0, + 0xcb, 0x48, 0xa6, 0x3f, 0xa7, 0xe3, 0xf8, 0x79, 0x8b, 0x84, 0x44, 0x91, 0x67, 0x85, 0xd0, 0xce, + 0xd6, 0x42, 0x8a, 0xf7, 0x80, 0xe4, 0x8c, 0x5e, 0x57, 0x20, 0x3e, 0xd8, 0x72, 0x5d, 0x03, 0xd2, + 0xf7, 0x3f, 0x7f, 0x7f, 0x9d, 0x5c, 0x24, 0x67, 0x69, 0x08, 0x4d, 0x6b, 0x83, 0xf4, 0x2e, 0x7a, + 0x75, 0x25, 0x58, 0xbf, 0xb4, 0x75, 0x7b, 0xfa, 0xd5, 0xf9, 0x36, 0xe6, 0xa6, 0xdd, 0xcf, 0x4d, + 0xf4, 0xe9, 0x36, 0x6a, 0x6a, 0x96, 0xcb, 0x3b, 0x61, 0x5f, 0x6f, 0xff, 0x05, 0x00, 0x00, 0xff, + 0xff, 0x3c, 0xa0, 0x02, 0xa5, 0x15, 0x02, 0x00, 0x00, } diff --git a/protobufs/gen/go/purchaseorder/service.pb.go b/protobufs/gen/go/purchaseorder/service.pb.go index 9a30256d4..d1b20e857 100644 --- a/protobufs/gen/go/purchaseorder/service.pb.go +++ b/protobufs/gen/go/purchaseorder/service.pb.go @@ -37,7 +37,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{0} + return fileDescriptor_service_393a7cd179a9d71e, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{1} + return fileDescriptor_service_393a7cd179a9d71e, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -122,7 +122,7 @@ func (m *PurchaseOrderCreatePayload) Reset() { *m = PurchaseOrderCreateP func (m *PurchaseOrderCreatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderCreatePayload) ProtoMessage() {} func (*PurchaseOrderCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{2} + return fileDescriptor_service_393a7cd179a9d71e, []int{2} } func (m *PurchaseOrderCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderCreatePayload.Unmarshal(m, b) @@ -169,7 +169,7 @@ func (m *PurchaseOrderUpdatePayload) Reset() { *m = PurchaseOrderUpdateP func (m *PurchaseOrderUpdatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderUpdatePayload) ProtoMessage() {} func (*PurchaseOrderUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{3} + return fileDescriptor_service_393a7cd179a9d71e, []int{3} } func (m *PurchaseOrderUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderUpdatePayload.Unmarshal(m, b) @@ -222,7 +222,7 @@ func (m *PurchaseOrderResponse) Reset() { *m = PurchaseOrderResponse{} } func (m *PurchaseOrderResponse) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderResponse) ProtoMessage() {} func (*PurchaseOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{4} + return fileDescriptor_service_393a7cd179a9d71e, []int{4} } func (m *PurchaseOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderResponse.Unmarshal(m, b) @@ -262,6 +262,7 @@ type ResponseHeader struct { VersionId string `protobuf:"bytes,2,opt,name=version_id,json=versionId,proto3" json:"version_id,omitempty"` State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` Collaborators []string `protobuf:"bytes,4,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + TransactionId string `protobuf:"bytes,5,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -271,7 +272,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{5} + return fileDescriptor_service_393a7cd179a9d71e, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -319,6 +320,13 @@ func (m *ResponseHeader) GetCollaborators() []string { return nil } +func (m *ResponseHeader) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + type PurchaseOrderData struct { PoStatus string `protobuf:"bytes,24,opt,name=po_status,json=poStatus,proto3" json:"po_status,omitempty"` // purchase order number or reference number @@ -365,7 +373,7 @@ func (m *PurchaseOrderData) Reset() { *m = PurchaseOrderData{} } func (m *PurchaseOrderData) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderData) ProtoMessage() {} func (*PurchaseOrderData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_4c1800c623b61b4a, []int{6} + return fileDescriptor_service_393a7cd179a9d71e, []int{6} } func (m *PurchaseOrderData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderData.Unmarshal(m, b) @@ -735,69 +743,70 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_4c1800c623b61b4a) -} - -var fileDescriptor_service_4c1800c623b61b4a = []byte{ - // 949 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xd7, 0xe6, 0x8f, 0x63, 0x8f, 0xed, 0xa4, 0x9e, 0xb6, 0x30, 0xdd, 0x34, 0x74, 0x31, 0xad, - 0x48, 0xdb, 0xc4, 0x96, 0x42, 0xe1, 0x80, 0x84, 0x50, 0x9a, 0x48, 0xa1, 0x07, 0x4a, 0xb4, 0x01, - 0x0e, 0x15, 0x92, 0x35, 0xde, 0x7d, 0x76, 0x56, 0xf2, 0xee, 0x2c, 0xb3, 0xe3, 0x60, 0x53, 0xf5, - 0x82, 0x38, 0x72, 0x21, 0x5c, 0x40, 0x48, 0x7c, 0x08, 0xbe, 0x0a, 0x5f, 0x81, 0xaf, 0xc0, 0x1d, - 0xcd, 0x9b, 0x59, 0xdb, 0x6b, 0x17, 0x27, 0xe5, 0xb4, 0x9a, 0xf7, 0xfb, 0xbd, 0xb7, 0xbf, 0xf7, - 0x66, 0xe6, 0x37, 0x64, 0x3b, 0x1d, 0xca, 0xe0, 0x9c, 0x67, 0x20, 0x64, 0x08, 0xb2, 0x9d, 0x81, - 0xbc, 0x88, 0x02, 0x68, 0xa5, 0x52, 0x28, 0x41, 0xeb, 0x05, 0xd0, 0xbd, 0xdb, 0x17, 0xa2, 0x3f, - 0x80, 0x36, 0x4f, 0xa3, 0x36, 0x4f, 0x12, 0xa1, 0xb8, 0x8a, 0x44, 0x92, 0x19, 0xb2, 0x7b, 0xcf, - 0xa2, 0xb8, 0xea, 0x0e, 0x7b, 0x6d, 0x15, 0xc5, 0x90, 0x29, 0x1e, 0xa7, 0x96, 0xb0, 0x87, 0x9f, - 0x60, 0xbf, 0x0f, 0xc9, 0x7e, 0xf6, 0x1d, 0xef, 0xf7, 0x41, 0xb6, 0x45, 0x8a, 0x25, 0x16, 0xcb, - 0x35, 0xf7, 0x08, 0x39, 0x01, 0xe5, 0xc3, 0xb7, 0x43, 0xc8, 0x14, 0x7d, 0x87, 0x90, 0x28, 0x84, - 0x44, 0x45, 0xbd, 0x08, 0x24, 0x73, 0x3c, 0x67, 0xb7, 0xe2, 0xcf, 0x44, 0x9a, 0x9f, 0x93, 0xc6, - 0x09, 0xa8, 0xaf, 0x41, 0x66, 0x91, 0x48, 0xae, 0x99, 0x44, 0x19, 0xd9, 0xb8, 0x30, 0x19, 0x6c, - 0x05, 0xc1, 0x7c, 0xd9, 0x1c, 0x11, 0xf7, 0xd4, 0xb6, 0xfe, 0x85, 0x6e, 0xfd, 0x48, 0x02, 0x57, - 0x70, 0xca, 0xc7, 0x03, 0xc1, 0x43, 0x7a, 0x9f, 0xd4, 0x03, 0x31, 0x18, 0xf0, 0xae, 0x90, 0x5c, - 0x09, 0x99, 0x31, 0xc7, 0x5b, 0xdd, 0xad, 0xf8, 0xc5, 0x20, 0x7d, 0x42, 0xd6, 0x42, 0xae, 0x38, - 0x96, 0xae, 0x1e, 0x78, 0xad, 0xc2, 0x2c, 0x5b, 0x85, 0xf2, 0xc7, 0x5c, 0x71, 0x1f, 0xd9, 0xcd, - 0x5f, 0x9d, 0xb9, 0x5f, 0x7f, 0x95, 0x86, 0x33, 0xbf, 0xbe, 0xaa, 0xa5, 0x05, 0x69, 0x2b, 0xcb, - 0xa4, 0xad, 0xbe, 0x91, 0xb4, 0x1f, 0x1d, 0x72, 0xbb, 0x80, 0xf9, 0x90, 0xa5, 0x22, 0xc9, 0x80, - 0x7e, 0x48, 0x4a, 0xe7, 0xc0, 0x43, 0xab, 0xa8, 0x7a, 0xb0, 0x33, 0x57, 0x31, 0x27, 0x7e, 0x86, - 0x24, 0xdf, 0x92, 0xff, 0xe7, 0x84, 0x7e, 0x72, 0xc8, 0x66, 0xb1, 0x20, 0xbd, 0x47, 0xaa, 0xa1, - 0x08, 0x86, 0x31, 0x24, 0xaa, 0x13, 0x85, 0xf9, 0x58, 0xf2, 0xd0, 0xb3, 0x90, 0xee, 0x10, 0x62, - 0xb7, 0x56, 0xe3, 0x66, 0xb3, 0x2b, 0x36, 0xf2, 0x2c, 0xa4, 0xb7, 0xc8, 0x7a, 0xa6, 0xb8, 0x02, - 0x1c, 0x48, 0xc5, 0x37, 0x8b, 0xc5, 0x59, 0xae, 0xbd, 0x66, 0x96, 0xcd, 0x7f, 0x4a, 0xa4, 0xb1, - 0x20, 0x95, 0x6e, 0x93, 0x4a, 0x2a, 0x3a, 0xba, 0xce, 0x30, 0x63, 0x0c, 0xab, 0x96, 0x53, 0x71, - 0x86, 0x6b, 0x0b, 0x26, 0xc3, 0xb8, 0x3b, 0xd9, 0xc3, 0x72, 0x2a, 0x9e, 0xe3, 0x5a, 0x4b, 0xc5, - 0xfe, 0x3b, 0x09, 0x8f, 0x21, 0x97, 0x8a, 0x91, 0xe7, 0x3c, 0x06, 0xfa, 0x2e, 0xa9, 0x19, 0x38, - 0x53, 0x12, 0x40, 0x59, 0xc5, 0x55, 0x8c, 0x9d, 0x61, 0x68, 0x5a, 0x21, 0x88, 0xd4, 0x98, 0xad, - 0xcd, 0x54, 0x38, 0x8a, 0xd4, 0x98, 0xbe, 0x47, 0xea, 0x06, 0xfe, 0x3e, 0x4a, 0x03, 0x11, 0x02, - 0x5b, 0x47, 0x86, 0x29, 0xfb, 0xc2, 0xc4, 0xa6, 0xa4, 0x40, 0x0c, 0x13, 0x25, 0xc7, 0xac, 0x34, - 0x43, 0x3a, 0x32, 0x31, 0xfa, 0x80, 0x6c, 0x4a, 0x08, 0xa2, 0x34, 0xd2, 0x73, 0x47, 0xb9, 0x1b, - 0xc8, 0xaa, 0x4f, 0xa2, 0x28, 0xf9, 0x21, 0xb9, 0x31, 0xa5, 0x59, 0xd9, 0x65, 0x24, 0x6e, 0x4d, - 0xe2, 0x56, 0x7a, 0xa1, 0x22, 0xca, 0xaf, 0xcc, 0x55, 0xc4, 0x16, 0x1e, 0x93, 0xc6, 0x94, 0x96, - 0xb7, 0x41, 0x90, 0x39, 0xfd, 0x55, 0xde, 0x4a, 0x81, 0x9c, 0xb7, 0x53, 0x9d, 0x23, 0xe7, 0x2d, - 0xb9, 0xa4, 0x1c, 0x0c, 0xa5, 0x84, 0x24, 0x18, 0xb3, 0x9a, 0xd9, 0x99, 0x7c, 0x3d, 0x1d, 0x3d, - 0x8f, 0x35, 0x9b, 0xd5, 0x3d, 0x67, 0x77, 0xd5, 0x8e, 0xfe, 0x10, 0x43, 0x7a, 0xf4, 0x09, 0xa8, - 0x9c, 0xb0, 0x89, 0x84, 0x4a, 0x02, 0x6a, 0x0a, 0x2b, 0x3e, 0xca, 0xe1, 0x2d, 0x03, 0x2b, 0x3e, - 0xb2, 0xf0, 0x1d, 0x52, 0xd6, 0xb0, 0xd4, 0x27, 0xf1, 0x06, 0x82, 0x1b, 0x8a, 0x8f, 0x7c, 0x7d, - 0x16, 0xef, 0x92, 0xca, 0x44, 0x2b, 0x6b, 0x98, 0x2d, 0x9d, 0x04, 0xf4, 0xf9, 0x45, 0x15, 0x8c, - 0x9a, 0xf3, 0x8b, 0x8b, 0xd9, 0x3d, 0x4c, 0x14, 0x0f, 0x14, 0xbb, 0x59, 0xd8, 0x43, 0x8c, 0x69, - 0x0f, 0x0c, 0x44, 0xac, 0xaf, 0x09, 0xbb, 0x65, 0x3c, 0xd0, 0x2e, 0xe9, 0xa7, 0xa4, 0x1e, 0xc2, - 0x20, 0xba, 0x00, 0x39, 0xee, 0x68, 0x0b, 0x62, 0xb7, 0xf1, 0x9a, 0xba, 0x2d, 0xe3, 0xf3, 0xad, - 0xdc, 0xe7, 0x5b, 0x5f, 0xe6, 0x3e, 0xef, 0xd7, 0xf2, 0x84, 0x63, 0xad, 0xf9, 0x13, 0x52, 0xd3, - 0x79, 0x9d, 0x00, 0xcd, 0x33, 0x64, 0x6f, 0x5d, 0x99, 0x5f, 0xd5, 0x7c, 0xe3, 0xb5, 0x78, 0x67, - 0x61, 0xa4, 0x24, 0xef, 0xa0, 0x47, 0xbc, 0x6d, 0x7a, 0xc6, 0x88, 0xbe, 0x61, 0x07, 0xbf, 0xad, - 0x93, 0xad, 0x63, 0x7b, 0xc3, 0xcf, 0xcc, 0xab, 0x45, 0x7f, 0x76, 0x48, 0xc9, 0xa4, 0xd3, 0x87, - 0xcb, 0xdc, 0xa4, 0x60, 0xe7, 0xee, 0xfd, 0x65, 0xd4, 0xdc, 0x69, 0x9a, 0x1f, 0x5d, 0x1e, 0xba, - 0x2e, 0x33, 0x99, 0x99, 0xc7, 0xbd, 0x3c, 0xc7, 0xc3, 0xa4, 0x1f, 0xfe, 0xfa, 0xfb, 0x97, 0x95, - 0x9b, 0xcd, 0xcd, 0x76, 0xa1, 0xd4, 0xc7, 0xce, 0x23, 0xfa, 0x87, 0x43, 0x4a, 0xc6, 0xc3, 0x97, - 0x6b, 0x2a, 0xf8, 0xfc, 0x35, 0x35, 0x1d, 0xa1, 0x26, 0x93, 0xf9, 0x1f, 0x9a, 0x3c, 0x77, 0xbb, - 0xa8, 0xa9, 0xfd, 0x72, 0xfa, 0x5c, 0xbc, 0xd2, 0x02, 0xff, 0x74, 0xf0, 0xa5, 0xb5, 0x6f, 0x27, - 0x9d, 0xb7, 0xe1, 0x85, 0x67, 0xf5, 0x9a, 0xda, 0xbe, 0xb9, 0x3c, 0xdc, 0x73, 0x1f, 0x9d, 0x80, - 0xf2, 0xb8, 0x97, 0xa5, 0x10, 0x44, 0xbd, 0x28, 0xf0, 0xac, 0xe5, 0x7a, 0xa2, 0xf7, 0x7a, 0xb5, - 0xef, 0xd3, 0x07, 0x4b, 0xd4, 0xb6, 0x5f, 0xda, 0xfc, 0x57, 0xf4, 0x77, 0x87, 0xac, 0x9e, 0x80, - 0xa2, 0x77, 0x16, 0xd5, 0xbe, 0x99, 0xcc, 0xb3, 0xcb, 0xc3, 0x7d, 0xf7, 0xb1, 0x96, 0xa9, 0xce, - 0xc1, 0x33, 0x77, 0x5d, 0x5d, 0xa9, 0x73, 0x87, 0x2e, 0x9b, 0xea, 0xd3, 0x27, 0xa4, 0x11, 0x88, - 0xb8, 0xf8, 0xff, 0xa7, 0x35, 0x7b, 0x4a, 0x4f, 0xf5, 0xb9, 0x3f, 0x75, 0x5e, 0x6c, 0x15, 0xe0, - 0xb4, 0xdb, 0x2d, 0xe1, 0x8d, 0xf8, 0xe0, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x84, 0xe7, - 0x4b, 0x93, 0x09, 0x00, 0x00, + proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_393a7cd179a9d71e) +} + +var fileDescriptor_service_393a7cd179a9d71e = []byte{ + // 963 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x5f, 0x6f, 0x1b, 0x45, + 0x10, 0xd7, 0xe5, 0x8f, 0x63, 0xaf, 0xed, 0xa4, 0xde, 0xb6, 0x70, 0xbd, 0x34, 0xf4, 0x30, 0xad, + 0x48, 0xdb, 0xc4, 0x96, 0x42, 0xe1, 0x01, 0x09, 0xa1, 0x34, 0x91, 0x42, 0x1e, 0x28, 0xd1, 0x05, + 0x78, 0xa8, 0x90, 0xac, 0xf5, 0xde, 0xc4, 0x39, 0xc9, 0x77, 0x7b, 0xec, 0xad, 0x83, 0x4d, 0xd5, + 0x17, 0xc4, 0x17, 0x20, 0xbc, 0x80, 0x90, 0xf8, 0x10, 0xf0, 0x51, 0xf8, 0x0a, 0x7c, 0x05, 0xde, + 0xd1, 0xce, 0xee, 0xd9, 0x3e, 0xbb, 0x38, 0x09, 0x4f, 0xa7, 0xfd, 0xcd, 0x6f, 0xe6, 0x7e, 0x33, + 0xb3, 0x3b, 0x43, 0x36, 0xd3, 0x81, 0xe4, 0xe7, 0x2c, 0x03, 0x21, 0x43, 0x90, 0xed, 0x0c, 0xe4, + 0x45, 0xc4, 0xa1, 0x95, 0x4a, 0xa1, 0x04, 0xad, 0x17, 0x8c, 0xde, 0xfd, 0x9e, 0x10, 0xbd, 0x3e, + 0xb4, 0x59, 0x1a, 0xb5, 0x59, 0x92, 0x08, 0xc5, 0x54, 0x24, 0x92, 0xcc, 0x90, 0xbd, 0x07, 0xd6, + 0x8a, 0xa7, 0xee, 0xe0, 0xac, 0xad, 0xa2, 0x18, 0x32, 0xc5, 0xe2, 0xd4, 0x12, 0x76, 0xf0, 0xc3, + 0x77, 0x7b, 0x90, 0xec, 0x66, 0xdf, 0xb1, 0x5e, 0x0f, 0x64, 0x5b, 0xa4, 0x18, 0x62, 0x3e, 0x5c, + 0x73, 0x87, 0x90, 0x23, 0x50, 0x01, 0x7c, 0x3b, 0x80, 0x4c, 0xd1, 0x77, 0x08, 0x89, 0x42, 0x48, + 0x54, 0x74, 0x16, 0x81, 0x74, 0x1d, 0xdf, 0xd9, 0xae, 0x04, 0x53, 0x48, 0xf3, 0x73, 0xd2, 0x38, + 0x02, 0xf5, 0x35, 0xc8, 0x2c, 0x12, 0xc9, 0x35, 0x9d, 0xa8, 0x4b, 0xd6, 0x2e, 0x8c, 0x87, 0xbb, + 0x84, 0xc6, 0xfc, 0xd8, 0x1c, 0x12, 0xef, 0xc4, 0xa6, 0xfe, 0x85, 0x4e, 0xfd, 0x40, 0x02, 0x53, + 0x70, 0xc2, 0x46, 0x7d, 0xc1, 0x42, 0xfa, 0x90, 0xd4, 0xb9, 0xe8, 0xf7, 0x59, 0x57, 0x48, 0xa6, + 0x84, 0xcc, 0x5c, 0xc7, 0x5f, 0xde, 0xae, 0x04, 0x45, 0x90, 0x3e, 0x23, 0x2b, 0x21, 0x53, 0x0c, + 0x43, 0x57, 0xf7, 0xfc, 0x56, 0xa1, 0x96, 0xad, 0x42, 0xf8, 0x43, 0xa6, 0x58, 0x80, 0xec, 0xe6, + 0x2f, 0xce, 0xcc, 0xaf, 0xbf, 0x4a, 0xc3, 0xa9, 0x5f, 0x5f, 0x95, 0xd2, 0x9c, 0xb4, 0xa5, 0x45, + 0xd2, 0x96, 0x6f, 0x24, 0xed, 0x47, 0x87, 0xdc, 0x2d, 0xd8, 0x02, 0xc8, 0x52, 0x91, 0x64, 0x40, + 0x3f, 0x24, 0xa5, 0x73, 0x60, 0xa1, 0x55, 0x54, 0xdd, 0xdb, 0x9a, 0x89, 0x98, 0x13, 0x3f, 0x43, + 0x52, 0x60, 0xc9, 0xff, 0xb3, 0x42, 0x7f, 0x3a, 0x64, 0xbd, 0x18, 0x90, 0x3e, 0x20, 0xd5, 0x50, + 0xf0, 0x41, 0x0c, 0x89, 0xea, 0x44, 0x61, 0x5e, 0x96, 0x1c, 0x3a, 0x0e, 0xe9, 0x16, 0x21, 0xb6, + 0xb5, 0xda, 0x6e, 0x9a, 0x5d, 0xb1, 0xc8, 0x71, 0x48, 0xef, 0x90, 0xd5, 0x4c, 0x31, 0x05, 0x58, + 0x90, 0x4a, 0x60, 0x0e, 0xf3, 0xb5, 0x5c, 0x79, 0x53, 0x2d, 0x1f, 0x91, 0x75, 0x25, 0x59, 0x92, + 0x31, 0xae, 0x6c, 0xf8, 0x55, 0x0c, 0x52, 0x9f, 0x42, 0x8f, 0xc3, 0xe6, 0x3f, 0x25, 0xd2, 0x98, + 0xcb, 0x88, 0x6e, 0x92, 0x4a, 0x2a, 0x3a, 0xfa, 0x77, 0x83, 0xcc, 0x75, 0xd1, 0xaf, 0x9c, 0x8a, + 0x53, 0x3c, 0x5b, 0x63, 0x32, 0x88, 0xbb, 0xe3, 0x56, 0x97, 0x53, 0xf1, 0x02, 0xcf, 0x3a, 0x23, + 0x2c, 0x53, 0x27, 0x61, 0x31, 0xe4, 0x19, 0x21, 0xf2, 0x82, 0xc5, 0x40, 0xdf, 0x25, 0x35, 0x63, + 0xce, 0x94, 0x04, 0x50, 0x36, 0xb1, 0x2a, 0x62, 0xa7, 0x08, 0x4d, 0x22, 0xf0, 0x48, 0x8d, 0xdc, + 0x95, 0xa9, 0x08, 0x07, 0x91, 0x1a, 0xd1, 0xf7, 0x48, 0xdd, 0x98, 0xbf, 0x8f, 0x52, 0x2e, 0x42, + 0xb0, 0x69, 0x99, 0xb0, 0x2f, 0x0d, 0x36, 0x21, 0x71, 0x31, 0x48, 0x94, 0x1c, 0xb9, 0xa5, 0x29, + 0xd2, 0x81, 0xc1, 0x74, 0x85, 0x24, 0xf0, 0x28, 0x8d, 0x74, 0x7b, 0x50, 0xee, 0x9a, 0xa9, 0xd0, + 0x18, 0x45, 0xc9, 0x8f, 0xc9, 0xad, 0x09, 0xcd, 0xca, 0x2e, 0x23, 0x71, 0x63, 0x8c, 0x5b, 0xe9, + 0x85, 0x88, 0x28, 0xbf, 0x32, 0x13, 0x11, 0x53, 0x78, 0x4a, 0x1a, 0x13, 0x5a, 0x9e, 0x06, 0x41, + 0xe6, 0xe4, 0x57, 0x79, 0x2a, 0x05, 0x72, 0x9e, 0x4e, 0x75, 0x86, 0x9c, 0xa7, 0xe4, 0x91, 0x32, + 0x1f, 0x48, 0x09, 0x09, 0x1f, 0xb9, 0x35, 0xd3, 0x99, 0xfc, 0x3c, 0x29, 0x3d, 0x8b, 0x35, 0xdb, + 0xad, 0xfb, 0xce, 0xf6, 0xb2, 0x2d, 0xfd, 0x3e, 0x42, 0xba, 0xf4, 0x09, 0xa8, 0x9c, 0xb0, 0x8e, + 0x84, 0x4a, 0x02, 0x6a, 0x62, 0x56, 0x6c, 0x98, 0x9b, 0x37, 0x8c, 0x59, 0xb1, 0xa1, 0x35, 0xdf, + 0x23, 0x65, 0x6d, 0x96, 0xfa, 0xc2, 0xde, 0x42, 0xe3, 0x9a, 0x62, 0xc3, 0x40, 0x5f, 0xd9, 0xfb, + 0xa4, 0x32, 0xd6, 0xea, 0x36, 0x4c, 0x4b, 0xc7, 0x80, 0xbe, 0xe6, 0xa8, 0xc2, 0xa5, 0xe6, 0x9a, + 0xe3, 0x61, 0xba, 0x87, 0x89, 0x62, 0x5c, 0xb9, 0xb7, 0x0b, 0x3d, 0x44, 0x4c, 0x8f, 0x4a, 0x2e, + 0x62, 0xfd, 0x9a, 0xdc, 0x3b, 0x66, 0x54, 0xda, 0x23, 0xfd, 0x94, 0xd4, 0x43, 0xe8, 0x47, 0x17, + 0x20, 0x47, 0x1d, 0x3d, 0xa9, 0xdc, 0xbb, 0xf8, 0x9a, 0xbd, 0x96, 0x59, 0x07, 0xad, 0x7c, 0x1d, + 0xb4, 0xbe, 0xcc, 0xd7, 0x41, 0x50, 0xcb, 0x1d, 0x0e, 0xb5, 0xe6, 0x4f, 0x48, 0x4d, 0xfb, 0x75, + 0x38, 0xce, 0xd8, 0xd0, 0x7d, 0xeb, 0x4a, 0xff, 0xaa, 0xe6, 0x9b, 0x91, 0x8c, 0x4f, 0x1b, 0x86, + 0x4a, 0xb2, 0x0e, 0x8e, 0x92, 0xb7, 0x4d, 0xce, 0x88, 0xe8, 0x17, 0xb6, 0xf7, 0xeb, 0x2a, 0xd9, + 0x38, 0xb4, 0x83, 0xe0, 0xd4, 0x2c, 0x37, 0xfa, 0x93, 0x43, 0x4a, 0xc6, 0x9d, 0x3e, 0x5e, 0x34, + 0x74, 0x0a, 0x53, 0xdf, 0x7b, 0xb8, 0x88, 0x9a, 0x0f, 0xa4, 0xe6, 0x47, 0x97, 0xfb, 0x9e, 0xe7, + 0x1a, 0xcf, 0xcc, 0x67, 0x7e, 0xee, 0xe3, 0xa3, 0xd3, 0x0f, 0x7f, 0xfd, 0xfd, 0xf3, 0xd2, 0xed, + 0xe6, 0x7a, 0xbb, 0x10, 0xea, 0x63, 0xe7, 0x09, 0xfd, 0xdd, 0x21, 0x25, 0x33, 0xea, 0x17, 0x6b, + 0x2a, 0xac, 0x83, 0x6b, 0x6a, 0x3a, 0x40, 0x4d, 0xc6, 0xf3, 0x3f, 0x34, 0xf9, 0xde, 0x66, 0x51, + 0x53, 0xfb, 0xd5, 0x64, 0xab, 0xbc, 0xd6, 0x02, 0xff, 0x70, 0x70, 0x21, 0xdb, 0x15, 0x4b, 0x67, + 0xa7, 0xf5, 0xdc, 0xf6, 0xbd, 0xa6, 0xb6, 0x6f, 0x2e, 0xf7, 0x77, 0xbc, 0x27, 0x47, 0xa0, 0x7c, + 0xe6, 0x67, 0x29, 0xf0, 0xe8, 0x2c, 0xe2, 0xbe, 0x9d, 0xcc, 0xbe, 0x38, 0x7b, 0xb3, 0xda, 0xf7, + 0xe9, 0xa3, 0x05, 0x6a, 0xdb, 0xaf, 0xac, 0xff, 0x6b, 0xfa, 0x9b, 0x43, 0x96, 0x8f, 0x40, 0xd1, + 0x7b, 0xf3, 0x6a, 0x6f, 0x26, 0xf3, 0xf4, 0x72, 0x7f, 0xd7, 0x7b, 0xaa, 0x65, 0xaa, 0x73, 0xf0, + 0xcd, 0x5b, 0x57, 0x57, 0xea, 0xdc, 0xa2, 0x8b, 0xaa, 0xfa, 0xfc, 0x19, 0x69, 0x70, 0x11, 0x17, + 0xff, 0xff, 0xbc, 0x66, 0x6f, 0xe9, 0x89, 0xbe, 0xf7, 0x27, 0xce, 0xcb, 0x8d, 0x82, 0x39, 0xed, + 0x76, 0x4b, 0xf8, 0x22, 0x3e, 0xf8, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xa0, 0xe0, 0x99, 0xba, + 0x09, 0x00, 0x00, } diff --git a/protobufs/gen/go/transactions/service.pb.go b/protobufs/gen/go/transactions/service.pb.go index 4c130990f..73505fcb9 100644 --- a/protobufs/gen/go/transactions/service.pb.go +++ b/protobufs/gen/go/transactions/service.pb.go @@ -37,7 +37,7 @@ func (m *TransactionStatusRequest) Reset() { *m = TransactionStatusReque func (m *TransactionStatusRequest) String() string { return proto.CompactTextString(m) } func (*TransactionStatusRequest) ProtoMessage() {} func (*TransactionStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_b7b04d343851d658, []int{0} + return fileDescriptor_service_3dc77ed74e902ae6, []int{0} } func (m *TransactionStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TransactionStatusRequest.Unmarshal(m, b) @@ -78,7 +78,7 @@ func (m *TransactionStatusResponse) Reset() { *m = TransactionStatusResp func (m *TransactionStatusResponse) String() string { return proto.CompactTextString(m) } func (*TransactionStatusResponse) ProtoMessage() {} func (*TransactionStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_b7b04d343851d658, []int{1} + return fileDescriptor_service_3dc77ed74e902ae6, []int{1} } func (m *TransactionStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TransactionStatusResponse.Unmarshal(m, b) @@ -203,30 +203,30 @@ var _TransactionService_serviceDesc = grpc.ServiceDesc{ Metadata: "transactions/service.proto", } -func init() { proto.RegisterFile("transactions/service.proto", fileDescriptor_service_b7b04d343851d658) } - -var fileDescriptor_service_b7b04d343851d658 = []byte{ - // 346 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4a, 0xc3, 0x40, - 0x10, 0x86, 0x49, 0x95, 0x8a, 0xdb, 0x2a, 0xb2, 0x48, 0x89, 0x41, 0x69, 0x28, 0xa8, 0x3d, 0xd8, - 0x2c, 0xd4, 0xb3, 0x60, 0x7b, 0x29, 0xde, 0x4a, 0xad, 0x17, 0x2f, 0x65, 0x9b, 0x8c, 0x21, 0xd0, - 0x64, 0xd7, 0xcc, 0x46, 0x0f, 0xe2, 0xc5, 0x47, 0xd0, 0xa7, 0xf0, 0xec, 0x0b, 0xf8, 0x0e, 0xbe, - 0x82, 0x0f, 0x22, 0xdd, 0x4d, 0x71, 0x4b, 0x15, 0x3d, 0x85, 0xd9, 0xff, 0xcf, 0x3f, 0x33, 0xdf, - 0x10, 0x4f, 0xe5, 0x3c, 0x43, 0x1e, 0xaa, 0x44, 0x64, 0xc8, 0x10, 0xf2, 0xbb, 0x24, 0x84, 0x40, - 0xe6, 0x42, 0x09, 0x5a, 0xb7, 0x35, 0x6f, 0x3f, 0x16, 0x22, 0x9e, 0x01, 0xe3, 0x32, 0x61, 0x3c, - 0xcb, 0x84, 0xe2, 0xfa, 0xdd, 0x78, 0xbd, 0x66, 0xa9, 0xea, 0x6a, 0x5a, 0xdc, 0x30, 0x95, 0xa4, - 0x80, 0x8a, 0xa7, 0xb2, 0x34, 0x9c, 0xe8, 0x4f, 0xd8, 0x89, 0x21, 0xeb, 0xe0, 0x3d, 0x8f, 0x63, - 0xc8, 0x99, 0x90, 0xa6, 0xed, 0x4a, 0x5c, 0xab, 0x47, 0xdc, 0xf1, 0x77, 0xf3, 0x4b, 0xc5, 0x55, - 0x81, 0x23, 0xb8, 0x2d, 0x00, 0x15, 0x3d, 0x24, 0xdb, 0xd6, 0x60, 0x93, 0x24, 0x72, 0x1d, 0xdf, - 0x69, 0x6f, 0x8e, 0xb6, 0xac, 0xd7, 0x8b, 0xa8, 0xf5, 0xe6, 0x90, 0xbd, 0x1f, 0x32, 0x50, 0x8a, - 0x0c, 0xe1, 0x9f, 0x21, 0xb4, 0x41, 0xaa, 0xa8, 0x7f, 0x74, 0x2b, 0x5a, 0x2e, 0x2b, 0xea, 0x92, - 0x8d, 0x14, 0x10, 0x79, 0x0c, 0xee, 0x9a, 0x16, 0x16, 0x25, 0x3d, 0x23, 0xf5, 0x19, 0x47, 0x35, - 0x29, 0x64, 0xc4, 0x15, 0x44, 0xee, 0xba, 0xef, 0xb4, 0x6b, 0x5d, 0x2f, 0x30, 0x7c, 0x82, 0x05, - 0x9f, 0x60, 0xbc, 0xe0, 0x33, 0xaa, 0xcd, 0xfd, 0x57, 0xc6, 0xde, 0x7d, 0x77, 0x08, 0xb5, 0xa7, - 0x36, 0x07, 0xa1, 0xaf, 0x0e, 0xd9, 0x1d, 0x80, 0x5a, 0xd9, 0x87, 0x1e, 0x05, 0xf6, 0x91, 0x82, - 0xdf, 0xa0, 0x79, 0xc7, 0x7f, 0xfa, 0x0c, 0x98, 0xd6, 0xf9, 0x73, 0xcf, 0xf5, 0x1a, 0x03, 0x50, - 0xbe, 0xe5, 0xf1, 0x8d, 0xe9, 0xe9, 0xe3, 0xf3, 0xa5, 0xd2, 0xa4, 0x07, 0xcc, 0xca, 0x62, 0x0f, - 0xcb, 0x1c, 0x1f, 0xfb, 0x5d, 0xb2, 0x13, 0x8a, 0x74, 0xa9, 0x5f, 0xbf, 0x5e, 0x2e, 0x32, 0x9c, - 0xaf, 0x3f, 0x74, 0xae, 0x6d, 0xf8, 0x28, 0xa7, 0xd3, 0xaa, 0xe6, 0x72, 0xfa, 0x15, 0x00, 0x00, - 0xff, 0xff, 0x43, 0x55, 0xde, 0xba, 0x8f, 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("transactions/service.proto", fileDescriptor_service_3dc77ed74e902ae6) } + +var fileDescriptor_service_3dc77ed74e902ae6 = []byte{ + // 348 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x4a, 0xeb, 0x40, + 0x14, 0xc6, 0x99, 0xde, 0x4b, 0x2f, 0x77, 0x5a, 0x45, 0x06, 0x29, 0x63, 0x10, 0x0d, 0x05, 0xb5, + 0x0b, 0x9b, 0x40, 0x5d, 0xbb, 0x68, 0x37, 0xc5, 0x5d, 0xa9, 0x75, 0xe3, 0xa6, 0x4c, 0x93, 0x63, + 0x08, 0x34, 0x99, 0x31, 0x67, 0xa2, 0x0b, 0x71, 0xe3, 0x23, 0xe8, 0x5b, 0xb8, 0xf5, 0x09, 0x7c, + 0x06, 0x5f, 0xc1, 0x07, 0x91, 0xce, 0xa4, 0x38, 0xa5, 0x8a, 0xae, 0xc2, 0x39, 0xdf, 0x97, 0xf3, + 0xe7, 0x77, 0x86, 0x7a, 0xba, 0x10, 0x39, 0x8a, 0x48, 0xa7, 0x32, 0xc7, 0x10, 0xa1, 0xb8, 0x49, + 0x23, 0x08, 0x54, 0x21, 0xb5, 0x64, 0x4d, 0x57, 0xf3, 0x76, 0x13, 0x29, 0x93, 0x39, 0x84, 0x42, + 0xa5, 0xa1, 0xc8, 0x73, 0xa9, 0x85, 0xc9, 0x5b, 0xaf, 0xb7, 0x5f, 0xa9, 0x26, 0x9a, 0x95, 0x57, + 0xa1, 0x4e, 0x33, 0x40, 0x2d, 0x32, 0x55, 0x19, 0x8e, 0xcd, 0x27, 0xea, 0x26, 0x90, 0x77, 0xf1, + 0x56, 0x24, 0x09, 0x14, 0xa1, 0x54, 0xb6, 0xed, 0x5a, 0xb9, 0x76, 0x9f, 0xf2, 0xc9, 0x67, 0xf3, + 0x73, 0x2d, 0x74, 0x89, 0x63, 0xb8, 0x2e, 0x01, 0x35, 0x3b, 0xa0, 0x9b, 0xce, 0x60, 0xd3, 0x34, + 0xe6, 0xc4, 0x27, 0x9d, 0xff, 0xe3, 0x0d, 0x27, 0x7b, 0x16, 0xb7, 0x5f, 0x08, 0xdd, 0xf9, 0xa2, + 0x06, 0x2a, 0x99, 0x23, 0xfc, 0xb2, 0x08, 0x6b, 0xd1, 0x3a, 0x9a, 0x1f, 0x79, 0xcd, 0xc8, 0x55, + 0xc4, 0x38, 0xfd, 0x97, 0x01, 0xa2, 0x48, 0x80, 0xff, 0x31, 0xc2, 0x32, 0x64, 0xa7, 0xb4, 0x39, + 0x17, 0xa8, 0xa7, 0xa5, 0x8a, 0x85, 0x86, 0x98, 0xff, 0xf5, 0x49, 0xa7, 0xd1, 0xf3, 0x02, 0xcb, + 0x27, 0x58, 0xf2, 0x09, 0x26, 0x4b, 0x3e, 0xe3, 0xc6, 0xc2, 0x7f, 0x61, 0xed, 0xbd, 0x57, 0x42, + 0x99, 0x3b, 0xb5, 0x3d, 0x08, 0x7b, 0x26, 0x74, 0x7b, 0x08, 0x7a, 0x6d, 0x1f, 0x76, 0x18, 0xb8, + 0x47, 0x0a, 0xbe, 0x83, 0xe6, 0x1d, 0xfd, 0xe8, 0xb3, 0x60, 0xda, 0xfd, 0xc7, 0x3e, 0xf7, 0x5a, + 0x43, 0xd0, 0xbe, 0xe3, 0xf1, 0xad, 0xe9, 0xe1, 0xed, 0xfd, 0xa9, 0xe6, 0xb3, 0xbd, 0x70, 0xe5, + 0xd1, 0xdc, 0xad, 0x82, 0xbc, 0x1f, 0xf4, 0xe8, 0x56, 0x24, 0xb3, 0x95, 0x86, 0x83, 0x66, 0xb5, + 0xc9, 0x68, 0xb1, 0xff, 0x88, 0x5c, 0xba, 0xf4, 0x51, 0xcd, 0x66, 0x75, 0x03, 0xe6, 0xe4, 0x23, + 0x00, 0x00, 0xff, 0xff, 0x1f, 0xcd, 0x20, 0xdd, 0x90, 0x02, 0x00, 0x00, } diff --git a/protobufs/gen/go/transactions/service.pb.gw.go b/protobufs/gen/go/transactions/service.pb.gw.go index 21cf13fd8..ae542e6db 100644 --- a/protobufs/gen/go/transactions/service.pb.gw.go +++ b/protobufs/gen/go/transactions/service.pb.gw.go @@ -126,7 +126,7 @@ func RegisterTransactionServiceHandlerClient(ctx context.Context, mux *runtime.S } var ( - pattern_TransactionService_GetTransactionStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"transaction", "transaction_id"}, "")) + pattern_TransactionService_GetTransactionStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"transactions", "transaction_id"}, "")) ) var ( diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index df5e349a9..1ddf804ab 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transaction/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"},"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/invoice/service.swagger.json b/protobufs/gen/swagger/invoice/service.swagger.json index 806c59901..96a0daaf5 100644 --- a/protobufs/gen/swagger/invoice/service.swagger.json +++ b/protobufs/gen/swagger/invoice/service.swagger.json @@ -282,6 +282,9 @@ "items": { "type": "string" } + }, + "transaction_id": { + "type": "string" } }, "title": "ResponseHeader contains a set of common fields for most documents" diff --git a/protobufs/gen/swagger/nft/service.swagger.json b/protobufs/gen/swagger/nft/service.swagger.json index 31792eb39..4027d8127 100644 --- a/protobufs/gen/swagger/nft/service.swagger.json +++ b/protobufs/gen/swagger/nft/service.swagger.json @@ -71,6 +71,9 @@ "properties": { "token_id": { "type": "string" + }, + "transaction_id": { + "type": "string" } } } diff --git a/protobufs/gen/swagger/purchaseorder/service.swagger.json b/protobufs/gen/swagger/purchaseorder/service.swagger.json index 072ae93c7..143880d90 100644 --- a/protobufs/gen/swagger/purchaseorder/service.swagger.json +++ b/protobufs/gen/swagger/purchaseorder/service.swagger.json @@ -285,6 +285,9 @@ "items": { "type": "string" } + }, + "transaction_id": { + "type": "string" } }, "title": "ResponseHeader contains a set of common fields for most documents" diff --git a/protobufs/gen/swagger/transactions/service.swagger.json b/protobufs/gen/swagger/transactions/service.swagger.json index f7cf06922..d45ed24a3 100644 --- a/protobufs/gen/swagger/transactions/service.swagger.json +++ b/protobufs/gen/swagger/transactions/service.swagger.json @@ -15,7 +15,7 @@ "application/json" ], "paths": { - "/transaction/{transaction_id}": { + "/transactions/{transaction_id}": { "get": { "description": "Get Transaction Status", "operationId": "GetTransactionStatus", diff --git a/protobufs/invoice/service.proto b/protobufs/invoice/service.proto index efe84bb88..6796074c2 100644 --- a/protobufs/invoice/service.proto +++ b/protobufs/invoice/service.proto @@ -80,6 +80,7 @@ message ResponseHeader { string version_id = 2; string state = 3; repeated string collaborators = 4; + string transaction_id = 5; } message InvoiceData { diff --git a/protobufs/nft/service.proto b/protobufs/nft/service.proto index 83cd2e0c2..807276b98 100644 --- a/protobufs/nft/service.proto +++ b/protobufs/nft/service.proto @@ -34,4 +34,5 @@ message NFTMintRequest { message NFTMintResponse { string token_id = 1; + string transaction_id = 2; } diff --git a/protobufs/purchaseorder/service.proto b/protobufs/purchaseorder/service.proto index 39d1dd91a..952fb6093 100644 --- a/protobufs/purchaseorder/service.proto +++ b/protobufs/purchaseorder/service.proto @@ -80,6 +80,7 @@ message ResponseHeader { string version_id = 2; string state = 3; repeated string collaborators = 4; + string transaction_id = 5; } message PurchaseOrderData { diff --git a/protobufs/transactions/service.proto b/protobufs/transactions/service.proto index 407b40975..0e0c18afc 100644 --- a/protobufs/transactions/service.proto +++ b/protobufs/transactions/service.proto @@ -25,7 +25,7 @@ message TransactionStatusResponse { service TransactionService { rpc GetTransactionStatus(TransactionStatusRequest) returns (TransactionStatusResponse) { option (google.api.http) = { - get: "/transaction/{transaction_id}" + get: "/transactions/{transaction_id}" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Get Transaction Status" diff --git a/queue/server.go b/queue/server.go index ff4e95755..231fac327 100644 --- a/queue/server.go +++ b/queue/server.go @@ -120,3 +120,8 @@ func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { } return 0, errors.New("value can not be parsed") } + +// TaskQueuer can be implemented by any queueing system +type TaskQueuer interface { + EnqueueJob(taskTypeName string, params map[string]interface{}) (TaskResult, error) +} diff --git a/testingutils/utils.go b/testingutils/utils.go index 3a3e291a5..ae5d2fd13 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -4,6 +4,8 @@ package testingutils import ( "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/stretchr/testify/mock" ) func MockConfigOption(cfg config.Configuration, key string, value interface{}) func() { @@ -23,3 +25,13 @@ func (m *MockSubscription) Err() <-chan error { } func (*MockSubscription) Unsubscribe() {} + +type MockQueue struct { + mock.Mock +} + +func (m *MockQueue) EnqueueJob(taskTypeName string, params map[string]interface{}) (queue.TaskResult, error) { + args := m.Called(taskTypeName, params) + res, _ := args.Get(0).(queue.TaskResult) + return res, args.Error(1) +} diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index dc3175bce..0f361727c 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -37,6 +37,8 @@ func addExternalCollaborator(t *testing.T, documentType string) { // Alice shares document with Bob first res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) + txID := getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -52,6 +54,8 @@ func addExternalCollaborator(t *testing.T, documentType string) { // Bob updates invoice and shares with Charlie as well res = updateDocument(bob.httpExpect, documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{alice.id.String(), charlie.id.String()})) + txID = getTransactionID(t, res) + waitTillSuccess(t, bob.httpExpect, txID) docIdentifier = getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -80,6 +84,8 @@ func collaboratorTimeOut(t *testing.T, documentType string) { // Kenny shares a document with Bob response := createDocument(kenny.httpExpect, documentType, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) + txID := getTransactionID(t, response) + waitTillSuccess(t, kenny.httpExpect, txID) // check if Bob and Kenny received the document docIdentifier := getDocumentIdentifier(t, response) @@ -98,6 +104,8 @@ func collaboratorTimeOut(t *testing.T, documentType string) { // Bob will anchor the document without Alice signature but will receive an error because kenny is dead response = updateDocument(bob.httpExpect, documentType, http.StatusInternalServerError, docIdentifier, updatedPayload) + txID = getTransactionID(t, response) + waitTillSuccess(t, bob.httpExpect, txID) // check if bob saved the updated document paramsV2 := map[string]interface{}{ diff --git a/testworld/httputils.go b/testworld/httputils.go index 1827b1e1f..8f273e650 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "net/http" "testing" + "time" "github.com/gavv/httpexpect" ) @@ -63,6 +64,15 @@ func getDocumentIdentifier(t *testing.T, response *httpexpect.Object) string { return docIdentifier } +func getTransactionID(t *testing.T, resp *httpexpect.Object) string { + txID := resp.Value("header").Path("$.transaction_id").String().Raw() + if txID == "" { + t.Error("transaction ID empty") + } + + return txID +} + func mintNFT(e *httpexpect.Expect, httpStatus int, payload map[string]interface{}) *httpexpect.Object { resp := e.POST("/token/mint"). WithHeader("accept", "application/json"). @@ -115,3 +125,20 @@ func createInsecureClient() *http.Client { } return &http.Client{Transport: tr} } + +func waitTillSuccess(t *testing.T, e *httpexpect.Expect, txID string) { + for { + resp := e.GET("/transactions/" + txID).Expect().Status(200).JSON().Object() + status := resp.Path("$.status").String().Raw() + if status == "pending" { + time.Sleep(100 * time.Millisecond) + continue + } + + if status == "failed" { + t.Error(resp.Path("$.message").String().Raw()) + } + + break + } +} diff --git a/testworld/nft_test.go b/testworld/nft_test.go index bd125c3f5..c16f43e83 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -32,6 +32,8 @@ func paymentObligationMint(t *testing.T, documentType string) { // Alice shares document with Bob res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultNFTPayload(documentType, []string{bob.id.String()})) + txID := getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { diff --git a/testworld/park_test.go b/testworld/park_test.go index e0bea509d..a4cff665f 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -16,6 +16,8 @@ func TestHost_Happy(t *testing.T) { // alice shares a document with bob and charlie res := createDocument(alice.httpExpect, typeInvoice, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) + txID := getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) docIdentifier := getDocumentIdentifier(t, res) diff --git a/testworld/proof_test.go b/testworld/proof_test.go index c4f0882e2..742541aab 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -27,6 +27,8 @@ func proofWithMultipleFields_successful(t *testing.T, documentType string) { // Alice shares a document with Bob res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) + txID := getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { diff --git a/transactions/base_task.go b/transactions/base_task.go new file mode 100644 index 000000000..02d4050b8 --- /dev/null +++ b/transactions/base_task.go @@ -0,0 +1,53 @@ +package transactions + +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" +) + +const ( + // TxIDParam maps transaction ID in the kwargs. + TxIDParam = "transactionID" +) + +// BaseTask holds the required details and helper functions for tasks to update transactions. +// should be embedded into the task +type BaseTask struct { + TxID uuid.UUID + TxService Service +} + +// ParseTransactionID parses txID. +func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { + txID, ok := kwargs[TxIDParam].(string) + if !ok { + return errors.New("missing transaction ID") + } + + var err error + b.TxID, err = uuid.FromString(txID) + if err != nil { + return errors.New("invalid transaction ID") + } + + return nil +} + +// UpdateTransaction add a new log and updates the status of the transaction based on the error. +func (b *BaseTask) UpdateTransaction(tenantID common.Address, name string, err error) error { + tx, erri := b.TxService.GetTransaction(tenantID, b.TxID) + if erri != nil { + return errors.AppendError(err, erri) + } + + if err == nil { + tx.Status = Success + tx.Logs = append(tx.Logs, NewLog(name, "")) + return b.TxService.SaveTransaction(tx) + } + + tx.Status = Failed + tx.Logs = append(tx.Logs, NewLog(name, err.Error())) + return errors.AppendError(err, b.TxService.SaveTransaction(tx)) +} diff --git a/transactions/base_task_test.go b/transactions/base_task_test.go new file mode 100644 index 000000000..84f21788b --- /dev/null +++ b/transactions/base_task_test.go @@ -0,0 +1,53 @@ +// +build unit + +package transactions + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/assert" +) + +func TestDocumentAnchorTask_updateTransaction(t *testing.T) { + task := new(BaseTask) + + tenantID := common.DummyIdentity + name := "some task" + task.TxID = uuid.Must(uuid.NewV4()) + task.TxService = NewService(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) + + // missing transaction with nil error + err := task.UpdateTransaction(tenantID, name, nil) + err = errors.GetErrs(err)[0] + assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + + // missing transaction with error + err = task.UpdateTransaction(tenantID, name, errors.New("anchor error")) + err = errors.GetErrs(err)[1] + assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + + // no error and success + tx := NewTransaction(tenantID, "") + assert.NoError(t, task.TxService.SaveTransaction(tx)) + task.TxID = tx.ID + assert.NoError(t, task.UpdateTransaction(tenantID, name, nil)) + tx, err = task.TxService.GetTransaction(tenantID, task.TxID) + assert.NoError(t, err) + assert.Equal(t, tx.Status, Success) + assert.Len(t, tx.Logs, 1) + + // failed task + tx = NewTransaction(tenantID, "") + assert.NoError(t, task.TxService.SaveTransaction(tx)) + task.TxID = tx.ID + err = task.UpdateTransaction(tenantID, name, errors.New("anchor error")) + assert.EqualError(t, errors.GetErrs(err)[0], "anchor error") + tx, err = task.TxService.GetTransaction(tenantID, task.TxID) + assert.NoError(t, err) + assert.Equal(t, tx.Status, Failed) + assert.Len(t, tx.Logs, 1) +} diff --git a/transactions/service.go b/transactions/service.go index e91a70185..361f03d22 100644 --- a/transactions/service.go +++ b/transactions/service.go @@ -1,6 +1,9 @@ package transactions import ( + "time" + + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" @@ -9,7 +12,11 @@ import ( // Service wraps the repository and exposes specific functions. type Service interface { + CreateTransaction(tenantID common.Address, desc string) (*Transaction, error) + GetTransaction(tenantID common.Address, id uuid.UUID) (*Transaction, error) + SaveTransaction(tx *Transaction) error GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) + WaitForTransaction(tenantID common.Address, txID uuid.UUID) error } // NewService returns a Service implementation. @@ -22,9 +29,46 @@ type service struct { repo Repository } +// SaveTransaction saves the transaction. +func (s service) SaveTransaction(tx *Transaction) error { + return s.repo.Save(tx) +} + +// GetTransaction returns the transaction associated with identity and id. +func (s service) GetTransaction(tenantID common.Address, id uuid.UUID) (*Transaction, error) { + return s.repo.Get(tenantID, id) +} + +// CreateTransaction creates a new transaction and saves it to the DB. +func (s service) CreateTransaction(tenantID common.Address, desc string) (*Transaction, error) { + tx := NewTransaction(tenantID, desc) + return tx, s.SaveTransaction(tx) +} + +// WaitForTransaction blocks until transaction status is moved from pending state. +// Note: use it with caution as this will block. +func (s service) WaitForTransaction(tenantID common.Address, txID uuid.UUID) error { + for { + resp, err := s.GetTransactionStatus(tenantID, txID) + if err != nil { + return err + } + + switch Status(resp.Status) { + case Failed: + return errors.New("transaction failed: %v", resp.Message) + case Success: + return nil + default: + time.Sleep(10 * time.Millisecond) + continue + } + } +} + // GetTransactionStatus returns the transaction status associated with identity and id. func (s service) GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { - tx, err := s.repo.Get(identity, id) + tx, err := s.GetTransaction(identity, id) if err != nil { return nil, err } diff --git a/transactions/service_test.go b/transactions/service_test.go index 4fca799e4..dd723046f 100644 --- a/transactions/service_test.go +++ b/transactions/service_test.go @@ -15,7 +15,7 @@ func TestService_GetTransaction(t *testing.T) { repo := ctx[BootstrappedRepo].(Repository) srv := ctx[BootstrappedService].(Service) - identity := common.Address([20]byte{}) + identity := common.Address([20]byte{1}) bytes := utils.RandomSlice(common.AddressLength) assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) txn := NewTransaction(identity, "Some transaction") @@ -52,3 +52,32 @@ func TestService_GetTransaction(t *testing.T) { assert.Equal(t, log.Message, txs.Message) assert.Equal(t, utils.ToTimestamp(log.CreatedAt), txs.LastUpdated) } + +func TestService_CreateTransaction(t *testing.T) { + srv := ctx[BootstrappedService].(Service) + identity := common.Address([20]byte{1}) + tx, err := srv.CreateTransaction(identity, "test") + assert.NoError(t, err) + assert.NotNil(t, tx) + assert.Equal(t, identity.String(), tx.Identity.String()) +} + +func TestService_WaitForTransaction(t *testing.T) { + srv := ctx[BootstrappedService].(Service) + repo := ctx[BootstrappedRepo].(Repository) + identity := common.Address([20]byte{1}) + + // failed + tx, err := srv.CreateTransaction(identity, "test") + assert.NoError(t, err) + assert.NotNil(t, tx) + assert.Equal(t, identity.String(), tx.Identity.String()) + tx.Status = Failed + assert.NoError(t, repo.Save(tx)) + assert.Error(t, srv.WaitForTransaction(identity, tx.ID)) + + // success + tx.Status = Success + assert.NoError(t, repo.Save(tx)) + assert.NoError(t, srv.WaitForTransaction(identity, tx.ID)) +} From d0a881868c2f2d42c25389ee678a759fdcb1b2aa Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Thu, 3 Jan 2019 15:47:20 +0100 Subject: [PATCH 109/220] increment sleep to 1 sec --- testworld/httputils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testworld/httputils.go b/testworld/httputils.go index 8f273e650..fd4d80bb7 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -131,7 +131,7 @@ func waitTillSuccess(t *testing.T, e *httpexpect.Expect, txID string) { resp := e.GET("/transactions/" + txID).Expect().Status(200).JSON().Object() status := resp.Path("$.status").String().Raw() if status == "pending" { - time.Sleep(100 * time.Millisecond) + time.Sleep(1 * time.Second) continue } From 6d13eb7784dd14d817292b1fdfb780cb854ff98a Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 4 Jan 2019 16:03:15 +0100 Subject: [PATCH 110/220] [MultiTenancy] Use db stored config at runtime (#603) * Enable config database and api * Enable config database and api * Minor * Fix createConfig issue * Add Testworld test for config API * Fix bug with GET /config/tenant/list (end point url ambigous) * Fix bug with GET /config/tenant/list (end point url ambigous) * Lint fix * Generate swagger * Remove race detection from TestWorld to improve perf * Use db stored config at runtime * Lint and swagger * Fix unit tests * Fix tests * Fix unit tests * Remove -race from testworld * Fix conflicts * Try testworld without -race * merging * Merging still * Fix confgi * Fix test --- anchors/anchor.go | 4 +- anchors/bootstrapper.go | 10 +- api/bootstrapper.go | 8 +- build/scripts/tests/run_testworld.sh | 2 +- config/configstore/error.go | 3 + config/configstore/handler.go | 14 +- config/configstore/mock_service.go | 2 +- config/configstore/model.go | 243 +++++++++++++++++- config/configstore/model_test.go | 52 +++- config/configstore/service.go | 28 ++ config/configuration.go | 28 +- coredocument/bootstrapper.go | 8 +- documents/bootstrapper.go | 8 +- documents/invoice/bootstrapper.go | 14 +- documents/invoice/model_test.go | 6 +- documents/purchaseorder/bootstrapper.go | 13 +- documents/purchaseorder/model_test.go | 3 + ethereum/bootstrapper.go | 12 +- identity/bootstrapper.go | 11 +- identity/identity.go | 4 +- nft/bootstrapper.go | 7 +- nft/ethereum_payment_obligation.go | 4 +- nft/payment_obligation_integration_test.go | 2 +- p2p/bootstrapper.go | 8 +- p2p/bootstrapper_test.go | 3 + p2p/server.go | 1 + protobufs/config/service.proto | 2 + protobufs/gen/go/config/service.pb.go | 200 +++++++------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 10 + queue/bootstrapper.go | 10 +- resources/data.go | 6 +- storage/test_bootstrapper.go | 4 +- testingutils/config/config.go | 2 +- 34 files changed, 569 insertions(+), 165 deletions(-) diff --git a/anchors/anchor.go b/anchors/anchor.go index 1c1d739e5..fac6dc398 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -3,6 +3,8 @@ package anchors import ( "math/big" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "time" @@ -34,7 +36,7 @@ type AnchorID [AnchorIDLength]byte type Config interface { GetEthereumDefaultAccountName() string GetEthereumContextWaitTimeout() time.Duration - GetContractAddress(address string) common.Address + GetContractAddress(contractName config.ContractName) common.Address } // ToAnchorID convert the bytes into AnchorID type diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 6a9e55446..098f4459e 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -1,6 +1,8 @@ package anchors import ( + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -17,17 +19,17 @@ type Bootstrapper struct{} // Bootstrap initializes the anchorRepositoryContract as well as the anchorConfirmationTask that depends on it. // the anchorConfirmationTask is added to be registered on the Queue at queue.Bootstrapper. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(false, ctx) + if err != nil { + return err } - cfg := ctx[bootstrap.BootstrappedConfig].(Config) if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress("anchorRepository"), client.GetEthClient()) + repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress(config.AnchorRepo), client.GetEthClient()) if err != nil { return err } diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 03ffdecf8..a18f773ad 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -12,12 +12,12 @@ type Bootstrapper struct{} // Bootstrap initiates api server func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[bootstrap.BootstrappedConfig].(Config) - if !ok { - return errors.New("config not initialised") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } - _, ok = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + _, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) if !ok { return errors.New("config store not initialised") } diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index 8a5c99cfb..7c6fce4e6 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -8,7 +8,7 @@ eval "$cleanup" status=$? -output="go test -race -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" +output="go test -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done if [ ${PIPESTATUS[0]} -ne 0 ]; then status=1 diff --git a/config/configstore/error.go b/config/configstore/error.go index 43b2986c4..e1152c8a8 100644 --- a/config/configstore/error.go +++ b/config/configstore/error.go @@ -5,4 +5,7 @@ import "github.com/centrifuge/go-centrifuge/errors" const ( // ErrConfigStorageBootstrap must be returned when there is an error while bootstrapping the config storage ErrConfigStorageBootstrap = errors.Error("error when bootstrapping config storage") + + // ErrConfigRetrieve must be returned when there is an error while retrieving config + ErrConfigRetrieve = errors.Error("error when retrieving config") ) diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 44d3cb85a..b5e207b42 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -60,8 +60,11 @@ func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*config func (h grpcHandler) CreateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { apiLog.Infof("Creating node config: %v", data) nodeConfig := new(NodeConfig) - nodeConfig.loadFromProtobuf(data) - nodeConfig, err := h.service.CreateConfig(nodeConfig) + err := nodeConfig.loadFromProtobuf(data) + if err != nil { + return nil, err + } + nodeConfig, err = h.service.CreateConfig(nodeConfig) if err != nil { return nil, err } @@ -82,8 +85,11 @@ func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { apiLog.Infof("Updating node config: %v", data) nodeConfig := new(NodeConfig) - nodeConfig.loadFromProtobuf(data) - nodeConfig, err := h.service.UpdateConfig(nodeConfig) + err := nodeConfig.loadFromProtobuf(data) + if err != nil { + return nil, err + } + nodeConfig, err = h.service.UpdateConfig(nodeConfig) if err != nil { return nil, err } diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 11c4a87d4..53efcde2d 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -9,7 +9,7 @@ type MockService struct { } func (MockService) GetConfig() (*NodeConfig, error) { - panic("implement me") + return nil, nil } func (MockService) GetTenant(identifier []byte) (*TenantConfig, error) { diff --git a/config/configstore/model.go b/config/configstore/model.go index 6e02fd280..7bfc25b43 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -6,6 +6,10 @@ import ( "reflect" "time" + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/config" "github.com/ethereum/go-ethereum/common/hexutil" @@ -46,6 +50,203 @@ type NodeConfig struct { NetworkString string BootstrapPeers []string NetworkID uint32 + SmartContractAddresses map[config.ContractName]common.Address + PprofEnabled bool +} + +// IsSet refer the interface +func (nc *NodeConfig) IsSet(key string) bool { + panic("irrelevant, NodeConfig#IsSet must not be used") +} + +// Set refer the interface +func (nc *NodeConfig) Set(key string, value interface{}) { + panic("irrelevant, NodeConfig#Set must not be used") +} + +// SetDefault refer the interface +func (nc *NodeConfig) SetDefault(key string, value interface{}) { + panic("irrelevant, NodeConfig#SetDefault must not be used") +} + +// SetupSmartContractAddresses refer the interface +func (nc *NodeConfig) SetupSmartContractAddresses(network string, smartContractAddresses *config.SmartContractAddresses) { + panic("irrelevant, NodeConfig#SetupSmartContractAddresses must not be used") +} + +// Get refer the interface +func (nc *NodeConfig) Get(key string) interface{} { + panic("irrelevant, NodeConfig#Get must not be used") +} + +// GetString refer the interface +func (nc *NodeConfig) GetString(key string) string { + panic("irrelevant, NodeConfig#GetString must not be used") +} + +// GetBool refer the interface +func (nc *NodeConfig) GetBool(key string) bool { + panic("irrelevant, NodeConfig#GetBool must not be used") +} + +// GetInt refer the interface +func (nc *NodeConfig) GetInt(key string) int { + panic("irrelevant, NodeConfig#GetInt must not be used") +} + +// GetDuration refer the interface +func (nc *NodeConfig) GetDuration(key string) time.Duration { + panic("irrelevant, NodeConfig#GetDuration must not be used") +} + +// GetStoragePath refer the interface +func (nc *NodeConfig) GetStoragePath() string { + return nc.StoragePath +} + +// GetConfigStoragePath refer the interface +func (nc *NodeConfig) GetConfigStoragePath() string { + panic("irrelevant, NodeConfig#GetConfigStoragePath must not be used") +} + +// GetP2PPort refer the interface +func (nc *NodeConfig) GetP2PPort() int { + return nc.P2PPort +} + +// GetP2PExternalIP refer the interface +func (nc *NodeConfig) GetP2PExternalIP() string { + return nc.P2PExternalIP +} + +// GetP2PConnectionTimeout refer the interface +func (nc *NodeConfig) GetP2PConnectionTimeout() time.Duration { + return nc.P2PConnectionTimeout +} + +// GetServerPort refer the interface +func (nc *NodeConfig) GetServerPort() int { + return nc.ServerPort +} + +// GetServerAddress refer the interface +func (nc *NodeConfig) GetServerAddress() string { + return nc.ServerAddress +} + +// GetNumWorkers refer the interface +func (nc *NodeConfig) GetNumWorkers() int { + return nc.NumWorkers +} + +// GetWorkerWaitTimeMS refer the interface +func (nc *NodeConfig) GetWorkerWaitTimeMS() int { + return nc.WorkerWaitTimeMS +} + +// GetEthereumNodeURL refer the interface +func (nc *NodeConfig) GetEthereumNodeURL() string { + return nc.EthereumNodeURL +} + +// GetEthereumContextReadWaitTimeout refer the interface +func (nc *NodeConfig) GetEthereumContextReadWaitTimeout() time.Duration { + return nc.EthereumContextReadWaitTimeout +} + +// GetEthereumContextWaitTimeout refer the interface +func (nc *NodeConfig) GetEthereumContextWaitTimeout() time.Duration { + return nc.EthereumContextWaitTimeout +} + +// GetEthereumIntervalRetry refer the interface +func (nc *NodeConfig) GetEthereumIntervalRetry() time.Duration { + return nc.EthereumIntervalRetry +} + +// GetEthereumMaxRetries refer the interface +func (nc *NodeConfig) GetEthereumMaxRetries() int { + return nc.EthereumMaxRetries +} + +// GetEthereumGasPrice refer the interface +func (nc *NodeConfig) GetEthereumGasPrice() *big.Int { + return nc.EthereumGasPrice +} + +// GetEthereumGasLimit refer the interface +func (nc *NodeConfig) GetEthereumGasLimit() uint64 { + return nc.EthereumGasLimit +} + +// GetTxPoolAccessEnabled refer the interface +func (nc *NodeConfig) GetTxPoolAccessEnabled() bool { + return nc.TxPoolAccessEnabled +} + +// GetNetworkString refer the interface +func (nc *NodeConfig) GetNetworkString() string { + return nc.NetworkString +} + +// GetNetworkKey refer the interface +func (nc *NodeConfig) GetNetworkKey(k string) string { + panic("irrelevant, NodeConfig#GetNetworkKey must not be used") +} + +// GetContractAddressString refer the interface +func (nc *NodeConfig) GetContractAddressString(address string) string { + panic("irrelevant, NodeConfig#GetContractAddressString must not be used") +} + +// GetContractAddress refer the interface +func (nc *NodeConfig) GetContractAddress(contractName config.ContractName) common.Address { + return nc.SmartContractAddresses[contractName] +} + +// GetBootstrapPeers refer the interface +func (nc *NodeConfig) GetBootstrapPeers() []string { + return nc.BootstrapPeers +} + +// GetNetworkID refer the interface +func (nc *NodeConfig) GetNetworkID() uint32 { + return nc.NetworkID +} + +// GetEthereumAccount refer the interface +func (nc *NodeConfig) GetEthereumAccount(accountName string) (account *config.AccountConfig, err error) { + return nc.MainIdentity.EthereumAccount, nil +} + +// GetEthereumDefaultAccountName refer the interface +func (nc *NodeConfig) GetEthereumDefaultAccountName() string { + return nc.MainIdentity.EthereumDefaultAccountName +} + +// GetReceiveEventNotificationEndpoint refer the interface +func (nc *NodeConfig) GetReceiveEventNotificationEndpoint() string { + return nc.MainIdentity.ReceiveEventNotificationEndpoint +} + +// GetIdentityID refer the interface +func (nc *NodeConfig) GetIdentityID() ([]byte, error) { + return nc.MainIdentity.IdentityID, nil +} + +// GetSigningKeyPair refer the interface +func (nc *NodeConfig) GetSigningKeyPair() (pub, priv string) { + return nc.MainIdentity.SigningKeyPair.Pub, nc.MainIdentity.SigningKeyPair.Priv +} + +// GetEthAuthKeyPair refer the interface +func (nc *NodeConfig) GetEthAuthKeyPair() (pub, priv string) { + return nc.MainIdentity.EthAuthKeyPair.Pub, nc.MainIdentity.EthAuthKeyPair.Priv +} + +// IsPProfEnabled refer the interface +func (nc *NodeConfig) IsPProfEnabled() bool { + return nc.PprofEnabled } // ID Gets the ID of the document represented by this model @@ -104,10 +305,20 @@ func (nc *NodeConfig) createProtobuf() *configpb.ConfigData { TxPoolEnabled: nc.TxPoolAccessEnabled, Network: nc.NetworkString, NetworkId: nc.NetworkID, + PprofEnabled: nc.PprofEnabled, + SmartContractAddresses: convertAddressesToStringMap(nc.SmartContractAddresses), } } -func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) { +func convertAddressesToStringMap(addresses map[config.ContractName]common.Address) map[string]string { + m := make(map[string]string) + for k, v := range addresses { + m[string(k)] = v.String() + } + return m +} + +func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) error { identityID, _ := hexutil.Decode(data.MainIdentity.IdentityId) nc.MainIdentity = TenantConfig{ @@ -147,6 +358,25 @@ func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) { nc.NetworkString = data.Network nc.BootstrapPeers = data.BootstrapPeers nc.NetworkID = data.NetworkId + var err error + nc.SmartContractAddresses, err = convertStringMapToSmartContractAddresses(data.SmartContractAddresses) + if err != nil { + return err + } + nc.PprofEnabled = data.PprofEnabled + return nil +} + +func convertStringMapToSmartContractAddresses(addrs map[string]string) (map[config.ContractName]common.Address, error) { + m := make(map[config.ContractName]common.Address) + for k, v := range addrs { + if common.IsHexAddress(v) { + m[config.ContractName(k)] = common.HexToAddress(v) + } else { + return nil, errors.New("provided smart contract address %s is invalid", v) + } + } + return m, nil } // NewNodeConfig creates a new NodeConfig instance with configs @@ -194,7 +424,18 @@ func NewNodeConfig(c config.Configuration) *NodeConfig { NetworkString: c.GetNetworkString(), BootstrapPeers: c.GetBootstrapPeers(), NetworkID: c.GetNetworkID(), + SmartContractAddresses: extractSmartContractAddresses(c), + PprofEnabled: c.IsPProfEnabled(), + } +} + +func extractSmartContractAddresses(c config.Configuration) map[config.ContractName]common.Address { + sms := make(map[config.ContractName]common.Address) + names := config.ContractNames() + for _, n := range names { + sms[n] = c.GetContractAddress(n) } + return sms } // TenantConfig exposes configs specific to a tenant in the node diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 71775a1ed..ae08415f0 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -19,10 +19,56 @@ import ( ) type mockConfig struct { - config.Configuration mock.Mock } +func (m *mockConfig) IsSet(key string) bool { + args := m.Called(key) + return args.Get(0).(bool) +} + +func (m *mockConfig) Set(key string, value interface{}) { + m.Called(key, value) +} + +func (m *mockConfig) SetDefault(key string, value interface{}) { + m.Called(key, value) +} + +func (m *mockConfig) SetupSmartContractAddresses(network string, smartContractAddresses *config.SmartContractAddresses) { + m.Called(network, smartContractAddresses) +} + +func (m *mockConfig) Get(key string) interface{} { + args := m.Called(key) + return args.Get(0) +} + +func (m *mockConfig) GetString(key string) string { + args := m.Called(key) + return args.Get(0).(string) +} + +func (m *mockConfig) GetBool(key string) bool { + args := m.Called(key) + return args.Get(0).(bool) +} + +func (m *mockConfig) GetInt(key string) int { + args := m.Called(key) + return args.Get(0).(int) +} + +func (m *mockConfig) GetDuration(key string) time.Duration { + args := m.Called(key) + return args.Get(0).(time.Duration) +} + +func (m *mockConfig) IsPProfEnabled() bool { + args := m.Called() + return args.Get(0).(bool) +} + func (m *mockConfig) GetStoragePath() string { args := m.Called() return args.Get(0).(string) @@ -138,7 +184,7 @@ func (m *mockConfig) GetContractAddressString(address string) string { return args.Get(0).(string) } -func (m *mockConfig) GetContractAddress(address string) common.Address { +func (m *mockConfig) GetContractAddress(contractName config.ContractName) common.Address { args := m.Called() return args.Get(0).(common.Address) } @@ -255,5 +301,7 @@ func createMockConfig() *mockConfig { c.On("GetNetworkString").Return("somehill").Once() c.On("GetBootstrapPeers").Return([]string{"p1", "p2"}).Once() c.On("GetNetworkID").Return(uint32(1)).Once() + c.On("GetContractAddress", mock.Anything).Return(common.Address{}) + c.On("IsPProfEnabled", mock.Anything).Return(true) return c } diff --git a/config/configstore/service.go b/config/configstore/service.go index 36832ffb8..cbb6630db 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -1,5 +1,11 @@ package configstore +import ( + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" +) + // Service exposes functions over the config objects type Service interface { GetConfig() (*NodeConfig, error) @@ -57,3 +63,25 @@ func (s service) DeleteConfig() error { func (s service) DeleteTenant(identifier []byte) error { return s.repo.DeleteTenant(identifier) } + +// RetrieveConfig retrieves system config giving priority to db store config +func RetrieveConfig(dbOnly bool, ctx map[string]interface{}) (config.Configuration, error) { + var cfg config.Configuration + var err error + if cfgService, ok := ctx[BootstrappedConfigStorage].(Service); ok { + // may be we need a way to detect a corrupted db here + cfg, err = cfgService.GetConfig() + if err != nil { + apiLog.Warningf("could not load config from db: %v", err) + } + return cfg, nil + } + + // we have to allow loading from file in case this is coming from create config cmd where we don't add configs to db + if _, ok := ctx[bootstrap.BootstrappedConfig]; ok && cfg == nil && !dbOnly { + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + } else { + return nil, errors.NewTypedError(ErrConfigRetrieve, err) + } + return cfg, nil +} diff --git a/config/configuration.go b/config/configuration.go index 09e597c42..f18929f59 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -28,6 +28,28 @@ import ( var log = logging.Logger("config") +// ContractName is a type to indicate a contract name parameter +type ContractName string + +const ( + // AnchorRepo is the contract name for AnchorRepo + AnchorRepo ContractName = "anchorRepository" + + // IdentityFactory is the contract name for IdentityFactory + IdentityFactory ContractName = "identityFactory" + + // IdentityRegistry is the contract name for IdentityRegistry + IdentityRegistry ContractName = "identityRegistry" + + // PaymentObligation is the contract name for PaymentObligation + PaymentObligation ContractName = "paymentObligation" +) + +// ContractNames returns the list of smart contract names currently used in the system, please update this when adding new contracts +func ContractNames() [4]ContractName { + return [4]ContractName{AnchorRepo, IdentityFactory, IdentityRegistry, PaymentObligation} +} + // Configuration defines the methods that a config type should implement. type Configuration interface { // generic methods @@ -61,7 +83,7 @@ type Configuration interface { GetNetworkString() string GetNetworkKey(k string) string GetContractAddressString(address string) string - GetContractAddress(address string) common.Address + GetContractAddress(contractName ContractName) common.Address GetBootstrapPeers() []string GetNetworkID() uint32 @@ -273,8 +295,8 @@ func (c *configuration) GetContractAddressString(contract string) (address strin } // GetContractAddress returns the deployed contract address for a given contract. -func (c *configuration) GetContractAddress(contract string) (address common.Address) { - return common.HexToAddress(c.GetContractAddressString(contract)) +func (c *configuration) GetContractAddress(contractName ContractName) common.Address { + return common.HexToAddress(c.GetContractAddressString(string(contractName))) } // GetBootstrapPeers returns the list of configured bootstrap nodes for the given network. diff --git a/coredocument/bootstrapper.go b/coredocument/bootstrapper.go index 03770ba6e..e74964a2f 100644 --- a/coredocument/bootstrapper.go +++ b/coredocument/bootstrapper.go @@ -3,7 +3,7 @@ package coredocument import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" ) @@ -13,9 +13,9 @@ type Bootstrapper struct{} // Bootstrap adds processor to the context. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - if !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index f45e592e6..352d3deb3 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -2,7 +2,7 @@ package documents import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" @@ -36,6 +36,10 @@ type PostBootstrapper struct{} // Bootstrap register task to the queue. func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err + } queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) if !ok { return errors.New("queue not initialised") @@ -55,7 +59,7 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { BaseTask: transactions.BaseTask{ TxService: ctx[transactions.BootstrappedService].(transactions.Service), }, - config: ctx[bootstrap.BootstrappedConfig].(config.Configuration), + config: cfg, processor: coreDocProc, modelGetFunc: repo.Get, modelSaveFunc: repo.Update, diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 9bb8ec3da..86c577d22 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,12 +1,13 @@ package invoice import ( + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -17,12 +18,11 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } - cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("service registry not initialised") @@ -60,7 +60,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { repo, anchorRepo, idService, queueSrv, txService) - err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) + err = registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return errors.New("failed to register invoice service: %v", err) } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index a6d0d3e33..80da247f8 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -9,13 +9,16 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" @@ -45,6 +48,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, &identity.Bootstrapper{}, diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index fd66b0cad..8f72d47b4 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,12 +1,13 @@ package purchaseorder import ( + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -17,10 +18,10 @@ type Bootstrapper struct{} // Bootstrap initialises required services for purchaseorder. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } - cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { @@ -55,7 +56,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { // register service srv := DefaultService(cfg, repo, anchorRepo, idService, queueSrv, txService) - err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) + err = registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index d4943f67a..fbf21a4b9 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -9,6 +9,8 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -46,6 +48,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, &identity.Bootstrapper{}, diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 9bff73d54..0f817f8ed 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -1,10 +1,6 @@ package ethereum -import ( - "github.com/centrifuge/go-centrifuge/errors" - - "github.com/centrifuge/go-centrifuge/bootstrap" -) +import "github.com/centrifuge/go-centrifuge/config/configstore" // BootstrappedEthereumClient is a key to mapped client in bootstrap context. const BootstrappedEthereumClient string = "BootstrappedEthereumClient" @@ -14,10 +10,10 @@ type Bootstrapper struct{} // Bootstrap initialises ethereum client. func (Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(false, context) + if err != nil { + return err } - cfg := context[bootstrap.BootstrappedConfig].(Config) client, err := NewGethClient(cfg) if err != nil { return err diff --git a/identity/bootstrapper.go b/identity/bootstrapper.go index b511d56e4..cb18a220c 100644 --- a/identity/bootstrapper.go +++ b/identity/bootstrapper.go @@ -1,6 +1,7 @@ package identity import ( + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -19,22 +20,24 @@ type Bootstrapper struct{} // Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. // the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { + // we have to allow loading from file in case this is coming from create config cmd where we don't add configs to db + // TODO make the db config work for identity, would have to remove idconfig stuff from the contextutil package as it creates dep cycles + cfg, ok := context[bootstrap.BootstrappedConfig].(config.Configuration) + if !ok { return errors.New("config hasn't been initialized") } - cfg := context[bootstrap.BootstrappedConfig].(Config) if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } gethClient := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) - idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress("identityFactory"), gethClient) + idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress(config.IdentityFactory), gethClient) if err != nil { return err } - registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress("identityRegistry"), gethClient) + registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress(config.IdentityRegistry), gethClient) if err != nil { return err } diff --git a/identity/identity.go b/identity/identity.go index 8e9671c4d..f6b90b435 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" @@ -77,7 +79,7 @@ type Config interface { GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration - GetContractAddress(address string) common.Address + GetContractAddress(contractName config.ContractName) common.Address } // Identity defines an Identity on chain diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index ca06bffc1..0f13c9d36 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -3,6 +3,7 @@ package nft import ( "context" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/transactions" @@ -21,10 +22,10 @@ type Bootstrapper struct{} // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - if _, ok := ctx[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } - cfg := ctx[bootstrap.BootstrappedConfig].(Config) if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 1f0e94fa6..f38b052f6 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -5,6 +5,8 @@ import ( "math/big" "time" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -27,7 +29,7 @@ var log = logging.Logger("nft") type Config interface { GetIdentityID() ([]byte, error) GetEthereumDefaultAccountName() string - GetContractAddress(address string) common.Address + GetContractAddress(address config.ContractName) common.Address GetEthereumContextWaitTimeout() time.Duration } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 5cf6192d9..3a3e2e827 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -80,7 +80,7 @@ func TestPaymentObligationService_mint(t *testing.T) { resp, err := payOb.MintNFT( ccommon.DummyIdentity, ID, - cfg.GetContractAddress("paymentObligation").String(), + cfg.GetContractAddress(config.PaymentObligation).String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, ) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index a554401c0..b802915cf 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -2,7 +2,7 @@ package p2p import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -13,9 +13,9 @@ type Bootstrapper struct{} // Bootstrap initiates p2p server and client into context func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, ok := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - if !ok { - return errors.New("config not initialised") + cfg, err := configstore.RetrieveConfig(true, ctx) + if err != nil { + return err } registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 9c9b08170..5453acfbe 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,6 +5,8 @@ package p2p import ( "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" @@ -22,6 +24,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) + m[configstore.BootstrappedConfigStorage] = new(configstore.MockService) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/server.go b/p2p/server.go index 79ef87c76..d58550788 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -55,6 +55,7 @@ type messenger interface { // p2pServer implements api.Server type p2pServer struct { + // TODO [multi-tenancy] replace this with config service config Config host host.Host handlerCreator func() *receiver.Handler diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index 5d7605499..8325f82f5 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -146,4 +146,6 @@ message ConfigData { repeated string bootstrap_peers = 18; uint32 network_id = 19; TenantData main_identity = 20; + map smart_contract_addresses = 21; + bool pprof_enabled = 22; } diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 7149b7b6d..906a8ff2c 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -38,7 +38,7 @@ func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } func (*GetTenantRequest) ProtoMessage() {} func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{0} + return fileDescriptor_service_869e0c690febd200, []int{0} } func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } func (*GetAllTenantResponse) ProtoMessage() {} func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{1} + return fileDescriptor_service_869e0c690febd200, []int{1} } func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) @@ -115,7 +115,7 @@ func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } func (*UpdateTenantRequest) ProtoMessage() {} func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{2} + return fileDescriptor_service_869e0c690febd200, []int{2} } func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) @@ -162,7 +162,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{3} + return fileDescriptor_service_869e0c690febd200, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -215,7 +215,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{4} + return fileDescriptor_service_869e0c690febd200, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -265,7 +265,7 @@ func (m *TenantData) Reset() { *m = TenantData{} } func (m *TenantData) String() string { return proto.CompactTextString(m) } func (*TenantData) ProtoMessage() {} func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{5} + return fileDescriptor_service_869e0c690febd200, []int{5} } func (m *TenantData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TenantData.Unmarshal(m, b) @@ -348,6 +348,8 @@ type ConfigData struct { BootstrapPeers []string `protobuf:"bytes,18,rep,name=bootstrap_peers,json=bootstrapPeers,proto3" json:"bootstrap_peers,omitempty"` NetworkId uint32 `protobuf:"varint,19,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` MainIdentity *TenantData `protobuf:"bytes,20,opt,name=main_identity,json=mainIdentity,proto3" json:"main_identity,omitempty"` + SmartContractAddresses map[string]string `protobuf:"bytes,21,rep,name=smart_contract_addresses,json=smartContractAddresses,proto3" json:"smart_contract_addresses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + PprofEnabled bool `protobuf:"varint,22,opt,name=pprof_enabled,json=pprofEnabled,proto3" json:"pprof_enabled,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -357,7 +359,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_48f740854e8728dc, []int{6} + return fileDescriptor_service_869e0c690febd200, []int{6} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -517,6 +519,20 @@ func (m *ConfigData) GetMainIdentity() *TenantData { return nil } +func (m *ConfigData) GetSmartContractAddresses() map[string]string { + if m != nil { + return m.SmartContractAddresses + } + return nil +} + +func (m *ConfigData) GetPprofEnabled() bool { + if m != nil { + return m.PprofEnabled + } + return false +} + func init() { proto.RegisterType((*GetTenantRequest)(nil), "config.GetTenantRequest") proto.RegisterType((*GetAllTenantResponse)(nil), "config.GetAllTenantResponse") @@ -525,6 +541,7 @@ func init() { proto.RegisterType((*KeyPair)(nil), "config.KeyPair") proto.RegisterType((*TenantData)(nil), "config.TenantData") proto.RegisterType((*ConfigData)(nil), "config.ConfigData") + proto.RegisterMapType((map[string]string)(nil), "config.ConfigData.SmartContractAddressesEntry") } // Reference imports to suppress errors if they are not otherwise used. @@ -863,86 +880,91 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_48f740854e8728dc) } - -var fileDescriptor_service_48f740854e8728dc = []byte{ - // 1243 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xeb, 0x6e, 0x13, 0x47, - 0x14, 0x96, 0x09, 0xe4, 0x32, 0xb6, 0x73, 0x99, 0x24, 0xb0, 0x2c, 0x21, 0x2c, 0x5b, 0x95, 0x5a, - 0x88, 0xc4, 0x92, 0x5b, 0x89, 0xc2, 0x0f, 0x24, 0x93, 0x44, 0x51, 0xd4, 0x42, 0xad, 0x2d, 0x08, - 0xb5, 0x55, 0xb5, 0x9a, 0x78, 0x4f, 0xec, 0x15, 0xeb, 0x99, 0x61, 0xf6, 0x6c, 0x12, 0xab, 0xaa, - 0x54, 0xf1, 0x08, 0xee, 0x2b, 0xf4, 0x57, 0x5f, 0xa7, 0xaf, 0xd0, 0xbe, 0x47, 0x35, 0x97, 0x4d, - 0x9c, 0xd8, 0x21, 0xe2, 0x97, 0x3d, 0xe7, 0xf2, 0x7d, 0xe7, 0x3b, 0x73, 0x66, 0x66, 0xc9, 0x5a, - 0x57, 0xf0, 0xa3, 0xb4, 0xd7, 0xcc, 0x41, 0x1d, 0xa7, 0x5d, 0xd8, 0x96, 0x4a, 0xa0, 0xa0, 0xb3, - 0xd6, 0xea, 0x6f, 0xf4, 0x84, 0xe8, 0x65, 0xd0, 0x64, 0x32, 0x6d, 0x32, 0xce, 0x05, 0x32, 0x4c, - 0x05, 0xcf, 0x6d, 0x94, 0xbf, 0xe9, 0xbc, 0x66, 0x75, 0x58, 0x1c, 0x35, 0x93, 0x42, 0x99, 0x00, - 0xe7, 0xbf, 0x77, 0xd9, 0x0f, 0x03, 0x89, 0x43, 0xe7, 0x7c, 0x62, 0x7e, 0xba, 0x5b, 0x3d, 0xe0, - 0x5b, 0xf9, 0x09, 0xeb, 0xf5, 0x40, 0x35, 0x85, 0x34, 0xf0, 0x93, 0x54, 0x61, 0x8b, 0x2c, 0xef, - 0x03, 0xbe, 0x01, 0xce, 0x38, 0x46, 0xf0, 0xa1, 0x80, 0x1c, 0xe9, 0x26, 0x21, 0x69, 0x02, 0x1c, - 0xd3, 0xa3, 0x14, 0x94, 0x57, 0x09, 0x2a, 0x8d, 0x85, 0x68, 0xcc, 0x12, 0xbe, 0x20, 0x6b, 0xfb, - 0x80, 0xed, 0x2c, 0x2b, 0xd3, 0x72, 0x29, 0x78, 0x0e, 0xf4, 0x11, 0xb9, 0x99, 0x30, 0x64, 0x5e, - 0x25, 0x98, 0x69, 0x54, 0x5b, 0x74, 0xdb, 0x6a, 0xdd, 0xb6, 0x51, 0xbb, 0x0c, 0x59, 0x64, 0xfc, - 0xe1, 0xaf, 0x64, 0xf5, 0xad, 0x4c, 0x18, 0xc2, 0x67, 0xd1, 0x9e, 0xc1, 0xdf, 0x08, 0x2a, 0x9f, - 0x84, 0xff, 0x89, 0x2c, 0xed, 0x61, 0x1f, 0x14, 0x14, 0x83, 0x76, 0xb7, 0x2b, 0x0a, 0x8e, 0xd4, - 0x23, 0x73, 0x2c, 0x49, 0x14, 0xe4, 0xb9, 0xc3, 0x2d, 0x97, 0x74, 0x99, 0xcc, 0xbc, 0x87, 0xa1, - 0xc1, 0x5c, 0x88, 0xf4, 0x5f, 0xea, 0x93, 0x79, 0xc9, 0xf2, 0xfc, 0x44, 0xa8, 0xc4, 0x9b, 0x31, - 0xe6, 0xb3, 0x75, 0xb8, 0x45, 0xe6, 0xbe, 0x83, 0x61, 0x87, 0xa5, 0x4a, 0x27, 0xca, 0xe2, 0xd0, - 0xc1, 0xe9, 0xbf, 0xc6, 0x72, 0x8c, 0x25, 0x94, 0x3c, 0xc6, 0xf0, 0xbf, 0x1b, 0x84, 0x9c, 0x97, - 0x47, 0xbf, 0x25, 0x55, 0xc0, 0x7e, 0xcc, 0x6c, 0x51, 0x26, 0xb5, 0xda, 0xba, 0x53, 0xea, 0xb8, - 0x54, 0x73, 0x44, 0x00, 0xfb, 0x65, 0xfd, 0x4f, 0x89, 0xa7, 0x33, 0x13, 0x38, 0x62, 0x45, 0x86, - 0x25, 0x42, 0xcc, 0xd9, 0x00, 0x1c, 0xdf, 0x3a, 0x60, 0x7f, 0xd7, 0xba, 0x5d, 0xd2, 0x6b, 0x36, - 0x00, 0xfa, 0x8a, 0x7c, 0xa1, 0xa0, 0x0b, 0xe9, 0x31, 0xc4, 0x70, 0x0c, 0x3a, 0x45, 0xe8, 0x6e, - 0x76, 0xcd, 0x0c, 0xc4, 0xc0, 0x13, 0x29, 0x52, 0x8e, 0x4e, 0x67, 0xe0, 0x42, 0xf7, 0x74, 0xe4, - 0xeb, 0xb1, 0xc0, 0x3d, 0x17, 0x47, 0x1f, 0x90, 0xaa, 0xdd, 0x10, 0x1c, 0xc6, 0x69, 0xe2, 0xdd, - 0x1c, 0xdf, 0x23, 0x1c, 0x1e, 0x24, 0xf4, 0x19, 0x59, 0xce, 0xd3, 0x1e, 0x4f, 0x79, 0x2f, 0x7e, - 0x0f, 0xc3, 0x58, 0xb2, 0x54, 0x79, 0xb7, 0x8c, 0xce, 0xa5, 0x52, 0xa7, 0x6b, 0x60, 0xb4, 0xe8, - 0x02, 0xcb, 0x86, 0x3e, 0x23, 0xcb, 0x80, 0x7d, 0x56, 0x60, 0xff, 0x3c, 0x75, 0xf6, 0x8a, 0x54, - 0x17, 0xe8, 0xd6, 0xe1, 0xdf, 0x73, 0x84, 0xec, 0x98, 0x10, 0xd3, 0xe7, 0x87, 0xa4, 0x96, 0xa3, - 0x50, 0xac, 0x07, 0xb1, 0x64, 0xd8, 0x77, 0x7b, 0x54, 0x75, 0xb6, 0x0e, 0xc3, 0x3e, 0xbd, 0x4b, - 0xe6, 0x65, 0x4b, 0xc6, 0x52, 0x28, 0xbb, 0x61, 0xb7, 0xa2, 0x39, 0xd9, 0x92, 0x1d, 0xa1, 0x90, - 0x3e, 0x22, 0x4b, 0xda, 0x05, 0xa7, 0x08, 0x8a, 0xb3, 0x2c, 0x4e, 0xa5, 0x6b, 0x4f, 0x5d, 0xb6, - 0xe4, 0x9e, 0xb3, 0x1e, 0x48, 0xfa, 0x03, 0xb9, 0xad, 0xe3, 0xba, 0x82, 0x73, 0xe8, 0x9a, 0x76, - 0x62, 0x3a, 0x00, 0x51, 0xa0, 0x69, 0x4b, 0xb5, 0x75, 0x77, 0xdb, 0x9e, 0xd2, 0xed, 0xf2, 0x94, - 0x6e, 0xef, 0xba, 0x53, 0x1c, 0xad, 0xc9, 0x96, 0xdc, 0x39, 0xcb, 0x7b, 0x63, 0xd3, 0x74, 0x73, - 0xf5, 0x65, 0x01, 0xca, 0x96, 0x75, 0xcb, 0x94, 0x45, 0xac, 0xc9, 0x54, 0xf6, 0x25, 0x59, 0x74, - 0x01, 0xe5, 0x30, 0xcf, 0xda, 0xc2, 0xac, 0xb5, 0xed, 0x46, 0xfa, 0x01, 0xa9, 0xf2, 0x62, 0x10, - 0x9f, 0x08, 0xf5, 0x1e, 0x54, 0xee, 0xcd, 0x59, 0x1c, 0x5e, 0x0c, 0xde, 0x59, 0x0b, 0xdd, 0x22, - 0xab, 0xd6, 0x19, 0x9f, 0xb0, 0x14, 0x4d, 0xd9, 0xf1, 0x20, 0xf7, 0xe6, 0x4d, 0xe0, 0xb2, 0x75, - 0xbd, 0x63, 0x29, 0xea, 0xc2, 0x5e, 0xe5, 0x34, 0x20, 0x35, 0x3d, 0x7c, 0x5c, 0x24, 0x10, 0x17, - 0x2a, 0xf3, 0x16, 0xec, 0xae, 0x03, 0xf6, 0x5f, 0x8b, 0x04, 0xde, 0xaa, 0x8c, 0xfe, 0x42, 0xee, - 0xeb, 0x88, 0xae, 0xe0, 0x08, 0xa7, 0x18, 0x2b, 0x60, 0xc9, 0x39, 0xb4, 0xee, 0x08, 0xb9, 0xae, - 0x23, 0x77, 0x01, 0xfb, 0x3b, 0x36, 0x3d, 0x02, 0x96, 0x94, 0xec, 0xba, 0x2d, 0x91, 0x9d, 0xfd, - 0x12, 0xfc, 0x02, 0x6e, 0xf5, 0x3a, 0xdc, 0xf5, 0x73, 0xdc, 0x71, 0xcc, 0x7d, 0x42, 0x35, 0x66, - 0xca, 0x11, 0xd4, 0x31, 0xcb, 0x62, 0x05, 0xa8, 0x86, 0x5e, 0xed, 0x3a, 0x34, 0x3d, 0xa0, 0x07, - 0x2e, 0x27, 0xd2, 0x29, 0x7a, 0x58, 0x34, 0xd0, 0x80, 0x9d, 0x1a, 0x8c, 0x14, 0x72, 0xaf, 0x1e, - 0x54, 0x1a, 0xf5, 0xa8, 0x0e, 0xd8, 0x7f, 0xc5, 0x4e, 0x23, 0x6b, 0xa4, 0x21, 0xd1, 0x86, 0xb8, - 0xc7, 0xf2, 0x58, 0xaa, 0xb4, 0x0b, 0xde, 0x62, 0x50, 0x69, 0xdc, 0x8c, 0xf4, 0x7d, 0xb0, 0xcf, - 0xf2, 0x8e, 0x36, 0x8d, 0xc7, 0x64, 0xe9, 0x20, 0x45, 0x6f, 0x69, 0x3c, 0xe6, 0x7b, 0x6d, 0xd2, - 0x7c, 0x78, 0x1a, 0x4b, 0x21, 0xb2, 0x18, 0x38, 0x3b, 0xcc, 0x20, 0xf1, 0x96, 0x83, 0x4a, 0x63, - 0x3e, 0xaa, 0xe3, 0x69, 0x47, 0x88, 0x6c, 0xcf, 0x1a, 0xf5, 0x85, 0xc7, 0x01, 0xf5, 0x56, 0x7a, - 0x2b, 0xf6, 0xc2, 0x73, 0x4b, 0xfa, 0x15, 0x59, 0x3a, 0x14, 0x02, 0x73, 0x54, 0x4c, 0xc6, 0x12, - 0xf4, 0x84, 0xd0, 0x60, 0xa6, 0xb1, 0x10, 0x2d, 0x9e, 0x99, 0x3b, 0xda, 0x4a, 0xef, 0x13, 0xe2, - 0x72, 0xf4, 0x51, 0x5f, 0x35, 0xaa, 0x16, 0x9c, 0xe5, 0x20, 0xa1, 0x4f, 0x49, 0x7d, 0xc0, 0x52, - 0x1e, 0x97, 0x87, 0xdf, 0x5b, 0xbb, 0xf2, 0x5a, 0xae, 0xe9, 0xc0, 0x03, 0x17, 0xd7, 0xfa, 0x6b, - 0x9e, 0xd4, 0xed, 0x61, 0xfd, 0xd1, 0x3e, 0x8d, 0x94, 0x91, 0x85, 0x7d, 0x40, 0x6b, 0xa3, 0xb7, - 0x27, 0xda, 0xbf, 0xa7, 0x1f, 0x37, 0xff, 0x0c, 0xf8, 0xfc, 0xa0, 0x87, 0x8d, 0x51, 0x7b, 0xc5, - 0x5f, 0xda, 0x07, 0x0c, 0xf4, 0x24, 0x06, 0xd6, 0xf3, 0xf1, 0x9f, 0x7f, 0xff, 0xbc, 0xb1, 0x48, - 0x6b, 0x4d, 0xf7, 0x00, 0xeb, 0xb9, 0xa5, 0x85, 0xa1, 0xb0, 0x35, 0x51, 0xaf, 0x84, 0xba, 0xfc, - 0xf2, 0xf9, 0x53, 0xaa, 0x0f, 0x9f, 0x8f, 0xda, 0xab, 0xfe, 0x8a, 0x26, 0xb1, 0xc6, 0x71, 0x9a, - 0x4d, 0xba, 0x51, 0xd2, 0xa0, 0x71, 0xe6, 0xcd, 0xdf, 0xce, 0x5f, 0xac, 0xdf, 0xe9, 0x90, 0xd4, - 0xc7, 0x5f, 0xca, 0xfc, 0x4a, 0x75, 0x1b, 0x63, 0x25, 0x4d, 0x3c, 0xac, 0x61, 0x6b, 0xd4, 0xf6, - 0xfc, 0xdb, 0xba, 0x84, 0x76, 0x96, 0x5d, 0x2c, 0x23, 0x37, 0x75, 0xac, 0xd0, 0xa5, 0x4b, 0x75, - 0xd0, 0x8c, 0xd4, 0x76, 0x14, 0x30, 0x04, 0xd7, 0xd7, 0x29, 0xfd, 0x9b, 0xda, 0xd3, 0x6f, 0x46, - 0x6d, 0xdf, 0xf7, 0x6c, 0x6a, 0x1e, 0xe8, 0xe6, 0x05, 0x36, 0x28, 0xd0, 0x8f, 0xab, 0x65, 0x0b, - 0x2f, 0x34, 0xf7, 0x79, 0xe5, 0x31, 0xfd, 0x50, 0xb2, 0xb9, 0x16, 0x4f, 0x69, 0xe4, 0xd4, 0xe6, - 0x3e, 0x1b, 0xb5, 0x37, 0x7c, 0xbf, 0x64, 0xb3, 0xb5, 0x4f, 0xf0, 0xad, 0x85, 0x97, 0xd5, 0x69, - 0xca, 0x1e, 0xa9, 0xd9, 0xaf, 0x88, 0xcf, 0x14, 0xd8, 0x1c, 0xb5, 0xd7, 0x7d, 0xf7, 0x01, 0x72, - 0x41, 0xa0, 0xd5, 0xe6, 0x4f, 0x68, 0xfb, 0x58, 0x29, 0x99, 0x9c, 0xb8, 0x7b, 0x25, 0xea, 0x94, - 0xaf, 0x98, 0xa9, 0x2a, 0xdb, 0xa3, 0xf6, 0x1d, 0x7f, 0xbd, 0xa4, 0xbc, 0xa0, 0xd2, 0x90, 0x3e, - 0xf4, 0x3f, 0x39, 0x46, 0xba, 0x88, 0x8c, 0xd4, 0x76, 0x21, 0x83, 0x33, 0xb5, 0x57, 0x0d, 0xd2, - 0x15, 0xf6, 0xf0, 0x89, 0x51, 0x6d, 0x21, 0x26, 0x55, 0x2f, 0x3e, 0xbe, 0x78, 0x5c, 0xfe, 0xa8, - 0x94, 0x74, 0xd7, 0x1e, 0x99, 0xab, 0x08, 0x5f, 0x18, 0xcd, 0x25, 0xe1, 0xa4, 0xe6, 0xcd, 0xc7, - 0x9f, 0xd4, 0xfc, 0xf2, 0x11, 0x21, 0x5d, 0x31, 0x70, 0xb4, 0x2f, 0x6b, 0xee, 0xae, 0xe8, 0x68, - 0x92, 0x4e, 0xe5, 0xe7, 0x79, 0x6b, 0x97, 0x87, 0x87, 0xb3, 0x86, 0xf7, 0xeb, 0xff, 0x03, 0x00, - 0x00, 0xff, 0xff, 0xd9, 0x4e, 0xef, 0x2d, 0x70, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_869e0c690febd200) } + +var fileDescriptor_service_869e0c690febd200 = []byte{ + // 1326 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xe9, 0x6a, 0x1b, 0xc9, + 0x16, 0x46, 0x76, 0xbc, 0x95, 0x24, 0x2f, 0xe5, 0x25, 0x9d, 0x8e, 0xe3, 0x74, 0x14, 0x6e, 0xae, + 0x08, 0xb1, 0x04, 0xba, 0x17, 0xb2, 0xfc, 0x08, 0x28, 0xb6, 0x30, 0xe6, 0xde, 0x64, 0x44, 0x27, + 0x21, 0xcc, 0x0c, 0x43, 0x53, 0x56, 0x1f, 0x4b, 0x4d, 0x5a, 0x5d, 0x95, 0xea, 0xd3, 0xb2, 0xc5, + 0x30, 0x30, 0x84, 0x79, 0x02, 0xcd, 0x2b, 0xcc, 0x1b, 0xcd, 0x2b, 0xcc, 0xbc, 0xc7, 0x50, 0x4b, + 0x5b, 0xb2, 0x25, 0xdb, 0xe4, 0x97, 0xd4, 0x67, 0xf9, 0xbe, 0x73, 0xbe, 0x3a, 0xb5, 0x90, 0xad, + 0x0e, 0x4f, 0x4e, 0xa3, 0x6e, 0x3d, 0x05, 0x39, 0x88, 0x3a, 0x50, 0x13, 0x92, 0x23, 0xa7, 0x8b, + 0xc6, 0xea, 0xee, 0x76, 0x39, 0xef, 0xc6, 0x50, 0x67, 0x22, 0xaa, 0xb3, 0x24, 0xe1, 0xc8, 0x30, + 0xe2, 0x49, 0x6a, 0xa2, 0xdc, 0x3d, 0xeb, 0xd5, 0x5f, 0x27, 0xd9, 0x69, 0x3d, 0xcc, 0xa4, 0x0e, + 0xb0, 0xfe, 0xfb, 0x57, 0xfd, 0xd0, 0x17, 0x38, 0xb4, 0xce, 0x67, 0xfa, 0xa7, 0xb3, 0xdf, 0x85, + 0x64, 0x3f, 0x3d, 0x63, 0xdd, 0x2e, 0xc8, 0x3a, 0x17, 0x1a, 0x7e, 0x9a, 0xaa, 0xd2, 0x20, 0xeb, + 0x47, 0x80, 0x1f, 0x20, 0x61, 0x09, 0xfa, 0xf0, 0x25, 0x83, 0x14, 0xe9, 0x1e, 0x21, 0x51, 0x08, + 0x09, 0x46, 0xa7, 0x11, 0x48, 0xa7, 0xe0, 0x15, 0xaa, 0x2b, 0xfe, 0x84, 0xa5, 0xf2, 0x9a, 0x6c, + 0x1d, 0x01, 0x36, 0xe3, 0x38, 0x4f, 0x4b, 0x05, 0x4f, 0x52, 0xa0, 0x4f, 0xc8, 0x9d, 0x90, 0x21, + 0x73, 0x0a, 0xde, 0x7c, 0xb5, 0xd8, 0xa0, 0x35, 0xd3, 0x6b, 0xcd, 0x44, 0x1d, 0x32, 0x64, 0xbe, + 0xf6, 0x57, 0x7e, 0x22, 0x9b, 0x1f, 0x45, 0xc8, 0x10, 0xbe, 0x89, 0xf6, 0x02, 0x7e, 0xce, 0x2b, + 0xdc, 0x08, 0xff, 0x3d, 0x59, 0x6b, 0x61, 0x0f, 0x24, 0x64, 0xfd, 0x66, 0xa7, 0xc3, 0xb3, 0x04, + 0xa9, 0x43, 0x96, 0x58, 0x18, 0x4a, 0x48, 0x53, 0x8b, 0x9b, 0x7f, 0xd2, 0x75, 0x32, 0xff, 0x19, + 0x86, 0x1a, 0x73, 0xc5, 0x57, 0x7f, 0xa9, 0x4b, 0x96, 0x05, 0x4b, 0xd3, 0x33, 0x2e, 0x43, 0x67, + 0x5e, 0x9b, 0x2f, 0xbe, 0x2b, 0xfb, 0x64, 0xe9, 0x7f, 0x30, 0x6c, 0xb3, 0x48, 0xaa, 0x44, 0x91, + 0x9d, 0x58, 0x38, 0xf5, 0x57, 0x5b, 0x06, 0x98, 0x43, 0x89, 0x01, 0x56, 0xfe, 0x9e, 0x23, 0x64, + 0x5c, 0x1e, 0x7d, 0x41, 0x8a, 0x80, 0xbd, 0x80, 0x99, 0xa2, 0x74, 0x6a, 0xb1, 0x71, 0x37, 0xef, + 0xe3, 0x4a, 0xcd, 0x3e, 0x01, 0xec, 0xe5, 0xf5, 0x3f, 0x27, 0x8e, 0xca, 0x0c, 0xe1, 0x94, 0x65, + 0x31, 0xe6, 0x08, 0x41, 0xc2, 0xfa, 0x60, 0xf9, 0xb6, 0x01, 0x7b, 0x87, 0xc6, 0x6d, 0x93, 0xde, + 0xb1, 0x3e, 0xd0, 0xb7, 0xe4, 0xb1, 0x84, 0x0e, 0x44, 0x03, 0x08, 0x60, 0x00, 0x2a, 0x85, 0x2b, + 0x35, 0x3b, 0x7a, 0x06, 0x02, 0x48, 0x42, 0xc1, 0xa3, 0x04, 0x6d, 0x9f, 0x9e, 0x0d, 0x6d, 0xa9, + 0xc8, 0x77, 0x13, 0x81, 0x2d, 0x1b, 0x47, 0x1f, 0x92, 0xa2, 0x59, 0x10, 0x1c, 0x06, 0x51, 0xe8, + 0xdc, 0x99, 0x5c, 0x23, 0x1c, 0x1e, 0x87, 0xf4, 0x25, 0x59, 0x4f, 0xa3, 0x6e, 0x12, 0x25, 0xdd, + 0xe0, 0x33, 0x0c, 0x03, 0xc1, 0x22, 0xe9, 0x2c, 0xe8, 0x3e, 0xd7, 0xf2, 0x3e, 0xad, 0x80, 0xfe, + 0xaa, 0x0d, 0xcc, 0x05, 0x7d, 0x49, 0xd6, 0x01, 0x7b, 0x2c, 0xc3, 0xde, 0x38, 0x75, 0xf1, 0x9a, + 0x54, 0x1b, 0x68, 0xbf, 0x2b, 0xbf, 0xad, 0x10, 0x72, 0xa0, 0x43, 0xb4, 0xce, 0x8f, 0x48, 0x29, + 0x45, 0x2e, 0x59, 0x17, 0x02, 0xc1, 0xb0, 0x67, 0xd7, 0xa8, 0x68, 0x6d, 0x6d, 0x86, 0x3d, 0x7a, + 0x8f, 0x2c, 0x8b, 0x86, 0x08, 0x04, 0x97, 0x66, 0xc1, 0x16, 0xfc, 0x25, 0xd1, 0x10, 0x6d, 0x2e, + 0x91, 0x3e, 0x21, 0x6b, 0xca, 0x05, 0xe7, 0x08, 0x32, 0x61, 0x71, 0x10, 0x09, 0x2b, 0x4f, 0x59, + 0x34, 0x44, 0xcb, 0x5a, 0x8f, 0x05, 0xfd, 0x8e, 0xec, 0xa8, 0xb8, 0x0e, 0x4f, 0x12, 0xe8, 0x68, + 0x39, 0x31, 0xea, 0x03, 0xcf, 0x50, 0xcb, 0x52, 0x6c, 0xdc, 0xab, 0x99, 0x5d, 0x5a, 0xcb, 0x77, + 0x69, 0xed, 0xd0, 0xee, 0x62, 0x7f, 0x4b, 0x34, 0xc4, 0xc1, 0x45, 0xde, 0x07, 0x93, 0xa6, 0xc4, + 0x55, 0x87, 0x05, 0x48, 0x53, 0xd6, 0x82, 0x2e, 0x8b, 0x18, 0x93, 0xae, 0xec, 0x5f, 0x64, 0xd5, + 0x06, 0xe4, 0xc3, 0xbc, 0x68, 0x0a, 0x33, 0xd6, 0xa6, 0x1d, 0xe9, 0x87, 0xa4, 0x98, 0x64, 0xfd, + 0xe0, 0x8c, 0xcb, 0xcf, 0x20, 0x53, 0x67, 0xc9, 0xe0, 0x24, 0x59, 0xff, 0x93, 0xb1, 0xd0, 0x7d, + 0xb2, 0x69, 0x9c, 0xc1, 0x19, 0x8b, 0x50, 0x97, 0x1d, 0xf4, 0x53, 0x67, 0x59, 0x07, 0xae, 0x1b, + 0xd7, 0x27, 0x16, 0xa1, 0x2a, 0xec, 0x6d, 0x4a, 0x3d, 0x52, 0x52, 0xc3, 0x97, 0xf0, 0x10, 0x82, + 0x4c, 0xc6, 0xce, 0x8a, 0x59, 0x75, 0xc0, 0xde, 0x3b, 0x1e, 0xc2, 0x47, 0x19, 0xd3, 0x1f, 0xc9, + 0x03, 0x15, 0xd1, 0xe1, 0x09, 0xc2, 0x39, 0x06, 0x12, 0x58, 0x38, 0x86, 0x56, 0x8a, 0x90, 0xdb, + 0x14, 0xb9, 0x07, 0xd8, 0x3b, 0x30, 0xe9, 0x3e, 0xb0, 0x30, 0x67, 0x57, 0xb2, 0xf8, 0x66, 0xf6, + 0x73, 0xf0, 0x4b, 0xb8, 0xc5, 0xdb, 0x70, 0xb7, 0xc7, 0xb8, 0x93, 0x98, 0x47, 0x84, 0x2a, 0xcc, + 0x28, 0x41, 0x90, 0x03, 0x16, 0x07, 0x12, 0x50, 0x0e, 0x9d, 0xd2, 0x6d, 0x68, 0x6a, 0x40, 0x8f, + 0x6d, 0x8e, 0xaf, 0x52, 0xd4, 0xb0, 0x28, 0xa0, 0x3e, 0x3b, 0xd7, 0x18, 0x11, 0xa4, 0x4e, 0xd9, + 0x2b, 0x54, 0xcb, 0x7e, 0x19, 0xb0, 0xf7, 0x96, 0x9d, 0xfb, 0xc6, 0x48, 0x2b, 0x44, 0x19, 0x82, + 0x2e, 0x4b, 0x03, 0x21, 0xa3, 0x0e, 0x38, 0xab, 0x5e, 0xa1, 0x7a, 0xc7, 0x57, 0xe7, 0xc1, 0x11, + 0x4b, 0xdb, 0xca, 0x34, 0x19, 0x13, 0x47, 0xfd, 0x08, 0x9d, 0xb5, 0xc9, 0x98, 0xff, 0x2b, 0x93, + 0xe2, 0xc3, 0xf3, 0x40, 0x70, 0x1e, 0x07, 0x90, 0xb0, 0x93, 0x18, 0x42, 0x67, 0xdd, 0x2b, 0x54, + 0x97, 0xfd, 0x32, 0x9e, 0xb7, 0x39, 0x8f, 0x5b, 0xc6, 0xa8, 0x0e, 0xbc, 0x04, 0x50, 0x2d, 0xa5, + 0xb3, 0x61, 0x0e, 0x3c, 0xfb, 0x49, 0xff, 0x4d, 0xd6, 0x4e, 0x38, 0xc7, 0x14, 0x25, 0x13, 0x81, + 0x00, 0x35, 0x21, 0xd4, 0x9b, 0xaf, 0xae, 0xf8, 0xab, 0x17, 0xe6, 0xb6, 0xb2, 0xd2, 0x07, 0x84, + 0xd8, 0x1c, 0xb5, 0xd5, 0x37, 0x75, 0x57, 0x2b, 0xd6, 0x72, 0x1c, 0xd2, 0xe7, 0xa4, 0xdc, 0x67, + 0x51, 0x12, 0xe4, 0x9b, 0xdf, 0xd9, 0xba, 0xf6, 0x58, 0x2e, 0xa9, 0xc0, 0x63, 0x1b, 0x47, 0x7b, + 0xc4, 0x49, 0xfb, 0x4c, 0xa2, 0x5e, 0x51, 0xc9, 0x3a, 0x98, 0x4f, 0x33, 0xa4, 0xce, 0xb6, 0xbe, + 0x39, 0x6a, 0x39, 0xc6, 0x78, 0x4f, 0xd7, 0xde, 0xab, 0x94, 0x03, 0x9b, 0xd1, 0xcc, 0x13, 0x5a, + 0x09, 0xca, 0xa1, 0xbf, 0x93, 0xce, 0x74, 0xd2, 0xc7, 0xa4, 0x2c, 0x84, 0xe4, 0xa7, 0x17, 0x52, + 0xed, 0x68, 0xa9, 0x4a, 0xda, 0x68, 0x95, 0x72, 0x8f, 0xc9, 0xfd, 0x1b, 0xb0, 0xf3, 0xfb, 0xa1, + 0x30, 0xbe, 0x1f, 0xb6, 0xc8, 0xc2, 0x80, 0xc5, 0x59, 0x7e, 0xf0, 0x9a, 0x8f, 0x57, 0x73, 0x2f, + 0x0a, 0x8d, 0x3f, 0x96, 0x49, 0xd9, 0x94, 0xfc, 0xde, 0x5c, 0xfa, 0x94, 0x91, 0x95, 0x23, 0x40, + 0x63, 0xa3, 0x3b, 0x53, 0x83, 0xd5, 0x52, 0xd7, 0xb6, 0x4b, 0xa7, 0xdb, 0xad, 0x54, 0x47, 0xcd, + 0x0d, 0x77, 0xed, 0x08, 0xd0, 0x53, 0x7b, 0xcc, 0x33, 0x9e, 0xaf, 0x7f, 0xfe, 0xf5, 0xfb, 0xdc, + 0x2a, 0x2d, 0xd5, 0xed, 0xd3, 0x42, 0xed, 0x48, 0x9a, 0x69, 0x0a, 0xa3, 0x36, 0x75, 0x72, 0xa8, + 0xab, 0x77, 0xba, 0x3b, 0x63, 0x5d, 0x2a, 0xaf, 0x46, 0xcd, 0x4d, 0x77, 0x43, 0x91, 0x18, 0xe3, + 0x24, 0xcd, 0x1e, 0xdd, 0xcd, 0x69, 0x50, 0x3b, 0xd3, 0xfa, 0xcf, 0xe3, 0xbb, 0xf8, 0x17, 0x3a, + 0x24, 0xe5, 0xc9, 0x37, 0x40, 0x7a, 0x6d, 0x77, 0xbb, 0x13, 0x25, 0x4d, 0x3d, 0x19, 0x2a, 0x8d, + 0x51, 0xd3, 0x71, 0x77, 0x54, 0x09, 0xcd, 0x38, 0xbe, 0x5c, 0x46, 0xaa, 0xeb, 0xd8, 0xa0, 0x6b, + 0x57, 0xea, 0xa0, 0x31, 0x29, 0x1d, 0x48, 0x60, 0x08, 0x56, 0xd7, 0x19, 0xfa, 0xcd, 0xd4, 0xf4, + 0xbf, 0xa3, 0xa6, 0xeb, 0x3a, 0x26, 0x35, 0xf5, 0x94, 0x78, 0x9e, 0x09, 0xf2, 0xd4, 0xb3, 0xc1, + 0xb0, 0x55, 0x2e, 0x89, 0xfb, 0xaa, 0xf0, 0x94, 0x7e, 0xc9, 0xd9, 0xac, 0xc4, 0x33, 0x84, 0x9c, + 0x29, 0xee, 0xcb, 0x51, 0x73, 0xd7, 0x75, 0x73, 0x36, 0x53, 0xfb, 0x14, 0xdf, 0x56, 0xe5, 0x6a, + 0x77, 0x8a, 0xb2, 0x4b, 0x4a, 0xe6, 0x7d, 0xf4, 0x8d, 0x0d, 0xd6, 0x47, 0xcd, 0x6d, 0xd7, 0x3e, + 0xad, 0x2e, 0x35, 0x68, 0x7a, 0x73, 0xa7, 0x7a, 0xfb, 0x5a, 0xc8, 0x99, 0x6c, 0x73, 0xf7, 0x73, + 0xd4, 0x19, 0xef, 0xb3, 0x99, 0x5d, 0x36, 0x47, 0xcd, 0xbb, 0xee, 0x76, 0x4e, 0x79, 0xa9, 0x4b, + 0x4d, 0xfa, 0xc8, 0xbd, 0x71, 0x8c, 0x54, 0x11, 0x31, 0x29, 0x1d, 0x42, 0x0c, 0x17, 0xdd, 0x5e, + 0x37, 0x48, 0xd7, 0xd8, 0x2b, 0xcf, 0x74, 0xd7, 0x06, 0x62, 0xba, 0xeb, 0xd5, 0xa7, 0x97, 0xb7, + 0xcb, 0xaf, 0x85, 0x9c, 0xee, 0xd6, 0x2d, 0x73, 0x1d, 0xe1, 0x6b, 0xdd, 0x73, 0x4e, 0x38, 0xdd, + 0xf3, 0xde, 0xd3, 0x1b, 0x7b, 0x7e, 0xf3, 0x84, 0x90, 0x0e, 0xef, 0x5b, 0xda, 0x37, 0x25, 0x7b, + 0x56, 0xb4, 0x15, 0x49, 0xbb, 0xf0, 0xc3, 0xb2, 0xb1, 0x8b, 0x93, 0x93, 0x45, 0xcd, 0xfb, 0x9f, + 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9e, 0x81, 0x92, 0x4a, 0x0c, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 1ddf804ab..19838a823 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"},"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"},"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 1c0ac785a..6e9404f26 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -294,6 +294,16 @@ }, "main_identity": { "$ref": "#/definitions/configTenantData" + }, + "smart_contract_addresses": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "pprof_enabled": { + "type": "boolean", + "format": "boolean" } } }, diff --git a/queue/bootstrapper.go b/queue/bootstrapper.go index b2acc20de..3349aaf84 100644 --- a/queue/bootstrapper.go +++ b/queue/bootstrapper.go @@ -1,10 +1,8 @@ package queue import ( - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -14,10 +12,10 @@ type Bootstrapper struct { // Bootstrap initiates the queue. func (b *Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[bootstrap.BootstrappedConfig]; !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(false, context) + if err != nil { + return err } - cfg := context[bootstrap.BootstrappedConfig].(config.Configuration) srv := &Server{config: cfg, taskTypes: []TaskType{}} context[bootstrap.BootstrappedQueueServer] = srv b.context = context diff --git a/resources/data.go b/resources/data.go index f3f7d5b5f..ab66c7b4b 100644 --- a/resources/data.go +++ b/resources/data.go @@ -84,12 +84,12 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4668, mode: os.FileMode(420), modTime: time.Unix(1544540466, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4668, mode: os.FileMode(420), modTime: time.Unix(1545075267, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x92\xc9\x6e\xe3\x48\x0c\x86\xef\x7a\x0a\x81\x97\x5c\xbc\xd4\xbe\xbd\xc1\x20\x98\xd3\x0c\x90\x33\xab\xc8\x8a\x05\xdb\xb2\x5a\x4b\x12\x23\xc8\xbb\x37\xe4\x38\x9d\x6b\x1a\xba\x90\x04\x7f\xfe\xa4\xea\xe3\xf9\xc0\x23\x2f\xe7\xd4\xb4\x2d\x96\x72\x59\xfa\x79\x5a\xe3\xb6\x3d\x63\xd7\xa7\xf6\x16\xb6\xed\x91\xaf\xa9\x7d\x78\x07\x24\x1a\x79\x9a\x20\x41\x88\x59\x60\x70\x36\xe8\x62\x8c\x31\x58\x2a\x79\x99\x8d\xd3\x2c\x48\x17\x6b\x91\xa5\x91\x0a\x2d\x6c\xa0\x8c\xd7\x61\xbe\x40\x7a\x87\xd2\x0d\x07\x1e\x21\x01\xf2\xb4\x95\x2a\x6c\xcb\x3c\xae\x0d\xb7\xf2\xcc\x6f\x33\x24\x28\xde\xc7\x1a\xb4\x8f\xe4\xbd\xa0\xa8\x4a\x2d\x92\x88\x0c\x86\xaa\x25\x59\x14\x48\x25\x54\x85\x22\x2b\x94\x46\x48\xed\x05\x69\xa7\x45\xd5\xa1\x88\x12\xf0\xcf\xbc\x01\x47\x3c\x4f\xab\x6d\xf7\x02\x09\xb4\x2b\xd2\x05\xf6\x3a\xd7\x18\x44\x65\x6f\xb3\xf0\xca\xd7\x10\x05\x7a\x89\x04\x1f\x1b\x38\x52\x85\x04\xd3\x6d\x61\xb8\xa5\xdf\x43\xe8\x78\xe2\x1e\x92\x56\x1b\xe8\x21\x29\xa7\xa4\x31\x1b\x18\x20\xc9\x0d\x8c\x90\xc2\x06\x26\x3c\xad\x07\x10\xcb\xcc\xd2\xb1\x2e\x31\xc8\x68\x0c\x49\x2e\xa8\x72\xc8\xca\xb3\x61\xc7\x22\xdb\x5c\xb3\xd1\x99\x85\xf6\x0e\x2d\x85\x10\x62\x45\xe7\x23\xaa\x20\x95\x5a\x17\x39\x63\x59\x7f\x45\x91\x2a\xe4\x20\xad\xb5\x36\xa3\x64\x24\x5f\x90\xa3\x70\x82\x43\x30\x0a\x6b\xc1\xa0\xad\x23\xe1\x8c\xb5\x99\x22\x5a\x6f\x55\x46\x57\x4b\x11\x51\x71\x5d\x27\x75\x04\x09\x8c\x65\xe1\x04\xba\x2d\x29\xe4\xad\xd1\x39\x6c\xa3\x52\x75\x6b\x4c\x50\xd1\xc4\x48\xda\x13\x6c\xe0\x85\xc7\xa9\xbb\xac\x47\x7e\x3c\xdc\x1f\x7e\xc0\x69\x7a\xbd\x8c\x94\xda\x87\xaf\xd2\x9d\x81\xd4\xfe\x14\x81\xa6\xe9\x88\xfb\xb9\x9b\xaf\xff\x50\x6a\x41\xbc\x09\xf9\xfd\x41\xd3\xfc\x5a\x78\xe1\x15\xba\x7e\x39\x3f\x5d\xc6\x23\x8f\x53\x6a\x55\xd3\xb6\xaf\xb7\xe4\x09\xbb\xf9\xff\xee\xcc\xff\xfe\x97\x5a\xd9\x34\x47\xbe\xde\x08\x9d\xba\xe7\xbe\xeb\x9f\x3f\x61\x1d\x96\x7c\xea\xca\xe3\x4a\xe9\x6e\xb7\xdf\xed\xf6\x79\xe9\x4e\xb4\x1f\x79\xba\x2c\x63\xe1\x69\x7f\xef\x7e\xe4\xeb\x6e\x58\xf2\x6e\xe0\xf3\xa7\x6e\xec\x5e\x70\xe6\x9f\x09\x8f\xab\xf8\x26\xe4\xf9\x80\xcb\x7c\xf8\xa1\xf7\xbd\xfb\x2f\x8d\xbf\x54\x5f\xae\xbf\x03\x00\x00\xff\xff\xb0\x1c\xaf\x3f\xaa\x03\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x92\xcd\x6e\x1c\x37\x0c\xc7\xef\xf3\x14\x02\x2f\xbe\xec\xae\xf5\xfd\xf5\x06\x45\xd0\x5e\x5a\x20\x67\x4a\xa2\x6c\x61\xbd\xb3\x53\x8d\xc6\xce\x22\xc8\xbb\x17\xb3\xb1\x9b\xab\x83\xb9\x90\x04\xff\xfc\x93\xa3\x5f\xa6\x79\xf4\x56\xb7\x27\xfa\x8b\xc6\xdb\xb5\x9f\x23\x1b\xb4\x8e\x36\x3f\x4d\x34\x9e\xa9\xd3\x76\x89\x13\x63\x98\xf3\x75\x9b\xc7\xba\xc7\x8c\x5d\xb0\xcd\x91\xdd\x43\xc6\xce\x74\x8b\xec\xe1\x3b\x60\x29\x9d\xd6\x15\x22\xf8\x90\x38\x7a\x6b\xbc\xca\x5a\x6b\x8d\xb9\x16\x27\x92\xb6\x8a\x78\x51\xd9\x18\x24\xa1\x85\x44\x03\x07\xc8\xfd\xb6\x8c\x2b\xc4\xef\x90\xdb\xf2\x4c\x1d\x22\x20\xad\x47\x21\xfd\x31\x8f\xbe\x37\xdc\xcb\x83\xbe\x0d\x88\x90\x9d\x0b\xd5\x2b\x17\x8a\x73\xbc\x04\x99\x6b\x16\xa5\x14\x8d\xbe\x2a\x51\x0c\x72\x2c\xd9\x57\x89\x3c\x49\x14\x9a\x0b\xe5\x78\x51\x56\xf1\xaa\x7c\xe6\xd9\xe3\xff\xf3\x16\xec\x78\x59\x77\xdb\xf6\x0a\x11\x94\xcd\xc2\x7a\x72\x2a\xd5\xe0\x79\x25\x67\x12\x77\xd2\x55\x1f\x38\x3a\x81\x05\x7e\x1c\xe0\x5c\x2a\x44\x58\xef\x0b\xc3\x3d\xfd\x35\xa4\x9c\x5f\x68\x86\xa8\xe4\x01\x66\x88\xd2\x4a\xa1\xf5\x01\x16\x88\xe2\x00\x1d\xa2\x3f\xc0\x8a\x2f\xfb\x01\x85\x44\x22\x61\x49\xe5\xe0\x45\xd0\xba\x08\xca\x28\x93\x4f\xd2\x91\x26\x4b\x3c\x99\x54\x93\x56\x89\xb8\x72\x16\x4d\xf1\xde\x87\x8a\xd6\x05\x94\x5e\x48\xb9\x2f\x72\xc1\xbc\xff\x8a\x2c\xa4\x4f\x5e\x18\x63\x4c\x42\x41\x58\x5c\x46\x0a\xdc\x72\xf2\x5e\x4b\xac\x19\xbd\x32\xb6\x70\xab\x8d\x49\x25\xa0\x71\x46\x26\xb4\x35\x67\x1e\x24\xd5\x7d\x52\x2b\x10\x41\x1b\xe2\x96\xa3\x3d\x16\x89\x74\xd4\x2a\xf9\x63\x90\xb2\x1e\xb5\xf6\x32\xe8\x10\x8a\x72\x05\x0e\xf0\x4a\x7d\x6d\xd7\xfd\xc8\x1f\x0f\xef\x0f\xbf\xe0\xba\xbe\x5d\x7b\x89\xec\xe1\xa3\xf4\xce\x40\x64\x9f\x45\x60\x9a\x5a\xa1\x79\xb4\x71\xfb\xa3\x44\x06\xfc\x1b\x17\xbf\x3e\x98\xa6\x7f\x37\xda\x68\x87\x6e\xde\x2e\x5f\xaf\xfd\x4c\x7d\x8d\x4c\x4e\x8c\xbd\xdd\x93\xaf\xd8\xc6\x3f\xed\x42\x7f\xfe\x1d\x99\x98\xa6\x33\xdd\xee\x84\xae\xed\x69\x6e\xf3\xd3\x4f\x58\x97\x2d\xbd\xb4\xfc\x65\xa7\xf4\x74\x7a\x3c\x9d\x1e\xd3\xd6\x5e\xca\x63\xa7\xf5\xba\xf5\x4c\xeb\xe3\x7b\xf7\x17\xba\x9d\x96\x2d\x9d\x16\xba\xfc\xd4\xf5\xf6\x8a\x83\x3e\x27\x3c\xef\xe2\xbb\x90\xc6\x33\x6e\xe3\xf9\x93\xde\xef\xdd\xbf\x69\xfc\xa1\xfa\x70\xfd\x2f\x00\x00\xff\xff\x56\xed\xff\x60\xc5\x03\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 938, mode: os.FileMode(420), modTime: time.Unix(1540808141, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 965, mode: os.FileMode(420), modTime: time.Unix(1545556716, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/storage/test_bootstrapper.go b/storage/test_bootstrapper.go index 3683ecbfd..8f7f88a1c 100644 --- a/storage/test_bootstrapper.go +++ b/storage/test_bootstrapper.go @@ -16,7 +16,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { cfg := context[bootstrap.BootstrappedConfig].(config.Configuration) crs := GetRandomTestStoragePath() - cfg.SetDefault("configStorage.path", crs) + cfg.Set("configStorage.path", crs) log.Info("Set configStorage.path to:", cfg.GetConfigStoragePath()) configdb, err = NewLevelDBStorage(cfg.GetConfigStoragePath()) if err != nil { @@ -25,7 +25,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { context[BootstrappedConfigDB] = NewLevelDBRepository(configdb) rs := GetRandomTestStoragePath() - cfg.SetDefault("storage.Path", rs) + cfg.Set("storage.Path", rs) log.Info("Set storage.Path to:", cfg.GetStoragePath()) db, err = NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { diff --git a/testingutils/config/config.go b/testingutils/config/config.go index c6f69f1bf..3ce171184 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -124,7 +124,7 @@ func (m *MockConfig) GetContractAddressString(address string) string { return args.Get(0).(string) } -func (m *MockConfig) GetContractAddress(address string) common.Address { +func (m *MockConfig) GetContractAddress(contractName config.ContractName) common.Address { args := m.Called() return args.Get(0).(common.Address) } From 57b65a348ce343113f135581dce1150e1e152ed0 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 4 Jan 2019 16:16:42 +0100 Subject: [PATCH 111/220] use json marshaller (#608) --- notification/notification.go | 14 +------ notification/notification_test.go | 70 +++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/notification/notification.go b/notification/notification.go index ba51fff22..0653d75b5 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -1,12 +1,12 @@ package notification import ( + "encoding/json" "net/http" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/jsonpb" logging "github.com/ipfs/go-log" ) @@ -55,7 +55,7 @@ func (wh webhookSender) Send(notification *notificationpb.NotificationMessage) ( return Success, nil } - payload, err := wh.constructPayload(notification) + payload, err := json.Marshal(notification) if err != nil { return Failure, err } @@ -73,13 +73,3 @@ func (wh webhookSender) Send(notification *notificationpb.NotificationMessage) ( return Success, nil } - -func (wh webhookSender) constructPayload(notification *notificationpb.NotificationMessage) ([]byte, error) { - marshaler := jsonpb.Marshaler{} - payload, err := marshaler.MarshalToString(notification) - if err != nil { - log.Error(err) - return nil, err - } - return []byte(payload), nil -} diff --git a/notification/notification_test.go b/notification/notification_test.go index 4db118365..b0000924b 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -3,20 +3,23 @@ package notification import ( + "encoding/json" + "io/ioutil" + "net/http" "os" + "sync" "testing" "time" "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/assert" ) @@ -31,32 +34,57 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestWebhookConstructPayload(t *testing.T) { - documentIdentifier := utils.RandomSlice(32) - coredoc := &coredocumentpb.CoreDocument{DocumentIdentifier: documentIdentifier} - cid := utils.RandomSlice(32) +type mockConfig struct { + url string +} + +func (m mockConfig) GetReceiveEventNotificationEndpoint() string { + return m.url +} +func TestWebhookSender_Send(t *testing.T) { + docID := utils.RandomSlice(32) + cid := utils.RandomSlice(32) ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") - notificationMessage := ¬ificationpb.NotificationMessage{ - DocumentId: hexutil.Encode(coredoc.DocumentIdentifier), + var wg sync.WaitGroup + wg.Add(1) + mux := http.NewServeMux() + mux.HandleFunc("/webhook", func(writer http.ResponseWriter, request *http.Request) { + var resp struct { + EventType uint32 `json:"event_type,omitempty"` + CentrifugeId string `json:"centrifuge_id,omitempty"` + Recorded *timestamp.Timestamp `json:"recorded,omitempty"` + DocumentType string `json:"document_type,omitempty"` + DocumentId string `json:"document_id,omitempty"` + } + defer request.Body.Close() + data, err := ioutil.ReadAll(request.Body) + assert.NoError(t, err) + + err = json.Unmarshal(data, &resp) + assert.NoError(t, err) + writer.Write([]byte("success")) + assert.Equal(t, hexutil.Encode(docID), resp.DocumentId) + assert.Equal(t, hexutil.Encode(cid), resp.CentrifugeId) + wg.Done() + }) + + server := &http.Server{Addr: ":8090", Handler: mux} + go server.ListenAndServe() + defer server.Close() + + wb := NewWebhookSender(mockConfig{url: "http://localhost:8090/webhook"}) + notif := ¬ificationpb.NotificationMessage{ + DocumentId: hexutil.Encode(docID), DocumentType: documenttypes.InvoiceDataTypeUrl, CentrifugeId: hexutil.Encode(cid), EventType: uint32(ReceivedPayload), Recorded: ts, } - whs := webhookSender{} - bresult, err := whs.constructPayload(notificationMessage) - assert.Nil(t, err, "Should not error out") - - unmarshaledNotificationMessage := ¬ificationpb.NotificationMessage{} - - jsonpb.UnmarshalString(string(bresult), unmarshaledNotificationMessage) - - assert.Equal(t, notificationMessage.Recorded, unmarshaledNotificationMessage.Recorded, "Recorder Timestamp should be equal") - assert.Equal(t, notificationMessage.DocumentType, unmarshaledNotificationMessage.DocumentType, "DocumentType should be equal") - assert.Equal(t, notificationMessage.DocumentId, unmarshaledNotificationMessage.DocumentId, "DocumentIdentifier should be equal") - assert.Equal(t, notificationMessage.CentrifugeId, unmarshaledNotificationMessage.CentrifugeId, "CentrifugeID should be equal") - assert.Equal(t, notificationMessage.EventType, unmarshaledNotificationMessage.EventType, "EventType should be equal") + status, err := wb.Send(notif) + assert.NoError(t, err) + assert.Equal(t, status, Success) + wg.Wait() } From cc879c3cea2acec7824ca3f24900728c73e5b923 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 4 Jan 2019 17:27:46 +0100 Subject: [PATCH 112/220] [MultiTenancy] Refactor identity package to remove cycles when using data structures from the interface (#606) * Enable config database and api * Enable config database and api * Minor * Fix createConfig issue * Add Testworld test for config API * Fix bug with GET /config/tenant/list (end point url ambigous) * Fix bug with GET /config/tenant/list (end point url ambigous) * Lint fix * Generate swagger * Remove race detection from TestWorld to improve perf * Use db stored config at runtime * Lint and swagger * Fix unit tests * Fix tests * Fix unit tests * Remove -race from testworld * Refactor identity and context * Make identity work with db stored config * Fix conflicts * Fix test and lint * Try testworld without -race * merging * Merging still * Fix confgi * Fix test * Fix tests --- anchors/anchor_repository_integration_test.go | 4 +- api/server_test.go | 5 +- bootstrap/bootstrappers/bootstrapper.go | 6 +- .../testingbootstrap/testing_bootstrap.go | 4 +- cmd/centrifuge/manage_identities.go | 12 ++- cmd/common.go | 14 ++-- config/configstore/model.go | 27 ++++++- contextutil/context.go | 26 +++--- coredocument/bootstrapper.go | 3 +- coredocument/coredocument_test.go | 11 +-- coredocument/processor_test.go | 30 +++---- coredocument/validator_test.go | 14 ++-- documents/anchor_task.go | 12 ++- documents/genericdoc/service_test.go | 9 ++- documents/invoice/bootstrapper.go | 3 +- documents/invoice/handler.go | 18 ++++- documents/invoice/handler_test.go | 11 +-- documents/invoice/model_test.go | 19 +++-- documents/invoice/service_test.go | 33 +++----- documents/invoice/validator_test.go | 8 +- documents/purchaseorder/bootstrapper.go | 3 +- documents/purchaseorder/handler.go | 18 ++++- documents/purchaseorder/handler_test.go | 9 +-- documents/purchaseorder/model_test.go | 19 +++-- documents/purchaseorder/service_test.go | 34 +++----- documents/purchaseorder/validator_test.go | 9 +-- documents/test/anchor_test.go | 11 ++- identity/{ => ethid}/bootstrapper.go | 10 +-- identity/{ => ethid}/bootstrapper_test.go | 2 +- identity/{ => ethid}/ethereum_identity.go | 81 ++++++++++--------- .../{ => ethid}/ethereum_identity_contract.go | 2 +- .../ethereum_identity_factory_contract.go | 2 +- .../ethereum_identity_integration_test.go | 18 +++-- .../ethereum_identity_registry_contract.go | 2 +- .../{ => ethid}/ethereum_identity_test.go | 58 ++++++------- .../id_registration_confirmation_task.go | 6 +- .../id_registration_confirmation_task_test.go | 12 +-- .../key_registration_confirmation_task.go | 10 ++- ...key_registration_confirmation_task_test.go | 20 ++--- identity/{ => ethid}/test_bootstrapper.go | 2 +- identity/{ => ethid}/util.go | 11 ++- identity/identity.go | 5 +- nft/bootstrapper.go | 3 +- nft/payment_obligation_integration_test.go | 10 +-- p2p/receiver/handler.go | 10 ++- p2p/receiver/handler_integration_test.go | 4 +- testingutils/commons/mock_identity.go | 4 +- testingutils/config/config.go | 14 ++++ testworld/park.go | 4 +- 49 files changed, 364 insertions(+), 298 deletions(-) rename identity/{ => ethid}/bootstrapper.go (91%) rename identity/{ => ethid}/bootstrapper_test.go (93%) rename identity/{ => ethid}/ethereum_identity.go (83%) rename identity/{ => ethid}/ethereum_identity_contract.go (99%) rename identity/{ => ethid}/ethereum_identity_factory_contract.go (99%) rename identity/{ => ethid}/ethereum_identity_integration_test.go (89%) rename identity/{ => ethid}/ethereum_identity_registry_contract.go (99%) rename identity/{ => ethid}/ethereum_identity_test.go (89%) rename identity/{ => ethid}/id_registration_confirmation_task.go (97%) rename identity/{ => ethid}/id_registration_confirmation_task_test.go (84%) rename identity/{ => ethid}/key_registration_confirmation_task.go (97%) rename identity/{ => ethid}/key_registration_confirmation_task_test.go (87%) rename identity/{ => ethid}/test_bootstrapper.go (92%) rename identity/{ => ethid}/util.go (72%) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 3e66a56e8..957333e57 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/anchors" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" @@ -25,7 +27,7 @@ var ( func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - identityService = ctx[identity.BootstrappedIDService].(identity.Service) + identityService = ctx[ethid.BootstrappedIDService].(identity.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/api/server_test.go b/api/server_test.go index a1a3f0f1d..90ce27d75 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -22,7 +24,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" @@ -51,7 +52,7 @@ func TestMain(m *testing.M) { transactions.Bootstrapper{}, &queue.Bootstrapper{}, anchors.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index e1254559f..300472943 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -11,7 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/p2p" @@ -40,7 +40,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { ethereum.Bootstrapper{}, &queue.Bootstrapper{}, &anchors.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, @@ -62,7 +62,7 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { ethereum.Bootstrapper{}, &queue.Bootstrapper{}, &anchors.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, } } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index ff6abc54e..2f1492162 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -13,7 +13,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" @@ -34,7 +34,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ ethereum.Bootstrapper{}, &queue.Bootstrapper{}, anchors.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index b3836f721..f059d72b4 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -3,6 +3,11 @@ package main import ( "io/ioutil" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/identity" "github.com/spf13/cobra" @@ -30,7 +35,7 @@ var createIdentityCmd = &cobra.Command{ } } - idService := ctx[identity.BootstrappedIDService].(identity.Service) + idService := ctx[ethid.BootstrappedIDService].(identity.Service) _, confirmations, err := idService.CreateIdentity(centID) if err != nil { panic(err) @@ -71,8 +76,9 @@ var addKeyCmd = &cobra.Command{ panic("Option not supported") } - idService := ctx[identity.BootstrappedIDService].(identity.Service) - err := idService.AddKeyFromConfig(purposeInt) + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + idService := ctx[ethid.BootstrappedIDService].(identity.Service) + err := idService.AddKeyFromConfig(cfg, purposeInt) if err != nil { panic(err) } diff --git a/cmd/common.go b/cmd/common.go index 8c1d6a223..16c658d84 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,6 +3,8 @@ package cmd import ( "context" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/storage" @@ -38,16 +40,16 @@ func generateKeys(config config.Configuration) { crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } -func addKeys(idService identity.Service) error { - err := idService.AddKeyFromConfig(identity.KeyPurposeP2P) +func addKeys(config config.Configuration, idService identity.Service) error { + err := idService.AddKeyFromConfig(config, identity.KeyPurposeP2P) if err != nil { panic(err) } - err = idService.AddKeyFromConfig(identity.KeyPurposeSigning) + err = idService.AddKeyFromConfig(config, identity.KeyPurposeSigning) if err != nil { panic(err) } - err = idService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = idService.AddKeyFromConfig(config, identity.KeyPurposeEthMsgAuth) if err != nil { panic(err) } @@ -87,7 +89,7 @@ func CreateConfig( cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) generateKeys(cfg) - idService := ctx[identity.BootstrappedIDService].(identity.Service) + idService := ctx[ethid.BootstrappedIDService].(identity.Service) id, err := createIdentity(idService) if err != nil { return err @@ -99,7 +101,7 @@ func CreateConfig( } cfg.Set("identityId", id.String()) log.Infof("Identity created [%s] [%x]", id.String(), id) - err = addKeys(idService) + err = addKeys(cfg, idService) if err != nil { return err } diff --git a/config/configstore/model.go b/config/configstore/model.go index 7bfc25b43..3c3546224 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -448,6 +448,31 @@ type TenantConfig struct { EthAuthKeyPair KeyPair } +// GetEthereumDefaultAccountName gets EthereumDefaultAccountName +func (tc *TenantConfig) GetEthereumDefaultAccountName() string { + return tc.EthereumDefaultAccountName +} + +// GetIdentityID gets IdentityID +func (tc *TenantConfig) GetIdentityID() ([]byte, error) { + return tc.IdentityID, nil +} + +// GetSigningKeyPair gets SigningKeyPair +func (tc *TenantConfig) GetSigningKeyPair() (pub, priv string) { + return tc.SigningKeyPair.Pub, tc.SigningKeyPair.Priv +} + +// GetEthAuthKeyPair gets EthAuthKeyPair +func (tc *TenantConfig) GetEthAuthKeyPair() (pub, priv string) { + return tc.EthAuthKeyPair.Pub, tc.EthAuthKeyPair.Priv +} + +// GetEthereumContextWaitTimeout gets EthereumContextWaitTimeout +func (tc *TenantConfig) GetEthereumContextWaitTimeout() time.Duration { + panic("irrelevant, TenantConfig#GetEthereumContextWaitTimeout must not be used") +} + // ID Get the ID of the document represented by this model func (tc *TenantConfig) ID() []byte { return tc.IdentityID @@ -515,7 +540,7 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (*TenantConf return nil, err } acc, err := c.GetEthereumAccount(ethAccountName) - if err != nil { + if err != nil && ethAccountName != "" { return nil, err } return &TenantConfig{ diff --git a/contextutil/context.go b/contextutil/context.go index 7a3ec39cd..af65d51c8 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -3,17 +3,16 @@ package contextutil import ( "context" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/config/configstore" + + "github.com/centrifuge/go-centrifuge/errors" ) type contextKey string const ( - // ErrIDConfigNotFound must be used when configuration can't be found - ErrIDConfigNotFound = errors.Error("id configuration wasn't found") - // ErrSelfNotFound must be used when self value is not found in the context ErrSelfNotFound = errors.Error("self value not found in the context") @@ -21,20 +20,15 @@ const ( ) // NewCentrifugeContext creates new instance of the request headers. -// TODO [multi-tenancy] replace config.Configuration with *configstore.TenantConfig -func NewCentrifugeContext(ctx context.Context, config config.Configuration) (context.Context, error) { - idConfig, err := identity.GetIdentityConfig(config.(identity.Config)) - if err != nil { - return nil, errors.NewTypedError(ErrIDConfigNotFound, errors.New("%v", err)) - } - return context.WithValue(ctx, self, idConfig), nil +func NewCentrifugeContext(ctx context.Context, cfg *configstore.TenantConfig) (context.Context, error) { + return context.WithValue(ctx, self, cfg), nil } // Self returns Self CentID. func Self(ctx context.Context) (*identity.IDConfig, error) { - self, ok := ctx.Value(self).(*identity.IDConfig) - if ok { - return self, nil + tc, ok := ctx.Value(self).(*configstore.TenantConfig) + if !ok { + return nil, ErrSelfNotFound } - return nil, ErrSelfNotFound + return identity.GetIdentityConfig(tc) } diff --git a/coredocument/bootstrapper.go b/coredocument/bootstrapper.go index e74964a2f..ee28d6a69 100644 --- a/coredocument/bootstrapper.go +++ b/coredocument/bootstrapper.go @@ -6,6 +6,7 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" ) // Bootstrapper to initialise processor @@ -23,7 +24,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 2c2d78d39..a763f1bbf 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -3,12 +3,13 @@ package coredocument import ( - "context" "crypto/sha256" "flag" "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -245,9 +246,7 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - self, _ := contextutil.Self(ctxh) + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) collaborators, err := GetExternalCollaborators(self.ID, cd) assert.Nil(t, err) assert.NotNil(t, collaborators) @@ -261,9 +260,7 @@ func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) cd.Collaborators[1] = utils.RandomSlice(5) - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - self, _ := contextutil.Self(ctxh) + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) _, err = GetExternalCollaborators(self.ID, cd) assert.NotNil(t, err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index 5a05742b6..e7a231264 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -49,9 +51,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - err = dp.PrepareForSignatureRequests(ctxh, model) + ctxh := testingconfig.CreateTenantContext(t, cfg) + err := dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -71,11 +72,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Nil(t, FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - ctxh, err = contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.NotNil(t, err) cfg.Set("keys.signing.publicKey", pub) - ctxh, err = contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh = testingconfig.CreateTenantContext(t, cfg) // failed unpack model = mockModel{} @@ -114,13 +112,11 @@ func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = dp.RequestSignatures(ctxh, model) + err := dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -262,14 +258,12 @@ func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.Document func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = dp.AnchorDocument(ctxh, model) + err := dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") @@ -358,13 +352,11 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv := &testingcommons.MockIDService{} srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = dp.SendDocument(ctxh, model) + err := dp.SendDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go index 02e5ac5ce..d0b8fec53 100644 --- a/coredocument/validator_test.go +++ b/coredocument/validator_test.go @@ -5,9 +5,9 @@ package coredocument import ( "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/testingutils/config" - "context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -207,16 +207,14 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - self, _ := contextutil.Self(ctxh) + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) idKeys := self.Keys[identity.KeyPurposeSigning] rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) // fail getCoreDoc model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err = rfsv.Validate(nil, model) + err := rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -539,9 +537,7 @@ func TestPostAnchoredValidator(t *testing.T) { } func TestPreSignatureRequestValidator(t *testing.T) { - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - self, _ := contextutil.Self(ctxh) + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) idKeys := self.Keys[identity.KeyPurposeSigning] psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) assert.Len(t, psv, 3) diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 3b5efe664..9bdc0c133 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -2,6 +2,11 @@ package documents import ( "context" + "fmt" + + "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" @@ -91,7 +96,12 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) }() - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), d.config) + tc, err := configstore.NewTenantConfig("", d.config) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxh, err := contextutil.NewCentrifugeContext(context.Background(), tc) if err != nil { return false, errors.New("failed to get context header: %v", err) } diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index ef13623a4..6b1d4e468 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -3,19 +3,20 @@ package genericdoc import ( - "context" "math/big" "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -174,7 +175,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv // Functions returns service mocks func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s documents.Service) testingcommons.MockIDService { - idkey := &identity.EthereumIdentityKey{ + idkey := ðid.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), @@ -254,7 +255,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) i.CoreDocument.SigningRoot = nil - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) + ctxh := testingconfig.CreateTenantContext(t, cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 86c577d22..11ff74aa8 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -3,6 +3,7 @@ package invoice import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" @@ -33,7 +34,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index b30ec14a3..dcd391e9a 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -3,6 +3,8 @@ package invoice import ( "fmt" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -42,7 +44,13 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", h.config) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -74,7 +82,13 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", h.config) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index ab5371f58..f84f2dca8 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,7 +6,7 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -242,8 +242,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() @@ -259,8 +258,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() @@ -277,8 +275,7 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) txID := uuid.Must(uuid.NewV4()) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{Header: new(clientinvoicepb.ResponseHeader)} diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 80da247f8..23851052d 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -3,12 +3,15 @@ package invoice import ( - "context" "encoding/json" "os" "reflect" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" @@ -51,7 +54,7 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, @@ -189,9 +192,7 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - id, _ := contextutil.Self(contextHeader) + id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) // fail recipient data := &clientinvoicepb.InvoiceData{ Sender: "some number", @@ -200,7 +201,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { ExtraData: "some data", } inv := new(Invoice) - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) + err := inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, inv.Recipient) @@ -249,11 +250,9 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - ctxHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - id, _ := contextutil.Self(ctxHeader) + id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) m := new(Invoice) - err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) + err := m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, m.InvoiceSalts, "salts must be nil") diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 17c37383b..be7aec0b7 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -3,12 +3,12 @@ package invoice import ( - "context" "math/big" "testing" "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/gocelery" @@ -121,9 +121,7 @@ func TestService_DeriveFromPayload(t *testing.T) { _, err = invSrv.DeriveFromCreatePayload(nil, &clientinvoicepb.InvoiceCreatePayload{}) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - model, err = invSrv.DeriveFromCreatePayload(contextHeader, payload) + model, err = invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") receivedCoreDocument, err := model.PackCoreDocument() @@ -227,8 +225,7 @@ func TestService_Exists(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) _, srv := getServiceWithMockedLayers() invSrv := srv.(service) @@ -258,9 +255,7 @@ func TestService_DeriveInvoiceData(t *testing.T) { // success payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - inv, err := invSrv.DeriveFromCreatePayload(contextHeader, payload) + inv, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) assert.Nil(t, err, "must be non nil") data, err := invSrv.DeriveInvoiceData(inv) assert.Nil(t, err, "Derive must succeed") @@ -271,9 +266,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // success invSrv := service{repo: testRepo()} payload := testingdocuments.CreateInvoicePayload() - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - inv1, err := invSrv.DeriveFromCreatePayload(contextHeader, payload) + inv1, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) assert.Nil(t, err, "must be non nil") inv, ok := inv1.(*Invoice) assert.True(t, ok) @@ -288,7 +281,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // Functions returns service mocks func mockSignatureCheck(i *Invoice, idService testingcommons.MockIDService, invSrv Service) testingcommons.MockIDService { - idkey := &identity.EthereumIdentityKey{ + idkey := ðid.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), @@ -378,8 +371,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) i.CoreDocument.SigningRoot = nil - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - signature, err := invSrv.RequestDocumentSignature(ctxh, i) + signature, err := invSrv.RequestDocumentSignature(testingconfig.CreateTenantContext(t, cfg), i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, signature) @@ -493,8 +485,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + contextHeader := testingconfig.CreateTenantContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) @@ -564,13 +555,12 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_Update(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // pack failed model := &mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, err = invSrv.Update(ctxh, model) + _, _, err := invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -634,8 +624,7 @@ func TestService_Update(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // type mismatch inv, err := invSrv.calculateDataRoot(nil, &testingdocuments.MockModel{}, nil) diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 88e566bd9..728f190ce 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -5,9 +5,9 @@ package invoice import ( "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/testingutils/config" - "context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" @@ -82,9 +82,7 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - id, _ := contextutil.Self(contextHeader) + id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) inv := new(Invoice) err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 8f72d47b4..3b2aaffe5 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -3,6 +3,7 @@ package purchaseorder import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" @@ -33,7 +34,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 15384d12d..30a6ad7ef 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -3,6 +3,8 @@ package purchaseorder import ( "fmt" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -43,7 +45,13 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - ctxh, err := contextutil.NewCentrifugeContext(ctx, h.config) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", h.config) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxh, err := contextutil.NewCentrifugeContext(ctx, tc) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, err.Error()) @@ -75,7 +83,13 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, h.config) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", h.config) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 872f5070c..552e48b30 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,8 +6,9 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -78,8 +79,7 @@ func TestGRPCHandler_Create(t *testing.T) { req := testingdocuments.CreatePOPayload() ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // derive fails srv := h.service.(*mockService) @@ -134,8 +134,7 @@ func TestGrpcHandler_Update(t *testing.T) { } ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // derive fails srv := h.service.(*mockService) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index fbf21a4b9..a74909438 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -3,12 +3,15 @@ package purchaseorder import ( - "context" "encoding/json" "os" "reflect" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" @@ -51,7 +54,7 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, - &identity.Bootstrapper{}, + ðid.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, @@ -185,16 +188,14 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - id, _ := contextutil.Self(contextHeader) - assert.Nil(t, err) + id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "some recipient", ExtraData: "some data", } poModel := new(PurchaseOrder) - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) + err := poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, poModel.Recipient) @@ -224,11 +225,9 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { } func TestPOModel_calculateDataRoot(t *testing.T) { - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) - id, _ := contextutil.Self(contextHeader) + id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) poModel := new(PurchaseOrder) - err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) + err := poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, poModel.PurchaseOrderSalt, "salts must be nil") diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 513aa02d6..311286b19 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -3,10 +3,11 @@ package purchaseorder import ( - "context" "math/big" "testing" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/common" @@ -62,13 +63,12 @@ func TestService_Update(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // pack failed model := &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, err = poSrv.Update(ctxh, model) + _, _, err := poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -148,8 +148,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + contextHeader := testingconfig.CreateTenantContext(t, cfg) payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) @@ -215,8 +214,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_DeriveFromCreatePayload(t *testing.T) { poSrv := service{} - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // nil payload m, err := poSrv.DeriveFromCreatePayload(ctxh, nil) @@ -270,8 +268,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() @@ -354,7 +351,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, er // Functions returns service mocks func mockSignatureCheck(i *PurchaseOrder, srv *testingcommons.MockIDService, poSrv Service) *testingcommons.MockIDService { - idkey := &identity.EthereumIdentityKey{ + idkey := ðid.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), @@ -477,8 +474,6 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model _, poSrv := getServiceWithMockedLayers() - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) // unknown type m = &testingdocuments.MockModel{} @@ -489,7 +484,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - m, err = poSrv.DeriveFromCreatePayload(ctxh, payload) + m, err = poSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) assert.Nil(t, err) d, err = poSrv.DerivePurchaseOrderData(m) assert.Nil(t, err) @@ -498,8 +493,6 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { func TestService_DerivePurchaseOrderResponse(t *testing.T) { poSrv := service{} - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) // pack fails m := &testingdocuments.MockModel{} @@ -533,7 +526,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) + po, err := poSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) assert.Nil(t, err) r, err = poSrv.DerivePurchaseOrderResponse(po) assert.Nil(t, err) @@ -668,10 +661,8 @@ func TestService_ReceiveAnchoredDocument(t *testing.T) { } func TestService_RequestDocumentSignature(t *testing.T) { - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) poSrv := service{} - s, err := poSrv.RequestDocumentSignature(ctxh, nil) + s, err := poSrv.RequestDocumentSignature(testingconfig.CreateTenantContext(t, cfg), nil) assert.Nil(t, s) assert.Error(t, err) } @@ -680,8 +671,7 @@ func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{config: c, repo: testRepo()} - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) // type mismatch po, err := poSrv.calculateDataRoot(nil, &testingdocuments.MockModel{}, nil) diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 0f044b237..407ea03a9 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -5,9 +5,9 @@ package purchaseorder import ( "testing" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/testingutils/config" - "context" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" @@ -49,11 +49,10 @@ func TestFieldValidator_Validate(t *testing.T) { func TestDataRootValidation_Validate(t *testing.T) { drv := dataRootValidator() - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + contextHeader := testingconfig.CreateTenantContext(t, cfg) // nil error - err = drv.Validate(nil, nil) + err := drv.Validate(nil, nil) assert.Error(t, err) assert.Contains(t, err.Error(), "nil document") diff --git a/documents/test/anchor_test.go b/documents/test/anchor_test.go index ce311efa0..4764269e5 100644 --- a/documents/test/anchor_test.go +++ b/documents/test/anchor_test.go @@ -3,14 +3,15 @@ package documents_test import ( - "context" "errors" - "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "os" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" @@ -33,9 +34,7 @@ func TestMain(m *testing.M) { } func TestAnchorDocument(t *testing.T) { - ctx := context.Background() - ctxh, err := contextutil.NewCentrifugeContext(ctx, cfg) - assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) updater := func(id []byte, model documents.Model) error { return nil } diff --git a/identity/bootstrapper.go b/identity/ethid/bootstrapper.go similarity index 91% rename from identity/bootstrapper.go rename to identity/ethid/bootstrapper.go index cb18a220c..7c9f7c625 100644 --- a/identity/bootstrapper.go +++ b/identity/ethid/bootstrapper.go @@ -1,7 +1,8 @@ -package identity +package ethid import ( "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -21,10 +22,9 @@ type Bootstrapper struct{} // the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { // we have to allow loading from file in case this is coming from create config cmd where we don't add configs to db - // TODO make the db config work for identity, would have to remove idconfig stuff from the contextutil package as it creates dep cycles - cfg, ok := context[bootstrap.BootstrappedConfig].(config.Configuration) - if !ok { - return errors.New("config hasn't been initialized") + cfg, err := configstore.RetrieveConfig(false, context) + if err != nil { + return err } if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { diff --git a/identity/bootstrapper_test.go b/identity/ethid/bootstrapper_test.go similarity index 93% rename from identity/bootstrapper_test.go rename to identity/ethid/bootstrapper_test.go index 74bf1bc9f..a227d3cb5 100644 --- a/identity/bootstrapper_test.go +++ b/identity/ethid/bootstrapper_test.go @@ -1,6 +1,6 @@ // +build unit -package identity +package ethid import ( "testing" diff --git a/identity/ethereum_identity.go b/identity/ethid/ethereum_identity.go similarity index 83% rename from identity/ethereum_identity.go rename to identity/ethid/ethereum_identity.go index 207088b4e..4e7e94d93 100644 --- a/identity/ethereum_identity.go +++ b/identity/ethid/ethereum_identity.go @@ -1,4 +1,4 @@ -package identity +package ethid import ( "context" @@ -6,6 +6,7 @@ import ( "math/big" "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/identity" "bytes" @@ -76,17 +77,17 @@ func (idk *EthereumIdentityKey) String() string { } type ethereumIdentity struct { - centID CentID + centID identity.CentID contract contract contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) registryContract registry // TODO [multi-tenancy] replace this with config service - config Config + config identity.Config gethClientFinder func() ethereum.Client queue *queue.Server } -func newEthereumIdentity(id CentID, registryContract registry, config Config, +func newEthereumIdentity(id identity.CentID, registryContract registry, config identity.Config, queue *queue.Server, gethClientFinder func() ethereum.Client, contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) *ethereumIdentity { @@ -94,7 +95,7 @@ func newEthereumIdentity(id CentID, registryContract registry, config Config, } // CentrifugeID sets the CentID to the Identity -func (id *ethereumIdentity) SetCentrifugeID(centID CentID) { +func (id *ethereumIdentity) SetCentrifugeID(centID identity.CentID) { id.centID = centID } @@ -104,7 +105,7 @@ func (id *ethereumIdentity) String() string { } // CentrifugeID returns the CentrifugeID -func (id *ethereumIdentity) CentID() CentID { +func (id *ethereumIdentity) CentID() identity.CentID { return id.centID } @@ -123,7 +124,7 @@ func (id *ethereumIdentity) LastKeyForPurpose(keyPurpose int) (key []byte, err e } // FetchKey fetches the Key from the chain -func (id *ethereumIdentity) FetchKey(key []byte) (Key, error) { +func (id *ethereumIdentity) FetchKey(key []byte) (identity.Key, error) { contract, err := id.getContract() if err != nil { return nil, err @@ -146,7 +147,7 @@ func (id *ethereumIdentity) FetchKey(key []byte) (Key, error) { // CurrentP2PKey returns the latest P2P key func (id *ethereumIdentity) CurrentP2PKey() (ret string, err error) { - key, err := id.LastKeyForPurpose(KeyPurposeP2P) + key, err := id.LastKeyForPurpose(identity.KeyPurposeP2P) if err != nil { return ret, err } @@ -199,7 +200,7 @@ func (id *ethereumIdentity) getContract() (contract contract, err error) { } // AddKeyToIdentity adds key to the purpose on chain -func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) { +func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *identity.WatchIdentity, err error) { if utils.IsEmptyByteSlice(key) || len(key) > 32 { log.Errorf("Can't add key to identity: empty or invalid length(>32) key for [id: %s]: %x", id, key) return confirmations, errors.New("Can't add key to identity: Invalid key") @@ -284,7 +285,7 @@ func sendKeyRegistrationTransaction(identityContract contract, opts *bind.Transa } // sendIdentityCreationTransaction sends the actual transaction to create identity on Ethereum registry contract -func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated Identity) error { +func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated identity.Identity) error { //preparation of data in specific types for the call to Ethereum tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) if err != nil { @@ -298,9 +299,9 @@ func sendIdentityCreationTransaction(identityFactory factory, opts *bind.Transac } // setUpKeyRegisteredEventListener listens for Identity creation -func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config Config, identity Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *WatchIdentity, err error) { - confirmations = make(chan *WatchIdentity) - centID := identity.CentID() +func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config identity.Config, i identity.Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *identity.WatchIdentity, err error) { + confirmations = make(chan *identity.WatchIdentity) + centID := i.CentID() if err != nil { return nil, err } @@ -314,14 +315,14 @@ func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config Config, ident if err != nil { return nil, err } - go waitAndRouteKeyRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, identity) + go waitAndRouteKeyRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, i) return confirmations, nil } // setUpRegistrationEventListener sets up the listened for the "IdentityCreated" event to notify the upstream code about successful mining/creation // of the identity. -func (ids *EthereumIdentityService) setUpRegistrationEventListener(config Config, identityToBeCreated Identity, blockHeight uint64) (confirmations chan *WatchIdentity, err error) { - confirmations = make(chan *WatchIdentity) +func (ids *ethereumIdentityService) setUpRegistrationEventListener(config identity.Config, identityToBeCreated identity.Identity, blockHeight uint64) (confirmations chan *identity.WatchIdentity, err error) { + confirmations = make(chan *identity.WatchIdentity) centID := identityToBeCreated.CentID() if err != nil { return nil, err @@ -336,21 +337,21 @@ func (ids *EthereumIdentityService) setUpRegistrationEventListener(config Config } // waitAndRouteKeyRegistrationEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { +func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *identity.WatchIdentity, pushThisIdentity identity.Identity) { _, err := asyncRes.Get(timeout) - confirmations <- &WatchIdentity{Identity: pushThisIdentity, Error: err} + confirmations <- &identity.WatchIdentity{Identity: pushThisIdentity, Error: err} } // waitAndRouteIdentityRegistrationEvent notifies the confirmations channel whenever the identity creation is being noted as Ethereum event -func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *WatchIdentity, pushThisIdentity Identity) { +func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *identity.WatchIdentity, pushThisIdentity identity.Identity) { _, err := asyncRes.Get(timeout) - confirmations <- &WatchIdentity{pushThisIdentity, err} + confirmations <- &identity.WatchIdentity{pushThisIdentity, err} } -// EthereumIdentityService implements `Service` -type EthereumIdentityService struct { +// ethereumIdentityService implements `Service` +type ethereumIdentityService struct { // TODO [multi-tenancy] replace this with config service - config Config + config identity.Config factoryContract factory registryContract registry gethClientFinder func() ethereum.Client @@ -359,15 +360,15 @@ type EthereumIdentityService struct { } // NewEthereumIdentityService creates a new NewEthereumIdentityService given the config and the smart contracts -func NewEthereumIdentityService(config Config, factoryContract factory, registryContract registry, +func NewEthereumIdentityService(config identity.Config, factoryContract factory, registryContract registry, queue *queue.Server, gethClientFinder func() ethereum.Client, - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) Service { - return &EthereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) identity.Service { + return ðereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} } // CheckIdentityExists checks if the identity represented by id actually exists on ethereum -func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (exists bool, err error) { +func (ids *ethereumIdentityService) CheckIdentityExists(centrifugeID identity.CentID) (exists bool, err error) { client := ids.gethClientFinder() // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := client.GetGethCallOpts() @@ -391,7 +392,7 @@ func (ids *EthereumIdentityService) CheckIdentityExists(centrifugeID CentID) (ex } // CreateIdentity creates an identity representing the id on ethereum -func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) { +func (ids *ethereumIdentityService) CreateIdentity(centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider) conn := ids.gethClientFinder() @@ -422,7 +423,7 @@ func (ids *EthereumIdentityService) CreateIdentity(centrifugeID CentID) (id Iden } // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID -func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Address, error) { +func (ids *ethereumIdentityService) GetIdentityAddress(centID identity.CentID) (common.Address, error) { // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := ethereum.GetClient().GetGethCallOpts() address, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centID.BigInt()) @@ -437,7 +438,7 @@ func (ids *EthereumIdentityService) GetIdentityAddress(centID CentID) (common.Ad } // LookupIdentityForID looks up if the identity for given CentID exists on ethereum -func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Identity, error) { +func (ids *ethereumIdentityService) LookupIdentityForID(centrifugeID identity.CentID) (identity.Identity, error) { exists, err := ids.CheckIdentityExists(centrifugeID) if !exists { return nil, errors.New("identity [%s] does not exist with err [%v]", centrifugeID, err) @@ -450,7 +451,7 @@ func (ids *EthereumIdentityService) LookupIdentityForID(centrifugeID CentID) (Id } // GetClientP2PURL returns the p2p url associated with the centID -func (ids *EthereumIdentityService) GetClientP2PURL(centID CentID) (url string, err error) { +func (ids *ethereumIdentityService) GetClientP2PURL(centID identity.CentID) (url string, err error) { target, err := ids.LookupIdentityForID(centID) if err != nil { return url, errors.New("error fetching receiver identity: %v", err) @@ -466,7 +467,7 @@ func (ids *EthereumIdentityService) GetClientP2PURL(centID CentID) (url string, // GetClientsP2PURLs returns p2p urls associated with each centIDs // will error out at first failure -func (ids *EthereumIdentityService) GetClientsP2PURLs(centIDs []CentID) ([]string, error) { +func (ids *ethereumIdentityService) GetClientsP2PURLs(centIDs []identity.CentID) ([]string, error) { var p2pURLs []string for _, id := range centIDs { url, err := ids.GetClientP2PURL(id) @@ -481,7 +482,7 @@ func (ids *EthereumIdentityService) GetClientsP2PURLs(centIDs []CentID) ([]strin } // GetIdentityKey returns the key for provided identity -func (ids *EthereumIdentityService) GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) { +func (ids *ethereumIdentityService) GetIdentityKey(identity identity.CentID, pubKey []byte) (keyInfo identity.Key, err error) { id, err := ids.LookupIdentityForID(identity) if err != nil { return keyInfo, err @@ -500,7 +501,7 @@ func (ids *EthereumIdentityService) GetIdentityKey(identity CentID, pubKey []byt } // ValidateKey checks if a given key is valid for the given centrifugeID. -func (ids *EthereumIdentityService) ValidateKey(centID CentID, key []byte, purpose int) error { +func (ids *ethereumIdentityService) ValidateKey(centID identity.CentID, key []byte, purpose int) error { idKey, err := ids.GetIdentityKey(centID, key) if err != nil { return err @@ -522,8 +523,8 @@ func (ids *EthereumIdentityService) ValidateKey(centID CentID, key []byte, purpo } // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file -func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { - identityConfig, err := GetIdentityConfig(ids.config) +func (ids *ethereumIdentityService) AddKeyFromConfig(config identity.Config, purpose int) error { + identityConfig, err := identity.GetIdentityConfig(config) if err != nil { return err } @@ -533,7 +534,7 @@ func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { return err } - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(ids.config.GetEthereumContextWaitTimeout()) + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(config.GetEthereumContextWaitTimeout()) defer cancel() confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) if err != nil { @@ -552,13 +553,13 @@ func (ids *EthereumIdentityService) AddKeyFromConfig(purpose int) error { } // ValidateSignature validates a signature on a message based on identity data -func (ids *EthereumIdentityService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { - centID, err := ToCentID(signature.EntityId) +func (ids *ethereumIdentityService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { + centID, err := identity.ToCentID(signature.EntityId) if err != nil { return err } - err = ids.ValidateKey(centID, signature.PublicKey, KeyPurposeSigning) + err = ids.ValidateKey(centID, signature.PublicKey, identity.KeyPurposeSigning) if err != nil { return err } diff --git a/identity/ethereum_identity_contract.go b/identity/ethid/ethereum_identity_contract.go similarity index 99% rename from identity/ethereum_identity_contract.go rename to identity/ethid/ethereum_identity_contract.go index 9bf4bbdd3..1481fa50f 100644 --- a/identity/ethereum_identity_contract.go +++ b/identity/ethid/ethereum_identity_contract.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package identity +package ethid import ( "math/big" diff --git a/identity/ethereum_identity_factory_contract.go b/identity/ethid/ethereum_identity_factory_contract.go similarity index 99% rename from identity/ethereum_identity_factory_contract.go rename to identity/ethid/ethereum_identity_factory_contract.go index e7df612c2..aaa0025e0 100644 --- a/identity/ethereum_identity_factory_contract.go +++ b/identity/ethid/ethereum_identity_factory_contract.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package identity +package ethid import ( "math/big" diff --git a/identity/ethereum_identity_integration_test.go b/identity/ethid/ethereum_identity_integration_test.go similarity index 89% rename from identity/ethereum_identity_integration_test.go rename to identity/ethid/ethereum_identity_integration_test.go index 5fb0106f4..56c1d39c7 100644 --- a/identity/ethereum_identity_integration_test.go +++ b/identity/ethid/ethereum_identity_integration_test.go @@ -1,6 +1,6 @@ // +build integration -package identity_test +package ethid_test import ( "context" @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" @@ -25,7 +27,7 @@ func TestMain(m *testing.M) { time.Sleep(time.Second + 2) ctx := cc.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - identityService = ctx[identity.BootstrappedIDService].(identity.Service) + identityService = ctx[ethid.BootstrappedIDService].(identity.Service) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -80,8 +82,8 @@ func TestAddKeyFromConfig(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) defaultCentrifugeId := cfg.GetString("identityId") cfg.Set("identityId", centrifugeId.String()) - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") _, confirmations, err := identityService.CreateIdentity(centrifugeId) assert.Nil(t, err, "should not error out when creating identity") @@ -89,7 +91,7 @@ func TestAddKeyFromConfig(t *testing.T) { assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - err = identityService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err = identityService.AddKeyFromConfig(cfg, identity.KeyPurposeEthMsgAuth) assert.Nil(t, err, "should not error out") cfg.Set("identityId", defaultCentrifugeId) @@ -99,10 +101,10 @@ func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) defaultCentrifugeId := cfg.GetString("identityId") cfg.Set("identityId", centrifugeId.String()) - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - err := identityService.AddKeyFromConfig(identity.KeyPurposeEthMsgAuth) + err := identityService.AddKeyFromConfig(cfg, identity.KeyPurposeEthMsgAuth) assert.NotNil(t, err, "should error out") cfg.Set("identityId", defaultCentrifugeId) diff --git a/identity/ethereum_identity_registry_contract.go b/identity/ethid/ethereum_identity_registry_contract.go similarity index 99% rename from identity/ethereum_identity_registry_contract.go rename to identity/ethid/ethereum_identity_registry_contract.go index 84aee7b4f..10e96b744 100644 --- a/identity/ethereum_identity_registry_contract.go +++ b/identity/ethid/ethereum_identity_registry_contract.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package identity +package ethid import ( "math/big" diff --git a/identity/ethereum_identity_test.go b/identity/ethid/ethereum_identity_test.go similarity index 89% rename from identity/ethereum_identity_test.go rename to identity/ethid/ethereum_identity_test.go index 8388a36f8..f23dc378a 100644 --- a/identity/ethereum_identity_test.go +++ b/identity/ethid/ethereum_identity_test.go @@ -1,6 +1,6 @@ // +build unit -package identity +package ethid import ( "context" @@ -8,6 +8,8 @@ import ( "net/url" "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -102,7 +104,7 @@ func (mic MockIDContract) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, } func TestGetClientP2PURL_happy(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) @@ -122,7 +124,7 @@ func TestGetClientP2PURL_happy(t *testing.T) { } func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) @@ -142,7 +144,7 @@ func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { } func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) @@ -163,7 +165,7 @@ func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { } func TestGetIdentityKey_fail_lookup(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) @@ -183,7 +185,7 @@ func TestGetIdentityKey_fail_lookup(t *testing.T) { } func TestGetIdentityKey_fail_FetchKey(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) @@ -195,7 +197,7 @@ func TestGetIdentityKey_fail_FetchKey(t *testing.T) { RevokedAt *big.Int }{ [32]byte{1}, - []*big.Int{big.NewInt(KeyPurposeP2P)}, + []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, big.NewInt(1), }, errors.New("p2p key error")) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -213,7 +215,7 @@ func TestGetIdentityKey_fail_FetchKey(t *testing.T) { } func TestGetIdentityKey_fail_empty(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) @@ -225,7 +227,7 @@ func TestGetIdentityKey_fail_empty(t *testing.T) { RevokedAt *big.Int }{ [32]byte{}, - []*big.Int{big.NewInt(KeyPurposeP2P)}, + []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, big.NewInt(1), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -243,7 +245,7 @@ func TestGetIdentityKey_fail_empty(t *testing.T) { } func TestGetIdentityKey_Success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) @@ -255,7 +257,7 @@ func TestGetIdentityKey_Success(t *testing.T) { RevokedAt *big.Int }{ [32]byte{1}, - []*big.Int{big.NewInt(KeyPurposeP2P)}, + []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, big.NewInt(1), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -272,7 +274,7 @@ func TestGetIdentityKey_Success(t *testing.T) { } func TestValidateKey_success(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) @@ -286,7 +288,7 @@ func TestValidateKey_success(t *testing.T) { RevokedAt *big.Int }{ key, - []*big.Int{big.NewInt(KeyPurposeSigning)}, + []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, big.NewInt(0), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -294,7 +296,7 @@ func TestValidateKey_success(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) @@ -302,7 +304,7 @@ func TestValidateKey_success(t *testing.T) { } func TestValidateKey_fail_getId(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) @@ -316,7 +318,7 @@ func TestValidateKey_fail_getId(t *testing.T) { RevokedAt *big.Int }{ key, - []*big.Int{big.NewInt(KeyPurposeSigning)}, + []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, big.NewInt(0), }, errors.New("Key error")) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -324,7 +326,7 @@ func TestValidateKey_fail_getId(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) @@ -332,7 +334,7 @@ func TestValidateKey_fail_getId(t *testing.T) { } func TestValidateKey_fail_mismatch_key(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) @@ -344,7 +346,7 @@ func TestValidateKey_fail_mismatch_key(t *testing.T) { RevokedAt *big.Int }{ [32]byte{1}, - []*big.Int{big.NewInt(KeyPurposeSigning)}, + []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, big.NewInt(0), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -352,7 +354,7 @@ func TestValidateKey_fail_mismatch_key(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) @@ -360,7 +362,7 @@ func TestValidateKey_fail_mismatch_key(t *testing.T) { } func TestValidateKey_fail_missing_purpose(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) @@ -382,7 +384,7 @@ func TestValidateKey_fail_missing_purpose(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) @@ -390,7 +392,7 @@ func TestValidateKey_fail_missing_purpose(t *testing.T) { } func TestValidateKey_fail_wrong_purpose(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) @@ -404,7 +406,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { RevokedAt *big.Int }{ key, - []*big.Int{big.NewInt(KeyPurposeP2P)}, + []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, big.NewInt(0), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -412,7 +414,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) @@ -420,7 +422,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { } func TestValidateKey_fail_revocation(t *testing.T) { - centID, _ := ToCentID(utils.RandomSlice(CentIDLength)) + centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) @@ -434,7 +436,7 @@ func TestValidateKey_fail_revocation(t *testing.T) { RevokedAt *big.Int }{ key, - []*big.Int{big.NewInt(KeyPurposeSigning)}, + []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, big.NewInt(1), }, nil) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -442,7 +444,7 @@ func TestValidateKey_fail_revocation(t *testing.T) { }, func(address common.Address, backend bind.ContractBackend) (contract, error) { return i, nil }) - err := srv.ValidateKey(centID, pubKey, KeyPurposeSigning) + err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) f.AssertExpectations(t) r.AssertExpectations(t) g.AssertExpectations(t) diff --git a/identity/id_registration_confirmation_task.go b/identity/ethid/id_registration_confirmation_task.go similarity index 97% rename from identity/id_registration_confirmation_task.go rename to identity/ethid/id_registration_confirmation_task.go index 706c30e2d..5c7ffbd05 100644 --- a/identity/id_registration_confirmation_task.go +++ b/identity/ethid/id_registration_confirmation_task.go @@ -1,10 +1,12 @@ -package identity +package ethid import ( "context" "math/big" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" @@ -24,7 +26,7 @@ type identitiesCreatedFilterer interface { // idRegistrationConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumIdentityFactoryContract. // To see how it gets registered see bootstrapper.go and to see how it gets used see setUpRegistrationEventListener method type idRegistrationConfirmationTask struct { - centID CentID + centID identity.CentID blockHeight uint64 timeout time.Duration contextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) diff --git a/identity/id_registration_confirmation_task_test.go b/identity/ethid/id_registration_confirmation_task_test.go similarity index 84% rename from identity/id_registration_confirmation_task_test.go rename to identity/ethid/id_registration_confirmation_task_test.go index 960d9a09c..f8030fd65 100644 --- a/identity/id_registration_confirmation_task_test.go +++ b/identity/ethid/id_registration_confirmation_task_test.go @@ -1,10 +1,12 @@ // +build unit -package identity +package ethid import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -12,10 +14,10 @@ import ( func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) blockHeight := uint64(3132) timeout := float64(3000) - idBytes, _ := ToCentID(id) + idBytes, _ := identity.ToCentID(id) kwargs := map[string]interface{}{ centIDParam: idBytes, queue.BlockHeightParam: blockHeight, @@ -32,14 +34,14 @@ func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { func TestRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) err := rct.ParseKwargs(map[string]interface{}{"notId": id}) assert.NotNil(t, err, "Should not allow parsing without centId") } func TestRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) assert.NotNil(t, err, "Should not parse without the correct type of centId") } diff --git a/identity/key_registration_confirmation_task.go b/identity/ethid/key_registration_confirmation_task.go similarity index 97% rename from identity/key_registration_confirmation_task.go rename to identity/ethid/key_registration_confirmation_task.go index d448e2f8f..80a03b896 100644 --- a/identity/key_registration_confirmation_task.go +++ b/identity/ethid/key_registration_confirmation_task.go @@ -1,10 +1,12 @@ -package identity +package ethid import ( "context" "math/big" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -28,7 +30,7 @@ type keyRegisteredFilterer interface { // keyRegistrationConfirmationTask is a queued task to filter key registration events on Ethereum using EthereumIdentityContract. // To see how it gets registered see bootstrapper.go and to see how it gets used see setUpKeyRegisteredEventListener method type keyRegistrationConfirmationTask struct { - centID CentID + centID identity.CentID key [32]byte keyPurpose int blockHeight uint64 @@ -38,7 +40,7 @@ type keyRegistrationConfirmationTask struct { filterer keyRegisteredFilterer contract *EthereumIdentityRegistryContract // TODO [multi-tenancy] replace this with config service - config Config + config identity.Config gethClientFinder func() ethereum.Client contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) queue *queue.Server @@ -47,7 +49,7 @@ type keyRegistrationConfirmationTask struct { func newKeyRegistrationConfirmationTask( ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), registryContract *EthereumIdentityRegistryContract, - config Config, + config identity.Config, queue *queue.Server, gethClientFinder func() ethereum.Client, contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error), diff --git a/identity/key_registration_confirmation_task_test.go b/identity/ethid/key_registration_confirmation_task_test.go similarity index 87% rename from identity/key_registration_confirmation_task_test.go rename to identity/ethid/key_registration_confirmation_task_test.go index 4e6115948..044aae24b 100644 --- a/identity/key_registration_confirmation_task_test.go +++ b/identity/ethid/key_registration_confirmation_task_test.go @@ -1,10 +1,12 @@ // +build unit -package identity +package ethid import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "time" "github.com/centrifuge/go-centrifuge/queue" @@ -14,13 +16,13 @@ import ( func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) key := utils.RandomSlice(32) var keyFixed [32]byte copy(keyFixed[:], key) - keyPurpose := KeyPurposeSigning + keyPurpose := identity.KeyPurposeSigning bh := uint64(12) - idBytes, _ := ToCentID(id) + idBytes, _ := identity.ToCentID(id) kwargs := map[string]interface{}{ centIDParam: idBytes, keyParam: keyFixed, @@ -40,13 +42,13 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPathOverrideTimeout(t *testing.T) { rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) key := utils.RandomSlice(32) var keyFixed [32]byte copy(keyFixed[:], key) - keyPurpose := KeyPurposeSigning + keyPurpose := identity.KeyPurposeSigning bh := uint64(12) - idBytes, _ := ToCentID(id) + idBytes, _ := identity.ToCentID(id) overrideTimeout := float64(time.Second * 3) kwargs := map[string]interface{}{ centIDParam: idBytes, @@ -69,14 +71,14 @@ func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPathOverrideTimeout(t * func TestKeyRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { rct := keyRegistrationConfirmationTask{} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) err := rct.ParseKwargs(map[string]interface{}{"notId": id}) assert.NotNil(t, err, "Should not allow parsing without centId") } func TestKeyRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { rct := keyRegistrationConfirmationTask{} - id := utils.RandomSlice(CentIDLength) + id := utils.RandomSlice(identity.CentIDLength) err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) assert.NotNil(t, err, "Should not parse without the correct type of centId") } diff --git a/identity/test_bootstrapper.go b/identity/ethid/test_bootstrapper.go similarity index 92% rename from identity/test_bootstrapper.go rename to identity/ethid/test_bootstrapper.go index bd47cc285..39c9e3416 100644 --- a/identity/test_bootstrapper.go +++ b/identity/ethid/test_bootstrapper.go @@ -1,6 +1,6 @@ // +build integration unit -package identity +package ethid func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { return b.Bootstrap(context) diff --git a/identity/util.go b/identity/ethid/util.go similarity index 72% rename from identity/util.go rename to identity/ethid/util.go index 25fe92ff9..354208908 100644 --- a/identity/util.go +++ b/identity/ethid/util.go @@ -1,6 +1,9 @@ -package identity +package ethid -import "github.com/centrifuge/go-centrifuge/errors" +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" +) const ( centIDParam string = "CentID" @@ -20,8 +23,8 @@ func getBytes32(key interface{}) ([32]byte, error) { return fixed, nil } -func getCentID(key interface{}) (CentID, error) { - var fixed [CentIDLength]byte +func getCentID(key interface{}) (identity.CentID, error) { + var fixed [identity.CentIDLength]byte b, ok := key.([]interface{}) if !ok { return fixed, errors.New("could not parse interface to []byte") diff --git a/identity/identity.go b/identity/identity.go index f6b90b435..618919cdf 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -5,8 +5,6 @@ import ( "fmt" "math/big" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" @@ -79,7 +77,6 @@ type Config interface { GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration - GetContractAddress(contractName config.ContractName) common.Address } // Identity defines an Identity on chain @@ -135,7 +132,7 @@ type Service interface { ValidateKey(centID CentID, key []byte, purpose int) error // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file - AddKeyFromConfig(purpose int) error + AddKeyFromConfig(config Config, purpose int) error // ValidateSignature validates a signature on a message based on identity data ValidateSignature(signature *coredocumentpb.Signature, message []byte) error diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 0f13c9d36..f9114299c 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -36,7 +37,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("service registry not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 3a3e2e827..c451c2daa 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,17 +3,18 @@ package nft_test import ( - "context" "os" "testing" "time" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/identity" @@ -36,7 +37,7 @@ func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - idService = ctx[identity.BootstrappedIDService].(identity.Service) + idService = ctx[ethid.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txService = ctx[transactions.BootstrappedService].(transactions.Service) @@ -53,8 +54,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), cfg) - assert.Nil(t, err) + contextHeader := testingconfig.CreateTenantContext(t, cfg) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) model, err := invoiceService.DeriveFromCreatePayload(contextHeader, &invoicepb.InvoiceCreatePayload{ diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 8a2ce8441..07f196348 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" @@ -84,7 +86,13 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, srv.config) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", srv.config) + if err != nil { + log.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) if err != nil { log.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 263a5cbf2..0ff384a42 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -46,7 +48,7 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - idService = ctx[identity.BootstrappedIDService].(identity.Service) + idService = ctx[ethid.BootstrappedIDService].(identity.Service) handler = receiver.New(cfg, registry) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() diff --git a/testingutils/commons/mock_identity.go b/testingutils/commons/mock_identity.go index bcaf2d436..34a804630 100644 --- a/testingutils/commons/mock_identity.go +++ b/testingutils/commons/mock_identity.go @@ -47,8 +47,8 @@ func (srv *MockIDService) ValidateKey(centrifugeId identity.CentID, key []byte, return args.Error(0) } -func (srv *MockIDService) AddKeyFromConfig(purpose int) error { - args := srv.Called(purpose) +func (srv *MockIDService) AddKeyFromConfig(config identity.Config, purpose int) error { + args := srv.Called(config, purpose) return args.Error(0) } diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 3ce171184..72a1be6d7 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -1,9 +1,15 @@ package testingconfig import ( + "context" "math/big" + "testing" "time" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/stretchr/testify/assert" + "github.com/centrifuge/go-centrifuge/config" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" @@ -153,3 +159,11 @@ func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { args := m.Called() return args.Get(0).(string), args.Get(1).(string) } + +func CreateTenantContext(t *testing.T, cfg config.Configuration) context.Context { + tc, err := configstore.NewTenantConfig("", cfg) + assert.Nil(t, err) + contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), tc) + assert.Nil(t, err) + return contextHeader +} diff --git a/testworld/park.go b/testworld/park.go index 86d46b59f..618c1638c 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -8,6 +8,8 @@ import ( "os" "os/signal" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "testing" @@ -246,7 +248,7 @@ func (h *host) init() error { return err } h.config = h.bootstrappedCtx[bootstrap.BootstrappedConfig].(config.Configuration) - idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) + idService := h.bootstrappedCtx[ethid.BootstrappedIDService].(identity.Service) idBytes, err := h.config.GetIdentityID() if err != nil { return err From a1983904ebeb571248b81b899a116b4eb80f2972 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 7 Jan 2019 15:41:21 +0100 Subject: [PATCH 113/220] Multi tenancy service parts complete without api handlers and p2p handlers (#609) * Multi tenancy complete without api handlers and p2p handlers * Fixed unit tests * Fix unit tests * Fix unit tests --- api/bootstrapper_test.go | 4 +- api/server.go | 5 +- api/server_test.go | 5 +- api/service.go | 23 +++-- common/common.go | 13 --- config/configstore/mock_service.go | 46 ++++++---- config/configuration.go | 3 + contextutil/context.go | 27 ++++++ documents/anchor_task.go | 19 +++-- documents/anchor_task_test.go | 7 +- documents/bootstrapper.go | 9 +- documents/genericdoc/service.go | 76 +++++++++-------- documents/genericdoc/service_test.go | 55 +++++++----- documents/handler.go | 19 ++++- documents/handler_test.go | 14 +-- documents/invoice/bootstrapper.go | 9 +- documents/invoice/handler.go | 50 +++++------ documents/invoice/handler_test.go | 29 +++---- documents/invoice/model_test.go | 3 + documents/invoice/service.go | 99 ++++++++++++++-------- documents/invoice/service_test.go | 54 +++++++----- documents/model_test.go | 5 ++ documents/purchaseorder/bootstrapper.go | 10 +-- documents/purchaseorder/handler.go | 46 +++++----- documents/purchaseorder/handler_test.go | 48 +++++------ documents/purchaseorder/model_test.go | 3 + documents/purchaseorder/service.go | 87 +++++++++++-------- documents/purchaseorder/service_test.go | 74 +++++++++------- documents/registry.go | 12 ++- documents/registry_test.go | 2 +- documents/service.go | 19 ++--- nft/bootstrapper.go | 2 +- nft/ethereum_payment_obligation.go | 63 +++++--------- nft/ethereum_payment_obligation_test.go | 16 +++- nft/handler.go | 22 +++-- nft/handler_test.go | 33 +++++--- nft/minting_confirmation_task.go | 9 +- nft/minting_confirmation_task_test.go | 8 +- nft/payment_obligation.go | 6 +- nft/payment_obligation_integration_test.go | 7 +- notification/notification.go | 24 +++--- notification/notification_test.go | 13 ++- p2p/bootstrapper_test.go | 4 +- p2p/client.go | 2 + p2p/receiver/handler.go | 15 +++- testingutils/documents/documents.go | 12 +-- transactions/base_task.go | 4 +- transactions/base_task_test.go | 5 +- transactions/handler.go | 27 ++++-- transactions/handler_test.go | 12 ++- transactions/repository.go | 17 ++-- transactions/repository_test.go | 38 ++++----- transactions/service.go | 19 +++-- transactions/service_test.go | 33 ++++---- transactions/transaction.go | 9 +- 55 files changed, 714 insertions(+), 561 deletions(-) delete mode 100644 common/common.go diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index a5b5f3922..bb74d20da 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -23,7 +23,9 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) - m[configstore.BootstrappedConfigStorage] = new(configstore.MockService) + cs := new(configstore.MockService) + m[configstore.BootstrappedConfigStorage] = cs + cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/api/server.go b/api/server.go index f6c43fae0..b3146e3d7 100644 --- a/api/server.go +++ b/api/server.go @@ -11,7 +11,8 @@ import ( "sync" "time" - "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -210,7 +211,7 @@ func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, hand return nil, err } - ctx = context.WithValue(ctx, common.TenantKey, auth[0]) + ctx = context.WithValue(ctx, config.TenantKey, auth[0]) return handler(ctx, req) } diff --git a/api/server_test.go b/api/server_test.go index 90ce27d75..b8b0b49ff 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -17,7 +17,6 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" - "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -74,7 +73,7 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(cfg, nil, nil, nil, nil, nil)) + registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(nil, nil, nil, nil, nil)) capi := apiServer{config: cfg} ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) startErr := make(chan error) @@ -122,7 +121,7 @@ func TestCentAPIServer_FailedToGetRegistry(t *testing.T) { func Test_auth(t *testing.T) { handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return ctx.Value(common.TenantKey), nil + return ctx.Value(config.TenantKey), nil } // send ping path diff --git a/api/service.go b/api/service.go index 838d3b2d1..54e6d7c76 100644 --- a/api/service.go +++ b/api/service.go @@ -2,7 +2,6 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -36,21 +35,26 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, if !ok { return errors.New("failed to get %s", documents.BootstrappedRegistry) } + + configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(configstore.Service) + if !ok { + return errors.New("failed to get %s", configstore.BootstrappedConfigStorage) + } + payObService, ok := nodeObjReg[nft.BootstrappedPayObService].(nft.PaymentObligation) if !ok { return errors.New("failed to get %s", nft.BootstrappedPayObService) } // documents (common) - documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler(registry)) + documentpb.RegisterDocumentServiceServer(grpcServer, documents.GRPCHandler(configService, registry)) err := documentpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err } // invoice - invCfg := cfg.(config.Configuration) - handler, err := invoice.GRPCHandler(invCfg, registry) + handler, err := invoice.GRPCHandler(configService, registry) if err != nil { return err } @@ -61,8 +65,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // purchase orders - poCfg := cfg.(config.Configuration) - srv, err := purchaseorder.GRPCHandler(poCfg, registry) + srv, err := purchaseorder.GRPCHandler(configService, registry) if err != nil { return errors.New("failed to get purchase order handler: %v", err) } @@ -82,17 +85,13 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // nft api - nftpb.RegisterNFTServiceServer(grpcServer, nft.GRPCHandler(payObService)) + nftpb.RegisterNFTServiceServer(grpcServer, nft.GRPCHandler(configService, payObService)) err = nftpb.RegisterNFTServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err } // config api - configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(configstore.Service) - if !ok { - return errors.New("failed to get %s", configstore.BootstrappedConfigStorage) - } configpb.RegisterConfigServiceServer(grpcServer, configstore.GRPCHandler(configService)) err = configpb.RegisterConfigServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { @@ -101,7 +100,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, // transactions txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Service) - h := transactions.GRPCHandler(txSrv) + h := transactions.GRPCHandler(txSrv, configService) transactionspb.RegisterTransactionServiceServer(grpcServer, h) if err := transactionspb.RegisterTransactionServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts); err != nil { return err diff --git a/common/common.go b/common/common.go deleted file mode 100644 index d447030e6..000000000 --- a/common/common.go +++ /dev/null @@ -1,13 +0,0 @@ -// Package common holds the common types used across the node -package common - -import "github.com/ethereum/go-ethereum/common" - -var ( - // TenantKey is used as key for the tenant identity in the context.ContextWithValue. - TenantKey struct{} - - // DummyIdentity to be used until we have identity coming from auth header - // TODO(ved): get rid of this once we have multitenancy enabled - DummyIdentity = common.Address([20]byte{1}) -) diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 53efcde2d..191a10f54 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -8,38 +8,48 @@ type MockService struct { mock.Mock } -func (MockService) GetConfig() (*NodeConfig, error) { - return nil, nil +func (m MockService) GetConfig() (*NodeConfig, error) { + args := m.Called() + return args.Get(0).(*NodeConfig), args.Error(1) } -func (MockService) GetTenant(identifier []byte) (*TenantConfig, error) { - panic("implement me") +func (m MockService) GetTenant(identifier []byte) (*TenantConfig, error) { + args := m.Called(identifier) + return args.Get(0).(*TenantConfig), args.Error(0) } -func (MockService) GetAllTenants() ([]*TenantConfig, error) { - panic("implement me") +func (m MockService) GetAllTenants() ([]*TenantConfig, error) { + args := m.Called() + v, _ := args.Get(0).([]*TenantConfig) + return v, nil } -func (MockService) CreateConfig(data *NodeConfig) (*NodeConfig, error) { - panic("implement me") +func (m MockService) CreateConfig(data *NodeConfig) (*NodeConfig, error) { + args := m.Called(data) + return args.Get(0).(*NodeConfig), args.Error(0) } -func (MockService) CreateTenant(data *TenantConfig) (*TenantConfig, error) { - panic("implement me") +func (m MockService) CreateTenant(data *TenantConfig) (*TenantConfig, error) { + args := m.Called(data) + return args.Get(0).(*TenantConfig), args.Error(0) } -func (MockService) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { - panic("implement me") +func (m MockService) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { + args := m.Called() + return args.Get(0).(*NodeConfig), args.Error(0) } -func (MockService) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { - panic("implement me") +func (m MockService) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { + args := m.Called(data) + return args.Get(0).(*TenantConfig), args.Error(0) } -func (MockService) DeleteConfig() error { - panic("implement me") +func (m MockService) DeleteConfig() error { + args := m.Called() + return args.Error(0) } -func (MockService) DeleteTenant(identifier []byte) error { - panic("implement me") +func (m MockService) DeleteTenant(identifier []byte) error { + args := m.Called(identifier) + return args.Error(0) } diff --git a/config/configuration.go b/config/configuration.go index f18929f59..91650465d 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -28,6 +28,9 @@ import ( var log = logging.Logger("config") +// TenantKey is used as key for the tenant identity in the context.ContextWithValue. +var TenantKey struct{} + // ContractName is a type to indicate a contract name parameter type ContractName string diff --git a/contextutil/context.go b/contextutil/context.go index af65d51c8..55b44f58e 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -2,6 +2,10 @@ package contextutil import ( "context" + "fmt" + + "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/identity" @@ -32,3 +36,26 @@ func Self(ctx context.Context) (*identity.IDConfig, error) { } return identity.GetIdentityConfig(tc) } + +// Tenant extracts the TenanConfig from the given context value +func Tenant(ctx context.Context) (*configstore.TenantConfig, error) { + tc, ok := ctx.Value(self).(*configstore.TenantConfig) + if !ok { + return nil, ErrSelfNotFound + } + return tc, nil +} + +// CentContext updates a context with tenant info using the configstore, must only be used for api handlers +func CentContext(ctx context.Context, config configstore.Service) (context.Context, error) { + // TODO [multi-tenancy] remove following and read the tenantID from the context + tc, err := config.GetAllTenants() + if err != nil { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := NewCentrifugeContext(ctx, tc[0]) + if err != nil { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + return ctxHeader, nil +} diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 9bdc0c133..254d9ebf1 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -4,17 +4,17 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" @@ -32,10 +32,10 @@ type documentAnchorTask struct { transactions.BaseTask id []byte - tenantID common.Address + tenantID identity.CentID // state - config config.Configuration + config configstore.Service processor anchorProcessor modelGetFunc func(tenantID, id []byte) (Model, error) modelSaveFunc func(tenantID, id []byte, model Model) error @@ -68,7 +68,10 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { return errors.New("missing tenant ID") } - d.tenantID = common.HexToAddress(tenantID) + d.tenantID, err = identity.CentIDFromString(tenantID) + if err != nil { + return errors.New("invalid cent ID") + } return nil } @@ -96,7 +99,7 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) }() - tc, err := configstore.NewTenantConfig("", d.config) + tc, err := d.config.GetTenant(d.tenantID[:]) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) @@ -126,7 +129,7 @@ type taskQueuer interface { } // InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. -func InitDocumentAnchorTask(tq taskQueuer, txService transactions.Service, tenantID common.Address, modelID []byte) (uuid.UUID, error) { +func InitDocumentAnchorTask(tq taskQueuer, txService transactions.Service, tenantID identity.CentID, modelID []byte) (uuid.UUID, error) { tx, err := txService.CreateTransaction(tenantID, documentAnchorTaskName) if err != nil { return uuid.Nil, err @@ -135,7 +138,7 @@ func InitDocumentAnchorTask(tq taskQueuer, txService transactions.Service, tenan params := map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), modelIDParam: hexutil.Encode(modelID), - tenantIDParam: tenantID, + tenantIDParam: tenantID.String(), } _, err = tq.EnqueueJob(documentAnchorTaskName, params) diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index fb6618720..670224fae 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -5,7 +5,8 @@ package documents import ( "testing" - cc "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -55,7 +56,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { kwargs: map[string]interface{}{ transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), modelIDParam: hexutil.Encode(utils.RandomSlice(32)), - tenantIDParam: cc.DummyIdentity, + tenantIDParam: identity.RandomCentID().String(), }, }, } @@ -77,7 +78,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { if c.err == "" { assert.Equal(t, task.TxID.String(), c.kwargs[transactions.TxIDParam]) assert.Equal(t, hexutil.Encode(task.id), c.kwargs[modelIDParam]) - assert.Equal(t, task.tenantID, c.kwargs[tenantIDParam]) + assert.Equal(t, task.tenantID.String(), c.kwargs[tenantIDParam]) return } diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 352d3deb3..ad285af87 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -36,10 +36,11 @@ type PostBootstrapper struct{} // Bootstrap register task to the queue. func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(true, ctx) - if err != nil { - return err + cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + if !ok { + return errors.New("config service not initialised") } + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) if !ok { return errors.New("queue not initialised") @@ -59,7 +60,7 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { BaseTask: transactions.BaseTask{ TxService: ctx[transactions.BootstrappedService].(transactions.Service), }, - config: cfg, + config: cfgService, processor: coreDocProc, modelGetFunc: repo.Get, modelSaveFunc: repo.Update, diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index dc6ca7cb7..0a3279300 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -9,8 +9,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/common" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto" @@ -26,8 +24,6 @@ import ( // service implements Service type service struct { - // TODO [multi-tenancy] replace this with config service - config documents.Config repo documents.Repository identityService identity.Service notifier notification.Sender @@ -37,12 +33,12 @@ type service struct { var srvLog = logging.Logger("document-service") // DefaultService returns the default implementation of the service -func DefaultService(config config.Configuration, repo documents.Repository, +func DefaultService(repo documents.Repository, anchorRepo anchors.AnchorRepository, idService identity.Service) documents.Service { - return service{repo: repo, - config: config, + return service{ + repo: repo, anchorRepository: anchorRepo, - notifier: notification.NewWebhookSender(config), + notifier: notification.NewWebhookSender(), identityService: idService} } @@ -56,41 +52,41 @@ func getIDs(model documents.Model) ([]byte, []byte, error) { return cd.DocumentIdentifier, cd.NextVersion, nil } -func (s service) searchVersion(m documents.Model) (documents.Model, error) { +func (s service) searchVersion(ctx context.Context, m documents.Model) (documents.Model, error) { id, next, err := getIDs(m) if err != nil { return nil, err } - if s.Exists(next) { - nm, err := s.getVersion(id, next) + if s.Exists(ctx, next) { + nm, err := s.getVersion(ctx, id, next) if err != nil { return nil, err } - return s.searchVersion(nm) + return s.searchVersion(ctx, nm) } return m, nil } -func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { - model, err := s.getVersion(documentID, documentID) +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { + model, err := s.getVersion(ctx, documentID, documentID) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - return s.searchVersion(model) + return s.searchVersion(ctx, model) } -func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, error) { - return s.getVersion(documentID, version) +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { + return s.getVersion(ctx, documentID, version) } -func (s service) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(documentID) +func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -114,8 +110,8 @@ func (s service) createProofs(model documents.Model, fields []string) (*document } -func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.getVersion(documentID, version) +func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.getVersion(ctx, documentID, version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } @@ -128,6 +124,11 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -138,10 +139,6 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M } srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigTenantID - } idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] if !ok { @@ -154,7 +151,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - tenantID := common.DummyIdentity.Bytes() + tenantID := idConf.ID[:] // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { @@ -173,7 +170,12 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return sig, nil } -func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { + idConf, err := contextutil.Self(ctx) + if err != nil { + return documents.ErrDocumentConfigTenantID + } + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -183,7 +185,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) + err = s.repo.Update(idConf.ID[:], doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -198,17 +200,25 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C } // Async until we add queuing - go s.notifier.Send(notificationMsg) + go s.notifier.Send(ctx, notificationMsg) return nil } -func (s service) Exists(documentID []byte) bool { - return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) +func (s service) Exists(ctx context.Context, documentID []byte) bool { + idConf, err := contextutil.Self(ctx) + if err != nil { + return false + } + return s.repo.Exists(idConf.ID[:], documentID) } -func (s service) getVersion(documentID, version []byte) (documents.Model, error) { - model, err := s.repo.Get(common.DummyIdentity.Bytes(), version) +func (s service) getVersion(ctx context.Context, documentID, version []byte) (documents.Model, error) { + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, documents.ErrDocumentConfigTenantID + } + model, err := s.repo.Get(idConf.ID[:], version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index 6b1d4e468..566c9bc12 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -32,8 +31,9 @@ import ( var testRepoGlobal documents.Repository var ( - centIDBytes = utils.RandomSlice(identity.CentIDLength) - tenantID = common.DummyIdentity.Bytes() + cid = identity.RandomCentID() + centIDBytes = cid[:] + tenantID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -51,6 +51,7 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("identityId", cid.String()) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -58,7 +59,8 @@ func TestMain(m *testing.M) { func TestService_ReceiveAnchoredDocument(t *testing.T) { poSrv := service{} - err := poSrv.ReceiveAnchoredDocument(nil, nil) + ctxh := testingconfig.CreateTenantContext(t, cfg) + err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } @@ -66,7 +68,7 @@ func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDServi repo := testRepo() idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(nil, repo, &mockAnchorRepo{}, &idService), idService + return DefaultService(repo, &mockAnchorRepo{}, &idService), idService } type mockAnchorRepo struct { @@ -195,8 +197,9 @@ func TestService_CreateProofs(t *testing.T) { service, idService := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) idService = mockSignatureCheck(i, idService, service) - proof, err := service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + proof, err := service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) @@ -211,7 +214,8 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - _, err = service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -221,14 +225,16 @@ func TestService_CreateProofsInvalidField(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - _, err = service.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { service, _ := getServiceWithMockedLayers() - _, err := service.CreateProofs(utils.RandomSlice(32), []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err := service.CreateProofs(ctxh, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) } @@ -241,7 +247,8 @@ func TestService_CreateProofsForVersion(t *testing.T) { olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - proof, err := service.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + proof, err := service.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) @@ -266,7 +273,8 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) s, _ := getServiceWithMockedLayers() assert.Nil(t, err) - _, err = s.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = s.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -306,7 +314,8 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { } - model, err := service.GetCurrentVersion(documentIdentifier) + ctxh := testingconfig.CreateTenantContext(t, cfg) + model, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.Nil(t, err) cd, err := model.PackCoreDocument() @@ -329,10 +338,11 @@ func TestService_GetVersion_successful(t *testing.T) { }, } + ctxh := testingconfig.CreateTenantContext(t, cfg) err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) - mod, err := service.GetVersion(documentIdentifier, currentVersion) + mod, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) cd, err := mod.PackCoreDocument() @@ -347,7 +357,8 @@ func TestService_GetCurrentVersion_error(t *testing.T) { documentIdentifier := utils.RandomSlice(32) //document is not existing - _, err := service.GetCurrentVersion(documentIdentifier) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) inv := &invoice.Invoice{ @@ -361,7 +372,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { err = testRepo().Create(tenantID, documentIdentifier, inv) assert.Nil(t, err) - _, err = service.GetCurrentVersion(documentIdentifier) + _, err = service.GetCurrentVersion(ctxh, documentIdentifier) assert.Nil(t, err) } @@ -373,7 +384,8 @@ func TestService_GetVersion_error(t *testing.T) { currentVersion := utils.RandomSlice(32) //document is not existing - _, err := service.GetVersion(documentIdentifier, currentVersion) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) inv := &invoice.Invoice{ @@ -387,11 +399,11 @@ func TestService_GetVersion_error(t *testing.T) { assert.Nil(t, err) //random version - _, err = service.GetVersion(documentIdentifier, utils.RandomSlice(32)) + _, err = service.GetVersion(ctxh, documentIdentifier, utils.RandomSlice(32)) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) //random document id - _, err = service.GetVersion(utils.RandomSlice(32), documentIdentifier) + _, err = service.GetVersion(ctxh, utils.RandomSlice(32), documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -410,9 +422,10 @@ func testRepo() documents.Repository { func TestService_Exists(t *testing.T) { service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) + ctxh := testingconfig.CreateTenantContext(t, cfg) //document is not existing - _, err := service.GetCurrentVersion(documentIdentifier) + _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) inv := &invoice.Invoice{ @@ -425,10 +438,10 @@ func TestService_Exists(t *testing.T) { err = testRepo().Create(tenantID, documentIdentifier, inv) - exists := service.Exists(documentIdentifier) + exists := service.Exists(ctxh, documentIdentifier) assert.True(t, exists, "document should exist") - exists = service.Exists(utils.RandomSlice(32)) + exists = service.Exists(ctxh, utils.RandomSlice(32)) assert.False(t, exists, "document should not exist") } diff --git a/documents/handler.go b/documents/handler.go index 3d7519122..eb75f9aeb 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -3,6 +3,8 @@ package documents import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -15,17 +17,22 @@ var apiLog = logging.Logger("document-api") // grpcHandler handles all the common document related actions: proof generation type grpcHandler struct { + config configstore.Service registry *ServiceRegistry } // GRPCHandler returns an implementation of documentpb.DocumentServiceServer -func GRPCHandler(registry *ServiceRegistry) documentpb.DocumentServiceServer { - return grpcHandler{registry: registry} +func GRPCHandler(config configstore.Service, registry *ServiceRegistry) documentpb.DocumentServiceServer { + return grpcHandler{config: config, registry: registry} } // CreateDocumentProof creates precise proofs for the given fields func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProofEnvelope *documentpb.CreateDocumentProofRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofEnvelope) + cctx, err := contextutil.CentContext(ctx, h.config) + if err != nil { + return &documentpb.DocumentProof{}, err + } service, err := h.registry.LocateService(createDocumentProofEnvelope.Type) if err != nil { @@ -37,7 +44,7 @@ func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProo return &documentpb.DocumentProof{}, centerrors.New(code.Unknown, err.Error()) } - proof, err := service.CreateProofs(identifier, createDocumentProofEnvelope.Fields) + proof, err := service.CreateProofs(cctx, identifier, createDocumentProofEnvelope.Fields) if err != nil { return &documentpb.DocumentProof{}, centerrors.New(code.Unknown, err.Error()) } @@ -47,6 +54,10 @@ func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProo // CreateDocumentProofForVersion creates precise proofs for the given fields for the given version of the document func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDocumentProofForVersionEnvelope *documentpb.CreateDocumentProofForVersionRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofForVersionEnvelope) + cctx, err := contextutil.CentContext(ctx, h.config) + if err != nil { + return &documentpb.DocumentProof{}, err + } service, err := h.registry.LocateService(createDocumentProofForVersionEnvelope.Type) if err != nil { @@ -63,7 +74,7 @@ func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDo return &documentpb.DocumentProof{}, centerrors.New(code.Unknown, err.Error()) } - proof, err := service.CreateProofsForVersion(identifier, version, createDocumentProofForVersionEnvelope.Fields) + proof, err := service.CreateProofsForVersion(cctx, identifier, version, createDocumentProofForVersionEnvelope.Fields) if err != nil { return &documentpb.DocumentProof{}, centerrors.New(code.Unknown, err.Error()) } diff --git a/documents/handler_test.go b/documents/handler_test.go index 1c346cbca..884cb190d 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -29,7 +29,7 @@ func TestGrpcHandler_CreateDocumentProof(t *testing.T) { id, _ := hexutil.Decode(req.Identifier) doc := &documents.DocumentProof{} service.On("CreateProofs", id, req.Fields).Return(doc, nil) - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) retDoc, _ := grpcHandler.CreateDocumentProof(context.TODO(), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) @@ -46,7 +46,7 @@ func TestGrpcHandler_CreateDocumentProofUnableToLocateService(t *testing.T) { Type: "wrongService", Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") @@ -62,7 +62,7 @@ func TestGrpcHandler_CreateDocumentProofInvalidHex(t *testing.T) { Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") @@ -83,7 +83,7 @@ func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { version, _ := hexutil.Decode(req.Version) doc := &documents.DocumentProof{DocumentID: utils.RandomSlice(32)} service.On("CreateProofsForVersion", id, version, req.Fields).Return(doc, nil) - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) retDoc, _ := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) @@ -101,7 +101,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionUnableToLocateService(t *testi Type: "wrongService", Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") @@ -118,7 +118,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForId(t *testing.T) Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") @@ -135,7 +135,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForVersion(t *testin Type: serviceName, Fields: []string{"field1"}, } - grpcHandler := documents.GRPCHandler(registry) + grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 11ff74aa8..0c287d4d0 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,7 +1,6 @@ package invoice import ( - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -19,11 +18,6 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(true, ctx) - if err != nil { - return err - } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("service registry not initialised") @@ -57,11 +51,10 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { // register service srv := DefaultService( - cfg, repo, anchorRepo, idService, queueSrv, txService) - err = registry.Register(documenttypes.InvoiceDataTypeUrl, srv) + err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return errors.New("failed to register invoice service: %v", err) } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index dcd391e9a..e32ddb612 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -1,16 +1,11 @@ package invoice import ( - "fmt" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" @@ -24,12 +19,11 @@ var apiLog = logging.Logger("invoice-api") // anchoring, sending, finding stored invoice document type grpcHandler struct { service Service - // TODO [multi-tenancy] replace this with config service - config config.Configuration + config configstore.Service } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { +func GRPCHandler(config configstore.Service, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) if err != nil { return nil, err @@ -44,26 +38,20 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", h.config) - if err != nil { - apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) + cctx, err := contextutil.CentContext(ctx, h.config) if err != nil { apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + return nil, err } - doc, err := h.service.DeriveFromCreatePayload(ctxHeader, req) + doc, err := h.service.DeriveFromCreatePayload(cctx, req) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not derive create payload") } // validate and persist - doc, txID, err := h.service.Create(ctxHeader, doc) + doc, txID, err := h.service.Create(cctx, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not create document") @@ -82,16 +70,10 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", h.config) + ctxHeader, err := contextutil.CentContext(ctx, h.config) if err != nil { apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) - if err != nil { - apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + return nil, err } doc, err := h.service.DeriveFromUpdatePayload(ctxHeader, payload) @@ -119,6 +101,12 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi // GetVersion returns the requested version of the document func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clientinvoicepb.GetVersionRequest) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Get version request %v", getVersionRequest) + ctxHeader, err := contextutil.CentContext(ctx, h.config) + if err != nil { + apiLog.Error(err) + return nil, err + } + identifier, err := hexutil.Decode(getVersionRequest.Identifier) if err != nil { apiLog.Error(err) @@ -131,7 +119,7 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti return nil, centerrors.Wrap(err, "version is invalid") } - model, err := h.service.GetVersion(identifier, version) + model, err := h.service.GetVersion(ctxHeader, identifier, version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") @@ -149,13 +137,19 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti // Get returns the invoice the latest version of the document with given identifier func (h *grpcHandler) Get(ctx context.Context, getRequest *clientinvoicepb.GetRequest) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Get request %v", getRequest) + ctxHeader, err := contextutil.CentContext(ctx, h.config) + if err != nil { + apiLog.Error(err) + return nil, err + } + identifier, err := hexutil.Decode(getRequest.Identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is an invalid hex string") } - model, err := h.service.GetCurrentVersion(identifier) + model, err := h.service.GetCurrentVersion(ctxHeader, identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index f84f2dca8..3f89c7458 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,8 +6,6 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -36,14 +34,14 @@ func (m *mockService) Create(ctx context.Context, inv documents.Model) (document return model, txID, args.Error(2) } -func (m *mockService) GetCurrentVersion(identifier []byte) (documents.Model, error) { - args := m.Called(identifier) +func (m *mockService) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { + args := m.Called(ctx, documentID) data, _ := args.Get(0).(documents.Model) return data, args.Error(1) } -func (m *mockService) GetVersion(identifier []byte, version []byte) (documents.Model, error) { - args := m.Called(identifier, version) +func (m *mockService) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { + args := m.Called(ctx, documentID, version) data, _ := args.Get(0).(documents.Model) return data, args.Error(1) } @@ -74,7 +72,7 @@ func (m *mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clie } func getHandler() *grpcHandler { - return &grpcHandler{service: &mockService{}, config: cfg} + return &grpcHandler{service: &mockService{}, config: configService} } func TestGRPCHandler_Create_derive_fail(t *testing.T) { @@ -161,7 +159,7 @@ func TestGrpcHandler_Get_invalid_input(t *testing.T) { assert.EqualError(t, err, "identifier is an invalid hex string: hex string without 0x prefix") payload.Identifier = identifier - srv.On("GetCurrentVersion", identifierBytes).Return(nil, errors.New("not found")) + srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(nil, errors.New("not found")) res, err = h.Get(context.Background(), payload) srv.AssertExpectations(t) assert.Nil(t, res) @@ -176,7 +174,7 @@ func TestGrpcHandler_Get(t *testing.T) { model := new(mockModel) payload := &clientinvoicepb.GetRequest{Identifier: identifier} response := &clientinvoicepb.InvoiceResponse{} - srv.On("GetCurrentVersion", identifierBytes).Return(model, nil) + srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(model, nil) srv.On("DeriveInvoiceResponse", model).Return(response, nil) res, err := h.Get(context.Background(), payload) model.AssertExpectations(t) @@ -201,7 +199,7 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { payload.Identifier = "0x01" mockErr := errors.New("not found") - srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(nil, mockErr) + srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(nil, mockErr) res, err = h.GetVersion(context.Background(), payload) srv.AssertExpectations(t) assert.EqualError(t, err, "document not found: not found") @@ -215,7 +213,7 @@ func TestGrpcHandler_GetVersion(t *testing.T) { payload := &clientinvoicepb.GetVersionRequest{Identifier: "0x01", Version: "0x00"} response := &clientinvoicepb.InvoiceResponse{} - srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(model, nil) + srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(model, nil) srv.On("DeriveInvoiceResponse", model).Return(response, nil) res, err := h.GetVersion(context.Background(), payload) model.AssertExpectations(t) @@ -242,10 +240,9 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh := testingconfig.CreateTenantContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() + srv.On("Update", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -258,10 +255,9 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh := testingconfig.CreateTenantContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(nil, errors.New("derive response error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) @@ -275,12 +271,11 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := context.Background() - ctxh := testingconfig.CreateTenantContext(t, cfg) txID := uuid.Must(uuid.NewV4()) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{Header: new(clientinvoicepb.ResponseHeader)} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, txID.String(), nil).Once() + srv.On("Update", mock.Anything, model).Return(model, txID.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(resp, nil).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 23851052d..12ae4b735 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -41,6 +41,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration +var configService configstore.Service func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -63,6 +64,8 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("identityId", cid.String()) + configService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 4eb24ba34..daefe71d4 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -9,8 +9,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/common" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto" @@ -56,8 +54,6 @@ type Service interface { // service implements Service and handles all invoice related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - // TODO [multi-tenancy] replace this with config service - config documents.Config repo documents.Repository notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -68,16 +64,14 @@ type service struct { // DefaultService returns the default implementation of the service. func DefaultService( - config config.Configuration, repo documents.Repository, anchorRepository anchors.AnchorRepository, identityService identity.Service, queueSrv queue.TaskQueuer, txService transactions.Service) Service { return service{ - config: config, repo: repo, - notifier: notification.NewWebhookSender(config), + notifier: notification.NewWebhookSender(), anchorRepository: anchorRepository, identityService: identityService, queueSrv: queueSrv, @@ -85,8 +79,8 @@ func DefaultService( } // CreateProofs creates proofs for the latest version document given the fields -func (s service) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(documentID) +func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -95,8 +89,8 @@ func (s service) CreateProofs(documentID []byte, fields []string) (*documents.Do } // CreateProofsForVersion creates proofs for a particular version of the document given the fields -func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetVersion(documentID, version) +func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.GetVersion(ctx, documentID, version) if err != nil { return nil, err } @@ -157,14 +151,19 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv } // calculateDataRoot validates the document, calculates the data root, and persists to DB -func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { +func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + inv, ok := new.(*Invoice) if !ok { return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields - err := inv.CalculateDataRoot() + err = inv.CalculateDataRoot() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -176,7 +175,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(common.DummyIdentity.Bytes(), inv.CoreDocument.CurrentVersion, inv) + err = s.repo.Create(self.ID[:], inv.CoreDocument.CurrentVersion, inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -186,7 +185,12 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents // Create takes and invoice model and does required validation checks, tries to persist to DB func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { - inv, err := s.calculateDataRoot(nil, inv, CreateValidator()) + self, err := contextutil.Self(ctx) + if err != nil { + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + inv, err = s.calculateDataRoot(ctx, nil, inv, CreateValidator()) if err != nil { return nil, uuid.Nil, err } @@ -199,7 +203,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod txID, err := documents.InitDocumentAnchorTask( s.queueSrv, s.txService, - common.DummyIdentity, + self.ID, cd.CurrentVersion) if err != nil { return nil, uuid.Nil, err @@ -210,17 +214,22 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod // Update finds the old document, validates the new version and persists the updated document func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + cd, err := inv.PackCoreDocument() if err != nil { return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - old, err := s.GetCurrentVersion(cd.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) if err != nil { return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - inv, err = s.calculateDataRoot(old, inv, UpdateValidator()) + inv, err = s.calculateDataRoot(ctx, old, inv, UpdateValidator()) if err != nil { return nil, uuid.Nil, err } @@ -228,7 +237,7 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod txID, err := documents.InitDocumentAnchorTask( s.queueSrv, s.txService, - common.DummyIdentity, + self.ID, cd.CurrentVersion) if err != nil { return nil, uuid.Nil, err @@ -238,8 +247,8 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod } // GetVersion returns an invoice for a given version -func (s service) GetVersion(documentID []byte, version []byte) (doc documents.Model, err error) { - inv, err := s.getInvoiceVersion(documentID, version) +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { + inv, err := s.getInvoiceVersion(ctx, documentID, version) if err != nil { return nil, err } @@ -247,14 +256,14 @@ func (s service) GetVersion(documentID []byte, version []byte) (doc documents.Mo } // GetCurrentVersion returns the last known version of an invoice -func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err error) { - inv, err := s.getInvoiceVersion(documentID, documentID) +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { + inv, err := s.getInvoiceVersion(ctx, documentID, documentID) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } nextVersion := inv.CoreDocument.NextVersion for nextVersion != nil { - temp, err := s.getInvoiceVersion(documentID, nextVersion) + temp, err := s.getInvoiceVersion(ctx, documentID, nextVersion) if err != nil { // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration return inv, nil @@ -266,8 +275,13 @@ func (s service) GetCurrentVersion(documentID []byte) (doc documents.Model, err return inv, nil } -func (s service) getInvoiceVersion(documentID, version []byte) (inv *Invoice, err error) { - doc, err := s.repo.Get(common.DummyIdentity.Bytes(), version) +func (s service) getInvoiceVersion(ctx context.Context, documentID, version []byte) (inv *Invoice, err error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + doc, err := s.repo.Get(self.ID[:], version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -338,7 +352,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, errors.New("failed to decode identifier: %v", err)) } - old, err := s.GetCurrentVersion(id) + old, err := s.GetCurrentVersion(ctx, id) if err != nil { return nil, err } @@ -372,6 +386,11 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv // RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -399,16 +418,15 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - tenantID := common.DummyIdentity.Bytes() // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) + if !s.repo.Exists(self.ID[:], doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(self.ID[:], doc.DocumentIdentifier, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } - err = s.repo.Create(tenantID, doc.CurrentVersion, model) + err = s.repo.Create(self.ID[:], doc.CurrentVersion, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -418,7 +436,12 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M } // ReceiveAnchoredDocument receives a new anchored document, validates and updates the document in DB -func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { + self, err := contextutil.Self(ctx) + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -428,7 +451,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) + err = s.repo.Update(self.ID[:], doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -443,12 +466,16 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C } // Async until we add queuing - go s.notifier.Send(notificationMsg) + go s.notifier.Send(ctx, notificationMsg) return nil } // Exists checks if an invoice exists -func (s service) Exists(documentID []byte) bool { - return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) +func (s service) Exists(ctx context.Context, documentID []byte) bool { + self, err := contextutil.Self(ctx) + if err != nil { + return false + } + return s.repo.Exists(self.ID[:], documentID) } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index be7aec0b7..2baab4de8 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -6,8 +6,6 @@ import ( "math/big" "testing" - "github.com/centrifuge/go-centrifuge/common" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/gocelery" @@ -32,8 +30,9 @@ import ( ) var ( - centIDBytes = utils.RandomSlice(identity.CentIDLength) - tenantID = common.DummyIdentity.Bytes() + cid = identity.RandomCentID() + centIDBytes = cid[:] + tenantID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -52,7 +51,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func TestDefaultService(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil).Once() - srv := DefaultService(c, testRepo(), nil, nil, nil, nil) + srv := DefaultService(testRepo(), nil, nil, nil, nil) assert.NotNil(t, srv, "must be non-nil") } @@ -64,7 +63,6 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) return idService, DefaultService( - c, testRepo(), &mockAnchorRepo{}, &idService, queueSrv, @@ -135,7 +133,8 @@ func TestService_GetLastVersion(t *testing.T) { doc, err := createMockDocument() assert.Nil(t, err) - mod1, err := invSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) + ctxh := testingconfig.CreateTenantContext(t, cfg) + mod1, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) invLoad1, _ := mod1.(*Invoice) @@ -153,7 +152,7 @@ func TestService_GetLastVersion(t *testing.T) { err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, inv2) assert.Nil(t, err) - mod2, err := invSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) + mod2, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) invLoad2, _ := mod2.(*Invoice) @@ -174,7 +173,8 @@ func TestService_GetVersion_invalid_version(t *testing.T) { err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) - mod, err := invSrv.GetVersion(utils.RandomSlice(32), currentVersion) + ctxh := testingconfig.CreateTenantContext(t, cfg) + mod, err := invSrv.GetVersion(ctxh, utils.RandomSlice(32), currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) assert.Nil(t, mod) } @@ -193,13 +193,14 @@ func TestService_GetVersion(t *testing.T) { err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) - mod, err := invSrv.GetVersion(documentIdentifier, currentVersion) + ctxh := testingconfig.CreateTenantContext(t, cfg) + mod, err := invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadInv, _ := mod.(*Invoice) assert.Equal(t, loadInv.CoreDocument.CurrentVersion, currentVersion) assert.Equal(t, loadInv.CoreDocument.DocumentIdentifier, documentIdentifier) - mod, err = invSrv.GetVersion(documentIdentifier, []byte{}) + mod, err = invSrv.GetVersion(ctxh, documentIdentifier, []byte{}) assert.Error(t, err) } @@ -216,10 +217,11 @@ func TestService_Exists(t *testing.T) { err := testRepo().Create(tenantID, documentIdentifier, inv) assert.Nil(t, err) - exists := invSrv.Exists(documentIdentifier) + ctxh := testingconfig.CreateTenantContext(t, cfg) + exists := invSrv.Exists(ctxh, documentIdentifier) assert.True(t, exists, "invoice should exist") - exists = invSrv.Exists(utils.RandomSlice(32)) + exists = invSrv.Exists(ctxh, utils.RandomSlice(32)) assert.False(t, exists, "invoice should not exist") } @@ -302,7 +304,8 @@ func TestService_CreateProofs(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) - proof, err := invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + proof, err := invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) @@ -318,7 +321,8 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) - _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -328,27 +332,30 @@ func TestService_CreateProofsInvalidField(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) - _, err = invSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, invService := getServiceWithMockedLayers() - _, err := invService.CreateProofs(utils.RandomSlice(32), []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err := invService.CreateProofs(ctxh, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) } func TestService_CreateProofsForVersion(t *testing.T) { idService, invSrv := getServiceWithMockedLayers() + ctxh := testingconfig.CreateTenantContext(t, cfg) i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, invSrv) olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - proof, err := invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) + proof, err := invSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) @@ -360,7 +367,8 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) _, invSrv := getServiceWithMockedLayers() assert.Nil(t, err) - _, err = invSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = invSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -627,7 +635,7 @@ func TestService_calculateDataRoot(t *testing.T) { ctxh := testingconfig.CreateTenantContext(t, cfg) // type mismatch - inv, err := invSrv.calculateDataRoot(nil, &testingdocuments.MockModel{}, nil) + inv, err := invSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -639,7 +647,7 @@ func TestService_calculateDataRoot(t *testing.T) { v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) - inv, err = invSrv.calculateDataRoot(nil, inv, v) + inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, v) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "validations fail") @@ -650,7 +658,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) err = invSrv.repo.Create(tenantID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) assert.Nil(t, err) - inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) + inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, CreateValidator()) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "db repository could not create the given model, key already exists") @@ -659,7 +667,7 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - inv, err = invSrv.calculateDataRoot(nil, inv, CreateValidator()) + inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, inv) assert.NotNil(t, inv.(*Invoice).CoreDocument.DataRoot) diff --git a/documents/model_test.go b/documents/model_test.go index b180e0a91..369db0bed 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -6,6 +6,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" @@ -15,17 +17,20 @@ import ( ) var ctx = map[string]interface{}{} +var ConfigService configstore.Service func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) + ConfigService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 3b2aaffe5..ce375c29e 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,7 +1,6 @@ package purchaseorder import ( - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -19,11 +18,6 @@ type Bootstrapper struct{} // Bootstrap initialises required services for purchaseorder. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(true, ctx) - if err != nil { - return err - } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("service registry not initialised") @@ -56,8 +50,8 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(cfg, repo, anchorRepo, idService, queueSrv, txService) - err = registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) + srv := DefaultService(repo, anchorRepo, idService, queueSrv, txService) + err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") } diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 30a6ad7ef..95b7c321c 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -1,16 +1,11 @@ package purchaseorder import ( - "fmt" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -25,12 +20,11 @@ var apiLog = logging.Logger("purchaseorder-api") // anchoring, sending, finding stored purchase order document type grpcHandler struct { service Service - // TODO [multi-tenancy] replace this with config service - config config.Configuration + config configstore.Service } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { +func GRPCHandler(config configstore.Service, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { return nil, errors.New("failed to fetch purchase order service") @@ -45,16 +39,10 @@ func GRPCHandler(config config.Configuration, registry *documents.ServiceRegistr // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", h.config) - if err != nil { - apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxh, err := contextutil.NewCentrifugeContext(ctx, tc) + ctxh, err := contextutil.CentContext(ctx, h.config) if err != nil { apiLog.Error(err) - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } doc, err := h.service.DeriveFromCreatePayload(ctxh, req) @@ -83,16 +71,10 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", h.config) - if err != nil { - apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) + ctxHeader, err := contextutil.CentContext(ctx, h.config) if err != nil { apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + return nil, err } doc, err := h.service.DeriveFromUpdatePayload(ctxHeader, payload) @@ -120,6 +102,12 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. // GetVersion returns the requested version of a purchase order func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb.GetVersionRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("GetVersion request %v", req) + ctxHeader, err := contextutil.CentContext(ctx, h.config) + if err != nil { + apiLog.Error(err) + return nil, err + } + identifier, err := hexutil.Decode(req.Identifier) if err != nil { apiLog.Error(err) @@ -132,7 +120,7 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. return nil, centerrors.Wrap(err, "version is invalid") } - model, err := h.service.GetVersion(identifier, version) + model, err := h.service.GetVersion(ctxHeader, identifier, version) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") @@ -150,13 +138,19 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. // Get returns the purchase order the latest version of the document with given identifier func (h grpcHandler) Get(ctx context.Context, getRequest *clientpurchaseorderpb.GetRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Get request %v", getRequest) + ctxHeader, err := contextutil.CentContext(ctx, h.config) + if err != nil { + apiLog.Error(err) + return nil, err + } + identifier, err := hexutil.Decode(getRequest.Identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "identifier is an invalid hex string") } - model, err := h.service.GetCurrentVersion(identifier) + model, err := h.service.GetCurrentVersion(ctxHeader, identifier) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "document not found") diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 552e48b30..12c8caf81 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,8 +6,6 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -44,14 +42,14 @@ func (m mockService) DeriveFromCreatePayload(ctx context.Context, payload *clien return model, args.Error(1) } -func (m mockService) GetCurrentVersion(identifier []byte) (documents.Model, error) { - args := m.Called(identifier) +func (m mockService) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { + args := m.Called(ctx, documentID) data, _ := args.Get(0).(documents.Model) return data, args.Error(1) } -func (m mockService) GetVersion(identifier []byte, version []byte) (documents.Model, error) { - args := m.Called(identifier, version) +func (m mockService) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { + args := m.Called(ctx, documentID, version) data, _ := args.Get(0).(documents.Model) return data, args.Error(1) } @@ -79,11 +77,10 @@ func TestGRPCHandler_Create(t *testing.T) { req := testingdocuments.CreatePOPayload() ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh := testingconfig.CreateTenantContext(t, cfg) // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromCreatePayload", ctxh, req).Return(nil, errors.New("derive failed")).Once() + srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Create(ctx, req) srv.AssertExpectations(t) @@ -92,8 +89,8 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() + srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Create", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -102,8 +99,8 @@ func TestGRPCHandler_Create(t *testing.T) { assert.Contains(t, err.Error(), "create failed") // derive response fails - srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Create", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -114,8 +111,8 @@ func TestGRPCHandler_Create(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} - srv.On("DeriveFromCreatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Create", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Create", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -134,11 +131,10 @@ func TestGrpcHandler_Update(t *testing.T) { } ctx := context.Background() model := &testingdocuments.MockModel{} - ctxh := testingconfig.CreateTenantContext(t, cfg) // derive fails srv := h.service.(*mockService) - srv.On("DeriveFromUpdatePayload", ctxh, req).Return(nil, errors.New("derive failed")).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(nil, errors.New("derive failed")).Once() h.service = srv resp, err := h.Update(ctx, req) srv.AssertExpectations(t) @@ -147,8 +143,8 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "derive failed") // create fails - srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(nil, uuid.Nil.String(), errors.New("update failed")).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Update", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -157,8 +153,8 @@ func TestGrpcHandler_Update(t *testing.T) { assert.Contains(t, err.Error(), "update failed") // derive response fails - srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -169,8 +165,8 @@ func TestGrpcHandler_Update(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} - srv.On("DeriveFromUpdatePayload", ctxh, req).Return(model, nil).Once() - srv.On("Update", ctxh, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() + srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -187,7 +183,7 @@ type mockModel struct { } func getHandler() *grpcHandler { - return &grpcHandler{service: &mockService{}, config: cfg} + return &grpcHandler{service: &mockService{}, config: configService} } func TestGrpcHandler_Get(t *testing.T) { @@ -198,7 +194,7 @@ func TestGrpcHandler_Get(t *testing.T) { model := new(mockModel) payload := &clientpopb.GetRequest{Identifier: identifier} response := &clientpopb.PurchaseOrderResponse{} - srv.On("GetCurrentVersion", identifierBytes).Return(model, nil) + srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(model, nil) srv.On("DerivePurchaseOrderResponse", model).Return(response, nil) res, err := h.Get(context.Background(), payload) model.AssertExpectations(t) @@ -223,7 +219,7 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { payload.Identifier = "0x01" mockErr := errors.New("not found") - srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(nil, mockErr) + srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(nil, mockErr) res, err = h.GetVersion(context.Background(), payload) srv.AssertExpectations(t) assert.EqualError(t, err, "document not found: not found") @@ -237,7 +233,7 @@ func TestGrpcHandler_GetVersion(t *testing.T) { payload := &clientpopb.GetVersionRequest{Identifier: "0x01", Version: "0x00"} response := &clientpopb.PurchaseOrderResponse{} - srv.On("GetVersion", []byte{0x01}, []byte{0x00}).Return(model, nil) + srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(model, nil) srv.On("DerivePurchaseOrderResponse", model).Return(response, nil) res, err := h.GetVersion(context.Background(), payload) model.AssertExpectations(t) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index a74909438..39db855cd 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -41,6 +41,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration +var configService configstore.Service func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -63,6 +64,8 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("identityId", cid.String()) + configService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index dc45ed6a8..8f89df22d 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -9,8 +9,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/common" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto" @@ -56,8 +54,6 @@ type Service interface { // service implements Service and handles all purchase order related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - // TODO [multi-tenancy] replace this with config service - config documents.Config repo documents.Repository notifier notification.Sender anchorRepository anchors.AnchorRepository @@ -68,16 +64,14 @@ type service struct { // DefaultService returns the default implementation of the service func DefaultService( - config config.Configuration, repo documents.Repository, anchorRepository anchors.AnchorRepository, identityService identity.Service, queueSrv queue.TaskQueuer, txService transactions.Service) Service { return service{ - config: config, repo: repo, - notifier: notification.NewWebhookSender(config), + notifier: notification.NewWebhookSender(), anchorRepository: anchorRepository, identityService: identityService, queueSrv: queueSrv, @@ -97,14 +91,19 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume } // calculateDataRoot validates the document, calculates the data root, and persists to DB -func (s service) calculateDataRoot(old, new documents.Model, validator documents.Validator) (documents.Model, error) { +func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + po, ok := new.(*PurchaseOrder) if !ok { return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } // create data root, has to be done at the model level to access fields - err := po.calculateDataRoot() + err = po.calculateDataRoot() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -116,7 +115,7 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(common.DummyIdentity.Bytes(), po.CoreDocument.CurrentVersion, po) + err = s.repo.Create(self.ID[:], po.CoreDocument.CurrentVersion, po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -126,7 +125,12 @@ func (s service) calculateDataRoot(old, new documents.Model, validator documents // Create validates, persists, and anchors a purchase order func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { - po, err := s.calculateDataRoot(nil, po, CreateValidator()) + self, err := contextutil.Self(ctx) + if err != nil { + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + + po, err = s.calculateDataRoot(ctx, nil, po, CreateValidator()) if err != nil { return nil, uuid.Nil, err } @@ -136,7 +140,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, common.DummyIdentity, cd.CurrentVersion) + txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, self.ID, cd.CurrentVersion) if err != nil { return nil, uuid.Nil, err } @@ -146,22 +150,27 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode // Update validates, persists, and anchors a new version of purchase order func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + cd, err := po.PackCoreDocument() if err != nil { return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - old, err := s.GetCurrentVersion(cd.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) if err != nil { return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - po, err = s.calculateDataRoot(old, po, UpdateValidator()) + po, err = s.calculateDataRoot(ctx, old, po, UpdateValidator()) if err != nil { return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, common.DummyIdentity, cd.CurrentVersion) + txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, self.ID, cd.CurrentVersion) if err != nil { return nil, uuid.Nil, err } @@ -201,7 +210,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpop return nil, errors.NewTypedError(documents.ErrDocumentIdentifier, errors.New("failed to decode identifier: %v", err)) } - old, err := s.GetCurrentVersion(id) + old, err := s.GetCurrentVersion(ctx, id) if err != nil { return nil, err } @@ -276,8 +285,12 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P }, nil } -func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *PurchaseOrder, err error) { - doc, err := s.repo.Get(common.DummyIdentity.Bytes(), version) +func (s service) getPurchaseOrderVersion(ctx context.Context, documentID, version []byte) (model *PurchaseOrder, err error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } + doc, err := s.repo.Get(self.ID[:], version) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) } @@ -293,14 +306,14 @@ func (s service) getPurchaseOrderVersion(documentID, version []byte) (model *Pur } // GetLastVersion returns the latest version of the document -func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { - model, err := s.getPurchaseOrderVersion(documentID, documentID) +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { + model, err := s.getPurchaseOrderVersion(ctx, documentID, documentID) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } nextVersion := model.CoreDocument.NextVersion for nextVersion != nil { - temp, err := s.getPurchaseOrderVersion(documentID, nextVersion) + temp, err := s.getPurchaseOrderVersion(ctx, documentID, nextVersion) if err != nil { // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration return model, nil @@ -313,8 +326,8 @@ func (s service) GetCurrentVersion(documentID []byte) (documents.Model, error) { } // GetVersion returns the specific version of the document -func (s service) GetVersion(documentID []byte, version []byte) (documents.Model, error) { - po, err := s.getPurchaseOrderVersion(documentID, version) +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { + po, err := s.getPurchaseOrderVersion(ctx, documentID, version) if err != nil { return nil, err } @@ -343,8 +356,8 @@ func (s service) purchaseOrderProof(model documents.Model, fields []string) (*do } // CreateProofs generates proofs for given document -func (s service) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(documentID) +func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -352,8 +365,8 @@ func (s service) CreateProofs(documentID []byte, fields []string) (*documents.Do } // CreateProofsForVersion generates proofs for specific version of the document -func (s service) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetVersion(documentID, version) +func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { + model, err := s.GetVersion(ctx, documentID, version) if err != nil { return nil, err } @@ -391,7 +404,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - tenantID := common.DummyIdentity.Bytes() + tenantID := idConf.ID[:] // Logic for receiving version n (n > 1) of the document for the first time if !s.repo.Exists(tenantID, cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { err = s.repo.Create(tenantID, cd.DocumentIdentifier, model) @@ -412,7 +425,11 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M // ReceiveAnchoredDocument validates the anchored document and updates it on DB // Note: this is document agnostic. But since we do not have a common implementation, adding it here. // will remove this once we have a common implementation for documents.Service -func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { + self, err := contextutil.Self(ctx) + if err != nil { + return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + } if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -422,7 +439,7 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - err = s.repo.Update(common.DummyIdentity.Bytes(), doc.CurrentVersion, model) + err = s.repo.Update(self.ID[:], doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -437,12 +454,16 @@ func (s service) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.C } // Async until we add queuing - go s.notifier.Send(notificationMsg) + go s.notifier.Send(ctx, notificationMsg) return nil } // Exists checks if an purchase order exists -func (s service) Exists(documentID []byte) bool { - return s.repo.Exists(common.DummyIdentity.Bytes(), documentID) +func (s service) Exists(ctx context.Context, documentID []byte) bool { + self, err := contextutil.Self(ctx) + if err != nil { + return false + } + return s.repo.Exists(self.ID[:], documentID) } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 311286b19..76440a960 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -10,7 +10,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -31,8 +30,9 @@ import ( ) var ( - tenantID = common.DummyIdentity.Bytes() - centIDBytes = utils.RandomSlice(identity.CentIDLength) + cid = identity.RandomCentID() + tenantID = cid[:] + centIDBytes = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -49,14 +49,12 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) idService := &testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) txService := ctx[transactions.BootstrappedService].(transactions.Service) - return idService, DefaultService(c, testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService) + return idService, DefaultService(testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService) } func TestService_Update(t *testing.T) { @@ -133,16 +131,17 @@ func TestService_Update(t *testing.T) { func TestService_DeriveFromUpdatePayload(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + poSrv := service{repo: testRepo()} + ctxh := testingconfig.CreateTenantContext(t, cfg) // nil payload - doc, err := poSrv.DeriveFromUpdatePayload(nil, nil) + doc, err := poSrv.DeriveFromUpdatePayload(ctxh, nil) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) // nil payload data - doc, err = poSrv.DeriveFromUpdatePayload(nil, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{}) + doc, err = poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) assert.Nil(t, doc) @@ -372,7 +371,8 @@ func TestService_CreateProofs(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) - proof, err := poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + proof, err := poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) @@ -388,7 +388,8 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) - _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -398,14 +399,16 @@ func TestService_CreateProofsInvalidField(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, poSrv) - _, err = poSrv.CreateProofs(i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { _, poSrv := getServiceWithMockedLayers() - _, err := poSrv.CreateProofs(utils.RandomSlice(32), []string{"po.po_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err := poSrv.CreateProofs(ctxh, utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) } @@ -447,6 +450,7 @@ func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseO } func TestService_CreateProofsForVersion(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) idService, poSrv := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) @@ -454,7 +458,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - proof, err := poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po.po_number"}) + proof, err := poSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po.po_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) @@ -466,7 +470,8 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) _, poSrv := getServiceWithMockedLayers() assert.Nil(t, err) - _, err = poSrv.CreateProofsForVersion(i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po.po_number"}) + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = poSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po.po_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -531,7 +536,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { r, err = poSrv.DerivePurchaseOrderResponse(po) assert.Nil(t, err) assert.Equal(t, payload.Data, r.Data) - assert.Equal(t, []string{"0x010101010101", "0x010101010101"}, r.Header.Collaborators) + assert.Equal(t, []string{cid.String(), "0x010101010101"}, r.Header.Collaborators) } func createMockDocument() (*PurchaseOrder, error) { @@ -554,12 +559,13 @@ func createMockDocument() (*PurchaseOrder, error) { func TestService_GetCurrentVersion(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + poSrv := service{repo: testRepo()} thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) - mod1, err := poSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) + mod1, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) poLoad1, _ := mod1.(*PurchaseOrder) @@ -577,7 +583,7 @@ func TestService_GetCurrentVersion(t *testing.T) { err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, po2) assert.Nil(t, err) - mod2, err := poSrv.GetCurrentVersion(doc.CoreDocument.DocumentIdentifier) + mod2, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) poLoad2, _ := mod2.(*PurchaseOrder) @@ -588,7 +594,7 @@ func TestService_GetCurrentVersion(t *testing.T) { func TestService_GetVersion_invalid_version(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + poSrv := service{repo: testRepo()} currentVersion := utils.RandomSlice(32) po := &PurchaseOrder{ @@ -600,8 +606,9 @@ func TestService_GetVersion_invalid_version(t *testing.T) { } err := testRepo().Create(tenantID, currentVersion, po) assert.Nil(t, err) + ctxh := testingconfig.CreateTenantContext(t, cfg) - mod, err := poSrv.GetVersion(utils.RandomSlice(32), currentVersion) + mod, err := poSrv.GetVersion(ctxh, utils.RandomSlice(32), currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) assert.Nil(t, mod) } @@ -609,7 +616,7 @@ func TestService_GetVersion_invalid_version(t *testing.T) { func TestService_GetVersion(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + poSrv := service{repo: testRepo()} documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) @@ -623,13 +630,14 @@ func TestService_GetVersion(t *testing.T) { err := testRepo().Create(tenantID, currentVersion, po) assert.Nil(t, err) - mod, err := poSrv.GetVersion(documentIdentifier, currentVersion) + ctxh := testingconfig.CreateTenantContext(t, cfg) + mod, err := poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadpo, _ := mod.(*PurchaseOrder) assert.Equal(t, loadpo.CoreDocument.CurrentVersion, currentVersion) assert.Equal(t, loadpo.CoreDocument.DocumentIdentifier, documentIdentifier) - mod, err = poSrv.GetVersion(documentIdentifier, []byte{}) + mod, err = poSrv.GetVersion(ctxh, documentIdentifier, []byte{}) assert.Error(t, err) } @@ -646,17 +654,19 @@ func TestService_Exists(t *testing.T) { err := testRepo().Create(tenantID, documentIdentifier, po) assert.Nil(t, err) - exists := poSrv.Exists(documentIdentifier) + ctxh := testingconfig.CreateTenantContext(t, cfg) + exists := poSrv.Exists(ctxh, documentIdentifier) assert.True(t, exists, "purchase order should exist") - exists = poSrv.Exists(utils.RandomSlice(32)) + exists = poSrv.Exists(ctxh, utils.RandomSlice(32)) assert.False(t, exists, "purchase order should not exist") } func TestService_ReceiveAnchoredDocument(t *testing.T) { poSrv := service{} - err := poSrv.ReceiveAnchoredDocument(nil, nil) + ctxh := testingconfig.CreateTenantContext(t, cfg) + err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } @@ -670,11 +680,11 @@ func TestService_RequestDocumentSignature(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{config: c, repo: testRepo()} + poSrv := service{repo: testRepo()} ctxh := testingconfig.CreateTenantContext(t, cfg) // type mismatch - po, err := poSrv.calculateDataRoot(nil, &testingdocuments.MockModel{}, nil) + po, err := poSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -686,7 +696,7 @@ func TestService_calculateDataRoot(t *testing.T) { v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) - po, err = poSrv.calculateDataRoot(nil, po, v) + po, err = poSrv.calculateDataRoot(ctxh, nil, po, v) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), "validations fail") @@ -697,7 +707,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) err = poSrv.repo.Create(tenantID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) assert.Nil(t, err) - po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) + po, err = poSrv.calculateDataRoot(ctxh, nil, po, CreateValidator()) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists) @@ -706,7 +716,7 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - po, err = poSrv.calculateDataRoot(nil, po, CreateValidator()) + po, err = poSrv.calculateDataRoot(ctxh, nil, po, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, po) assert.NotNil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) diff --git a/documents/registry.go b/documents/registry.go index 49848237d..1ef2060ae 100644 --- a/documents/registry.go +++ b/documents/registry.go @@ -1,6 +1,7 @@ package documents import ( + "context" "sync" "github.com/centrifuge/go-centrifuge/errors" @@ -23,6 +24,7 @@ func NewServiceRegistry() *ServiceRegistry { func (s *ServiceRegistry) Register(serviceID string, service Service) error { s.mutex.Lock() defer s.mutex.Unlock() + if _, ok := s.services[serviceID]; ok { return errors.New("service with provided id already registered") } @@ -35,27 +37,23 @@ func (s *ServiceRegistry) Register(serviceID string, service Service) error { func (s *ServiceRegistry) LocateService(serviceID string) (Service, error) { s.mutex.RLock() defer s.mutex.RUnlock() + if s.services[serviceID] == nil { return nil, errors.New("no service for core document type is registered") } - return s.services[serviceID], nil } // FindService will search the service based on the documentID -func (s *ServiceRegistry) FindService(documentID []byte) (Service, error) { +func (s *ServiceRegistry) FindService(ctx context.Context, documentID []byte) (Service, error) { s.mutex.RLock() defer s.mutex.RUnlock() for _, service := range s.services { - - exists := service.Exists(documentID) - + exists := service.Exists(ctx, documentID) if exists { return service, nil } - } return nil, errors.New("no service exists for provided documentID") - } diff --git a/documents/registry_test.go b/documents/registry_test.go index 5501b5154..d9abab538 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -21,7 +21,7 @@ func TestServiceRegistry_FindService(t *testing.T) { err := registry.Register("a service", a) err = registry.Register("b service", b) - service, err := registry.FindService([]byte{}) + service, err := registry.FindService(nil, []byte{}) assert.Nil(t, err, "findService should be successful") assert.Equal(t, a, service, "service a should be returned") } diff --git a/documents/service.go b/documents/service.go index 954500f0c..c2abd782c 100644 --- a/documents/service.go +++ b/documents/service.go @@ -8,13 +8,6 @@ import ( "github.com/centrifuge/precise-proofs/proofs/proto" ) -// Config specified configs required by documents package -type Config interface { - - // GetIdentityID retrieves the centID(TenentID) configured - GetIdentityID() ([]byte, error) -} - // DocumentProof is a value to represent a document and its field proofs type DocumentProof struct { DocumentID []byte @@ -27,26 +20,26 @@ type DocumentProof struct { type Service interface { // GetCurrentVersion reads a document from the database - GetCurrentVersion(documentID []byte) (Model, error) + GetCurrentVersion(ctx context.Context, documentID []byte) (Model, error) // Exists checks if a document exists - Exists(documentID []byte) bool + Exists(ctx context.Context, documentID []byte) bool // GetVersion reads a document from the database - GetVersion(documentID []byte, version []byte) (Model, error) + GetVersion(ctx context.Context, documentID []byte, version []byte) (Model, error) // DeriveFromCoreDocument derives a model given the core document DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) // CreateProofs creates proofs for the latest version document given the fields - CreateProofs(documentID []byte, fields []string) (*DocumentProof, error) + CreateProofs(ctx context.Context, documentID []byte, fields []string) (*DocumentProof, error) // CreateProofsForVersion creates proofs for a particular version of the document given the fields - CreateProofsForVersion(documentID, version []byte, fields []string) (*DocumentProof, error) + CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*DocumentProof, error) // RequestDocumentSignature Validates and Signs document received over the p2p layer RequestDocumentSignature(ctx context.Context, model Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB - ReceiveAnchoredDocument(model Model, headers *p2ppb.CentrifugeHeader) error + ReceiveAnchoredDocument(ctx context.Context, model Model, headers *p2ppb.CentrifugeHeader) error } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index f9114299c..b238e8076 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -57,7 +57,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { registry, idService, client, - cfg, queueSrv, + queueSrv, bindContract, txService, func() (uint64, error) { h, err := client.GetEthClient().HeaderByNumber(context.Background(), nil) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index f38b052f6..b0d3f7bd1 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -1,13 +1,12 @@ package nft import ( + "context" "encoding/hex" "math/big" - "time" - - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -25,14 +24,6 @@ import ( var log = logging.Logger("nft") -// Config is an interface to configurations required by nft package -type Config interface { - GetIdentityID() ([]byte, error) - GetEthereumDefaultAccountName() string - GetContractAddress(address config.ContractName) common.Address - GetEthereumContextWaitTimeout() time.Duration -} - // ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out type ethereumPaymentObligationContract interface { @@ -45,9 +36,6 @@ type ethereumPaymentObligation struct { registry *documents.ServiceRegistry identityService identity.Service ethClient ethereum.Client - - // TODO [multi-tenancy] replace this with config service - config Config queue queue.TaskQueuer bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) txService transactions.Service @@ -59,7 +47,6 @@ func newEthereumPaymentObligation( registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, - config Config, queue queue.TaskQueuer, bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error), txService transactions.Service, @@ -68,7 +55,6 @@ func newEthereumPaymentObligation( registry: registry, identityService: identityService, ethClient: ethClient, - config: config, bindContract: bindContract, queue: queue, txService: txService, @@ -76,13 +62,13 @@ func newEthereumPaymentObligation( } } -func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { - docService, err := s.registry.FindService(documentID) +func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { + docService, err := s.registry.FindService(ctx, documentID) if err != nil { return nil, err } - model, err := docService.GetCurrentVersion(documentID) + model, err := docService.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -92,7 +78,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, deposi return nil, err } - proofs, err := docService.CreateProofs(documentID, proofFields) + proofs, err := docService.CreateProofs(ctx, documentID, proofFields) if err != nil { return nil, err } @@ -119,14 +105,18 @@ func (s *ethereumPaymentObligation) prepareMintRequest(documentID []byte, deposi } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { +func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { + tc, err := contextutil.Tenant(ctx) + if err != nil { + return nil, err + } - requestData, err := s.prepareMintRequest(documentID, depositAddress, proofFields) + requestData, err := s.prepareMintRequest(ctx, documentID, depositAddress, proofFields) if err != nil { return nil, errors.New("failed to prepare mint request: %v", err) } - opts, err := s.ethClient.GetTxOpts(s.config.GetEthereumDefaultAccountName()) + opts, err := s.ethClient.GetTxOpts(tc.EthereumDefaultAccountName) if err != nil { return nil, err } @@ -136,7 +126,12 @@ func (s *ethereumPaymentObligation) MintNFT(tenantID common.Address, documentID return nil, err } - txID, err := s.queueTask(tenantID, requestData.TokenID, registryAddress) + cid, err := identity.ToCentID(tc.IdentityID) + if err != nil { + return nil, err + } + + txID, err := s.queueTask(cid, requestData.TokenID, registryAddress) if err != nil { return nil, errors.New("failed to queue task: %v", err) } @@ -152,7 +147,7 @@ func (s *ethereumPaymentObligation) MintNFT(tenantID common.Address, documentID }, nil } -func (s *ethereumPaymentObligation) queueTask(tenantID common.Address, tokenID *big.Int, registryAddress string) (txID uuid.UUID, err error) { +func (s *ethereumPaymentObligation) queueTask(tenantID identity.CentID, tokenID *big.Int, registryAddress string) (txID uuid.UUID, err error) { height, err := s.blockHeightFunc() if err != nil { return txID, err @@ -186,24 +181,6 @@ func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPayment return nil } -func (s *ethereumPaymentObligation) getIdentityAddress() (common.Address, error) { - centIDBytes, err := s.config.GetIdentityID() - if err != nil { - return common.Address{}, err - } - - centID, err := identity.ToCentID(centIDBytes) - if err != nil { - return common.Address{}, err - } - - address, err := s.identityService.GetIdentityAddress(centID) - if err != nil { - return common.Address{}, err - } - return address, nil -} - // MintRequest holds the data needed to mint and NFT from a Centrifuge document type MintRequest struct { diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 8509ccc19..629c5dfba 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -6,6 +6,10 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/config" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -163,6 +167,12 @@ func TestPaymentObligationService(t *testing.T) { ).Return(&types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") + cid := identity.RandomCentID() + configMock.On("GetIdentityID").Return(cid[:], nil) + configMock.On("GetEthereumAccount").Return(&config.AccountConfig{}, nil) + configMock.On("GetReceiveEventNotificationEndpoint").Return("") + configMock.On("GetSigningKeyPair").Return("", "") + configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv @@ -182,11 +192,11 @@ func TestPaymentObligationService(t *testing.T) { docService, paymentOb, idService, ethClient, mockCfg, queueSrv := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) - service := newEthereumPaymentObligation(registry, &idService, ðClient, &mockCfg, queueSrv, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + service := newEthereumPaymentObligation(registry, &idService, ðClient, queueSrv, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil }, txService, func() (uint64, error) { return 10, nil }) - tenantID := common.Address([20]byte{1, 2}) - _, err := service.MintNFT(tenantID, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + ctxh := testingconfig.CreateTenantContext(t, &mockCfg) + _, err := service.MintNFT(ctxh, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { diff --git a/nft/handler.go b/nft/handler.go index 87ad6d388..ed23091b1 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -3,9 +3,12 @@ package nft import ( "context" + "github.com/centrifuge/go-centrifuge/contextutil" + + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -15,19 +18,25 @@ import ( var apiLog = logging.Logger("nft-api") type grpcHandler struct { + config configstore.Service service PaymentObligation } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(payOb PaymentObligation) nftpb.NFTServiceServer { - return &grpcHandler{service: payOb} +func GRPCHandler(config configstore.Service, payOb PaymentObligation) nftpb.NFTServiceServer { + return &grpcHandler{config: config, service: payOb} } // MintNFT will be called from the client API to mint an NFT -func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { +func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { apiLog.Infof("Received request to Mint an NFT with %s with proof fields %s", request.Identifier, request.ProofFields) + ctxHeader, err := contextutil.CentContext(ctx, g.config) + if err != nil { + apiLog.Error(err) + return nil, err + } - err := validateParameters(request) + err = validateParameters(request) if err != nil { return nil, err } @@ -36,8 +45,7 @@ func (g grpcHandler) MintNFT(context context.Context, request *nftpb.NFTMintRequ return nil, centerrors.New(code.Unknown, err.Error()) } - tenantID := ccommon.DummyIdentity - resp, err := g.service.MintNFT(tenantID, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) + resp, err := g.service.MintNFT(ctxHeader, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } diff --git a/nft/handler_test.go b/nft/handler_test.go index 8da9bd7c6..4b2afcb49 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -7,10 +7,10 @@ import ( "math/big" "testing" - ccommon "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -20,8 +20,8 @@ type mockPaymentObligationService struct { mock.Mock } -func (m *mockPaymentObligationService) MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { - args := m.Called(tenantID, documentID, registryAddress, depositAddress, proofFields) +func (m *mockPaymentObligationService) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { + args := m.Called(ctx, documentID, registryAddress, depositAddress, proofFields) resp, _ := args.Get(0).(*MintNFTResponse) return resp, args.Error(1) } @@ -29,25 +29,34 @@ func (m *mockPaymentObligationService) MintNFT(tenantID common.Address, document func TestNFTMint_success(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &mockPaymentObligationService{} + mockConfigStore := mockConfigService() docID, _ := hexutil.Decode(nftMintRequest.Identifier) tokID := big.NewInt(1) nftResponse := &MintNFTResponse{TokenID: tokID.String()} mockService. - On("MintNFT", ccommon.DummyIdentity, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + On("MintNFT", mock.Anything, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(nftResponse, nil) - handler := grpcHandler{mockService} + handler := grpcHandler{mockConfigStore, mockService} nftMintResponse, err := handler.MintNFT(context.Background(), nftMintRequest) mockService.AssertExpectations(t) assert.Nil(t, err, "mint nft should be successful") assert.Equal(t, tokID.String(), nftMintResponse.TokenId, "TokenID should have a dummy value") } +func mockConfigService() *configstore.MockService { + mockConfigStore := &configstore.MockService{} + mockConfigStore.On("GetAllTenants").Return([]*configstore.TenantConfig{&configstore.TenantConfig{}}, nil) + return mockConfigStore +} + func TestNFTMint_InvalidIdentifier(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.Identifier = "32321" - handler := grpcHandler{&mockPaymentObligationService{}} + mockConfigStore := mockConfigService() + mockConfigStore.On("GetAllTenants").Return(context.Background()) + handler := grpcHandler{mockConfigStore, &mockPaymentObligationService{}} _, err := handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid identifier should throw an error") } @@ -57,10 +66,11 @@ func TestNFTMint_ServiceError(t *testing.T) { mockService := &mockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) mockService. - On("MintNFT", ccommon.DummyIdentity, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). + On("MintNFT", mock.Anything, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(nil, errors.New("service error")) - handler := grpcHandler{mockService} + mockConfigStore := mockConfigService() + handler := grpcHandler{mockConfigStore, mockService} _, err := handler.MintNFT(context.Background(), nftMintRequest) mockService.AssertExpectations(t) assert.NotNil(t, err) @@ -69,13 +79,14 @@ func TestNFTMint_ServiceError(t *testing.T) { func TestNFTMint_InvalidAddresses(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.RegistryAddress = "0x1234" - handler := grpcHandler{&mockPaymentObligationService{}} + mockConfigStore := mockConfigService() + handler := grpcHandler{mockConfigStore, &mockPaymentObligationService{}} _, err := handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid registry address should throw an error") nftMintRequest = getTestSetupData() nftMintRequest.DepositAddress = "abc" - handler = grpcHandler{&mockPaymentObligationService{}} + handler = grpcHandler{mockConfigStore, &mockPaymentObligationService{}} _, err = handler.MintNFT(context.Background(), nftMintRequest) assert.Error(t, err, "invalid deposit address should throw an error") } diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 9bba7b775..8f927c5cf 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -34,7 +36,7 @@ type mintingConfirmationTask struct { transactions.BaseTask //task parameter - tenantID common.Address + tenantID identity.CentID tokenID string blockHeight uint64 registryAddress string @@ -82,7 +84,10 @@ func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) return errors.New("missing tenant ID") } - nftc.tenantID = common.HexToAddress(tenantID) + nftc.tenantID, err = identity.CentIDFromString(tenantID) + if err != nil { + return err + } // parse TokenID tokenID, ok := kwargs[tokenIDParam] diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go index b8996b3c5..cd740b4e5 100644 --- a/nft/minting_confirmation_task_test.go +++ b/nft/minting_confirmation_task_test.go @@ -6,7 +6,8 @@ import ( "encoding/hex" "testing" - "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" @@ -20,10 +21,11 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { blockHeight := uint64(12) registryAddress := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" txID := uuid.Must(uuid.NewV4()).String() + cid := identity.RandomCentID() kwargs := map[string]interface{}{ transactions.TxIDParam: txID, - tenantIDParam: common.DummyIdentity.String(), + tenantIDParam: cid.String(), tokenIDParam: tokenId, queue.BlockHeightParam: blockHeight, registryAddressParam: registryAddress, @@ -34,7 +36,7 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { err = task.ParseKwargs(decoded) assert.Nil(t, err, "parsing should be successful") - assert.Equal(t, common.DummyIdentity, task.tenantID) + assert.Equal(t, cid, task.tenantID) assert.Equal(t, txID, task.TxID.String()) assert.Equal(t, tokenId, task.tokenID, "tokenId should be parsed correctly") assert.Equal(t, blockHeight, task.blockHeight, "blockHeight should be parsed correctly") diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index a6e731f30..165b9ea9b 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -1,12 +1,14 @@ package nft -import "github.com/ethereum/go-ethereum/common" +import ( + "context" +) // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(tenantID common.Address, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) + MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) } // MintNFTResponse holds tokenID and transaction ID. diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index c451c2daa..619855ff3 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -13,7 +13,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" - ccommon "github.com/centrifuge/go-centrifuge/common" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -49,7 +48,7 @@ func TestMain(m *testing.M) { func TestPaymentObligationService_mint(t *testing.T) { // create identity log.Debug("Create Identity for Testing") - testingidentity.CreateIdentityWithKeys(cfg, idService) + cid := testingidentity.CreateIdentityWithKeys(cfg, idService) // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) @@ -69,7 +68,7 @@ func TestPaymentObligationService_mint(t *testing.T) { }) assert.Nil(t, err, "should not error out when creating invoice model") modelUpdated, txID, err := invoiceService.Create(contextHeader, model) - err = txService.WaitForTransaction(ccommon.DummyIdentity, txID) + err = txService.WaitForTransaction(cid, txID) assert.Nil(t, err) // get ID @@ -78,7 +77,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // call mint // assert no error resp, err := payOb.MintNFT( - ccommon.DummyIdentity, + contextHeader, ID, cfg.GetContractAddress(config.PaymentObligation).String(), "0xf72855759a39fb75fc7341139f5d7a3974d4da08", diff --git a/notification/notification.go b/notification/notification.go index 0653d75b5..9a44c7a72 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -1,9 +1,12 @@ package notification import ( + "context" "encoding/json" "net/http" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" @@ -25,31 +28,28 @@ const ( Success Status = 1 ) -// Config defines methods required for this package. -type Config interface { - GetReceiveEventNotificationEndpoint() string -} - // Sender defines methods that can handle a notification. type Sender interface { - Send(notification *notificationpb.NotificationMessage) (Status, error) + Send(ctx context.Context, notification *notificationpb.NotificationMessage) (Status, error) } // NewWebhookSender returns an implementation of a Sender that sends notifications through webhooks. -func NewWebhookSender(config Config) Sender { - return webhookSender{config} +func NewWebhookSender() Sender { + return webhookSender{} } // NewWebhookSender implements Sender. // Sends notification through a webhook defined. type webhookSender struct { - // TODO [multi-tenancy] replace this with config service - config Config } // Send sends notification to the defined webhook. -func (wh webhookSender) Send(notification *notificationpb.NotificationMessage) (Status, error) { - url := wh.config.GetReceiveEventNotificationEndpoint() +func (wh webhookSender) Send(ctx context.Context, notification *notificationpb.NotificationMessage) (Status, error) { + tc, err := contextutil.Tenant(ctx) + if err != nil { + return Failure, err + } + url := tc.ReceiveEventNotificationEndpoint if url == "" { log.Warningf("Webhook URL not defined, manually fetch received document") return Success, nil diff --git a/notification/notification_test.go b/notification/notification_test.go index b0000924b..262b2fc14 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -23,12 +25,16 @@ import ( "github.com/stretchr/testify/assert" ) +var cfg config.Configuration + func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, } - bootstrap.RunTestBootstrappers(ibootstappers, nil) + ctx := make(map[string]interface{}) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -74,7 +80,7 @@ func TestWebhookSender_Send(t *testing.T) { go server.ListenAndServe() defer server.Close() - wb := NewWebhookSender(mockConfig{url: "http://localhost:8090/webhook"}) + wb := NewWebhookSender() notif := ¬ificationpb.NotificationMessage{ DocumentId: hexutil.Encode(docID), DocumentType: documenttypes.InvoiceDataTypeUrl, @@ -83,7 +89,8 @@ func TestWebhookSender_Send(t *testing.T) { Recorded: ts, } - status, err := wb.Send(notif) + cfg.Set("notifications.endpoint", "http://localhost:8090/webhook") + status, err := wb.Send(testingconfig.CreateTenantContext(t, cfg), notif) assert.NoError(t, err) assert.Equal(t, status, Success) wg.Wait() diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 5453acfbe..9c37ee8ef 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -23,8 +23,10 @@ func TestBootstrapper_Bootstrap(t *testing.T) { assert.Error(t, err) // config + cs := new(configstore.MockService) m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) - m[configstore.BootstrappedConfigStorage] = new(configstore.MockService) + m[configstore.BootstrappedConfigStorage] = cs + cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/client.go b/p2p/client.go index ddca7f0a0..c4d828331 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -42,6 +42,8 @@ func (s *p2pServer) SendAnchoredDocument(ctx context.Context, id identity.Identi if err != nil { return nil, err } + + // TODO [multi-tenancy] modify the protocol id here to include the centID of the receiving node recv, err := s.mes.sendMessage(ctx, pid, &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, CentrifugeProtocol) if err != nil { return nil, err diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 07f196348..89b6605ed 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -140,7 +140,18 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { - err := handshakeValidator(srv.config.GetNetworkID()).Validate(docReq.Header) + // TODO [multi-tenancy] remove following and read the config from the context + tc, err := configstore.NewTenantConfig("", srv.config) + if err != nil { + log.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) + if err != nil { + log.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + err = handshakeValidator(srv.config.GetNetworkID()).Validate(docReq.Header) if err != nil { return nil, err } @@ -150,7 +161,7 @@ func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.Anch return nil, centerrors.New(code.DocumentInvalid, err.Error()) } - err = svc.ReceiveAnchoredDocument(model, docReq.Header) + err = svc.ReceiveAnchoredDocument(ctxHeader, model, docReq.Header) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 23c7a3df9..99e846ee6 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -15,22 +15,22 @@ type MockService struct { mock.Mock } -func (m *MockService) GetCurrentVersion(documentID []byte) (documents.Model, error) { +func (m *MockService) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { args := m.Called(documentID) return args.Get(0).(documents.Model), args.Error(1) } -func (m *MockService) GetVersion(documentID []byte, version []byte) (documents.Model, error) { +func (m *MockService) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { args := m.Called(documentID, version) return args.Get(0).(documents.Model), args.Error(1) } -func (m *MockService) CreateProofs(documentID []byte, fields []string) (*documents.DocumentProof, error) { +func (m *MockService) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { args := m.Called(documentID, fields) return args.Get(0).(*documents.DocumentProof), args.Error(1) } -func (m *MockService) CreateProofsForVersion(documentID, version []byte, fields []string) (*documents.DocumentProof, error) { +func (m *MockService) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { args := m.Called(documentID, version, fields) return args.Get(0).(*documents.DocumentProof), args.Error(1) } @@ -45,12 +45,12 @@ func (m *MockService) RequestDocumentSignature(ctx context.Context, model docume return args.Get(0).(*coredocumentpb.Signature), args.Error(1) } -func (m *MockService) ReceiveAnchoredDocument(model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (m *MockService) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { args := m.Called() return args.Error(0) } -func (m *MockService) Exists(documentID []byte) bool { +func (m *MockService) Exists(ctx context.Context, documentID []byte) bool { args := m.Called() return args.Get(0).(bool) } diff --git a/transactions/base_task.go b/transactions/base_task.go index 02d4050b8..cdfb71e00 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -2,7 +2,7 @@ package transactions import ( "github.com/centrifuge/go-centrifuge/errors" - "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/identity" "github.com/satori/go.uuid" ) @@ -35,7 +35,7 @@ func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { } // UpdateTransaction add a new log and updates the status of the transaction based on the error. -func (b *BaseTask) UpdateTransaction(tenantID common.Address, name string, err error) error { +func (b *BaseTask) UpdateTransaction(tenantID identity.CentID, name string, err error) error { tx, erri := b.TxService.GetTransaction(tenantID, b.TxID) if erri != nil { return errors.AppendError(err, erri) diff --git a/transactions/base_task_test.go b/transactions/base_task_test.go index 84f21788b..a804644de 100644 --- a/transactions/base_task_test.go +++ b/transactions/base_task_test.go @@ -5,7 +5,8 @@ package transactions import ( "testing" - "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/satori/go.uuid" @@ -15,7 +16,7 @@ import ( func TestDocumentAnchorTask_updateTransaction(t *testing.T) { task := new(BaseTask) - tenantID := common.DummyIdentity + tenantID := identity.RandomCentID() name := "some task" task.TxID = uuid.Must(uuid.NewV4()) task.TxService = NewService(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) diff --git a/transactions/handler.go b/transactions/handler.go index 8f750109e..3d2d85287 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -3,7 +3,9 @@ package transactions import ( "context" - "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/satori/go.uuid" @@ -12,23 +14,36 @@ import ( // ErrInvalidTransactionID error for Invalid transaction ID. const ErrInvalidTransactionID = errors.Error("Invalid Transaction ID") +// ErrInvalidTenantID error for Invalid tenant ID. +const ErrInvalidTenantID = errors.Error("Invalid Tenant ID") + // GRPCHandler returns an implementation of the TransactionServiceServer -func GRPCHandler(srv Service) transactionspb.TransactionServiceServer { - return grpcHandler{srv: srv} +func GRPCHandler(srv Service, configService configstore.Service) transactionspb.TransactionServiceServer { + return grpcHandler{srv: srv, configService: configService} } // grpcHandler implements transactionspb.TransactionServiceServer type grpcHandler struct { - srv Service + srv Service + configService configstore.Service } // GetTransactionStatus returns transaction status of the given transaction id. func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactionspb.TransactionStatusRequest) (*transactionspb.TransactionStatusResponse, error) { - identity := common.DummyIdentity + // TODO [multi-tenancy] use the tenant ID in the context for this + tcs, err := h.configService.GetAllTenants() + if err != nil || len(tcs) == 0 { + return nil, ErrInvalidTenantID + } id := uuid.FromStringOrNil(req.TransactionId) if id == uuid.Nil { return nil, ErrInvalidTransactionID } - return h.srv.GetTransactionStatus(identity, id) + cid, err := identity.ToCentID(tcs[0].IdentityID) + if err != nil || len(tcs) == 0 { + return nil, ErrInvalidTenantID + } + + return h.srv.GetTransactionStatus(cid, id) } diff --git a/transactions/handler_test.go b/transactions/handler_test.go index c185c41bb..7fea0fd42 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -6,14 +6,18 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/common" + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/stretchr/testify/assert" ) func TestGRPCHandler_GetTransactionStatus(t *testing.T) { - h := GRPCHandler(ctx[BootstrappedService].(Service)) + cService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + h := GRPCHandler(ctx[BootstrappedService].(Service), cService) req := new(transactionspb.TransactionStatusRequest) ctxl := context.Background() @@ -31,7 +35,9 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { assert.True(t, errors.IsOfType(ErrInvalidTransactionID, err)) // missing err - tx := NewTransaction(common.DummyIdentity, "") + tcs, _ := cService.GetAllTenants() + cid, err := identity.ToCentID(tcs[0].IdentityID) + tx := NewTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) assert.Nil(t, res) diff --git a/transactions/repository.go b/transactions/repository.go index d66f5d293..de1827963 100644 --- a/transactions/repository.go +++ b/transactions/repository.go @@ -2,9 +2,8 @@ package transactions import ( "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/satori/go.uuid" ) @@ -18,7 +17,7 @@ const ( // Repository can be implemented by a type that handles storage for transactions. type Repository interface { - Get(identity common.Address, id uuid.UUID) (*Transaction, error) + Get(identity identity.CentID, id uuid.UUID) (*Transaction, error) Save(transaction *Transaction) error } @@ -36,20 +35,16 @@ func NewRepository(repo storage.Repository) Repository { // getKey appends identity with id. // With identity coming at first, we can even fetch transactions belonging to specific identity through prefix. -func getKey(identity common.Address, id uuid.UUID) ([]byte, error) { - if utils.IsEmptyAddress(identity) { - return nil, errors.New("identity cannot be empty") - } - +func getKey(cid identity.CentID, id uuid.UUID) ([]byte, error) { if uuid.Equal(uuid.Nil, id) { return nil, errors.New("transaction ID is not valid") } - return append(identity[:], id.Bytes()...), nil + return append(cid[:], id.Bytes()...), nil } // Get returns the transaction associated with identity and id. -func (r *txRepository) Get(identity common.Address, id uuid.UUID) (*Transaction, error) { +func (r *txRepository) Get(identity identity.CentID, id uuid.UUID) (*Transaction, error) { key, err := getKey(identity, id) if err != nil { return nil, errors.NewTypedError(ErrKeyConstructionFailed, err) @@ -65,7 +60,7 @@ func (r *txRepository) Get(identity common.Address, id uuid.UUID) (*Transaction, // Save saves the transaction to the repository. func (r *txRepository) Save(tx *Transaction) error { - key, err := getKey(tx.Identity, tx.ID) + key, err := getKey(tx.CID, tx.ID) if err != nil { return errors.NewTypedError(ErrKeyConstructionFailed, err) } diff --git a/transactions/repository_test.go b/transactions/repository_test.go index 62ed71a08..2fb5415ac 100644 --- a/transactions/repository_test.go +++ b/transactions/repository_test.go @@ -6,13 +6,16 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -24,6 +27,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) @@ -33,41 +37,33 @@ func TestMain(m *testing.M) { } func Test_getKey(t *testing.T) { - identity := common.Address([20]byte{}) + cid := identity.RandomCentID() id := uuid.UUID([16]byte{}) - // zero address - key, err := getKey(identity, id) - assert.Nil(t, key) - assert.Equal(t, "identity cannot be empty", err.Error()) - - bytes := utils.RandomSlice(common.AddressLength) - assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) - // empty id - key, err = getKey(identity, id) + key, err := getKey(cid, id) assert.Nil(t, key) assert.Equal(t, "transaction ID is not valid", err.Error()) id = uuid.Must(uuid.NewV4()) - key, err = getKey(identity, id) + key, err = getKey(cid, id) assert.Nil(t, err) - assert.Equal(t, append(identity[:], id.Bytes()...), key) + assert.Equal(t, append(cid[:], id.Bytes()...), key) } func TestRepository(t *testing.T) { - identity := common.Address([20]byte{}) - bytes := utils.RandomSlice(common.AddressLength) - assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) + cid := identity.RandomCentID() + bytes := utils.RandomSlice(identity.CentIDLength) + assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) repo := ctx[BootstrappedRepo].(Repository) - tx := NewTransaction(identity, "Some transaction") + tx := NewTransaction(cid, "Some transaction") assert.NotNil(t, tx.ID) - assert.NotNil(t, tx.Identity) + assert.NotNil(t, tx.CID) assert.Equal(t, Pending, tx.Status) // get tx from repo - _, err := repo.Get(identity, tx.ID) + _, err := repo.Get(cid, tx.ID) assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) // save tx into repo @@ -76,9 +72,9 @@ func TestRepository(t *testing.T) { assert.Nil(t, err) // get tx back - tx, err = repo.Get(identity, tx.ID) + tx, err = repo.Get(cid, tx.ID) assert.Nil(t, err) assert.NotNil(t, tx) - assert.Equal(t, identity, tx.Identity) + assert.Equal(t, cid, tx.CID) assert.Equal(t, Success, tx.Status) } diff --git a/transactions/service.go b/transactions/service.go index 361f03d22..2baa1bdeb 100644 --- a/transactions/service.go +++ b/transactions/service.go @@ -3,20 +3,21 @@ package transactions import ( "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/satori/go.uuid" ) // Service wraps the repository and exposes specific functions. type Service interface { - CreateTransaction(tenantID common.Address, desc string) (*Transaction, error) - GetTransaction(tenantID common.Address, id uuid.UUID) (*Transaction, error) + CreateTransaction(tenantID identity.CentID, desc string) (*Transaction, error) + GetTransaction(tenantID identity.CentID, id uuid.UUID) (*Transaction, error) SaveTransaction(tx *Transaction) error - GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) - WaitForTransaction(tenantID common.Address, txID uuid.UUID) error + GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) + WaitForTransaction(tenantID identity.CentID, txID uuid.UUID) error } // NewService returns a Service implementation. @@ -35,19 +36,19 @@ func (s service) SaveTransaction(tx *Transaction) error { } // GetTransaction returns the transaction associated with identity and id. -func (s service) GetTransaction(tenantID common.Address, id uuid.UUID) (*Transaction, error) { +func (s service) GetTransaction(tenantID identity.CentID, id uuid.UUID) (*Transaction, error) { return s.repo.Get(tenantID, id) } // CreateTransaction creates a new transaction and saves it to the DB. -func (s service) CreateTransaction(tenantID common.Address, desc string) (*Transaction, error) { +func (s service) CreateTransaction(tenantID identity.CentID, desc string) (*Transaction, error) { tx := NewTransaction(tenantID, desc) return tx, s.SaveTransaction(tx) } // WaitForTransaction blocks until transaction status is moved from pending state. // Note: use it with caution as this will block. -func (s service) WaitForTransaction(tenantID common.Address, txID uuid.UUID) error { +func (s service) WaitForTransaction(tenantID identity.CentID, txID uuid.UUID) error { for { resp, err := s.GetTransactionStatus(tenantID, txID) if err != nil { @@ -67,7 +68,7 @@ func (s service) WaitForTransaction(tenantID common.Address, txID uuid.UUID) err } // GetTransactionStatus returns the transaction status associated with identity and id. -func (s service) GetTransactionStatus(identity common.Address, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { +func (s service) GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { tx, err := s.GetTransaction(identity, id) if err != nil { return nil, err diff --git a/transactions/service_test.go b/transactions/service_test.go index dd723046f..cf6baf2ce 100644 --- a/transactions/service_test.go +++ b/transactions/service_test.go @@ -5,9 +5,10 @@ package transactions import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" ) @@ -15,13 +16,13 @@ func TestService_GetTransaction(t *testing.T) { repo := ctx[BootstrappedRepo].(Repository) srv := ctx[BootstrappedService].(Service) - identity := common.Address([20]byte{1}) - bytes := utils.RandomSlice(common.AddressLength) - assert.Equal(t, common.AddressLength, copy(identity[:], bytes)) - txn := NewTransaction(identity, "Some transaction") + cid := identity.RandomCentID() + bytes := utils.RandomSlice(identity.CentIDLength) + assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) + txn := NewTransaction(cid, "Some transaction") // no transaction - txs, err := srv.GetTransactionStatus(identity, txn.ID) + txs, err := srv.GetTransactionStatus(cid, txn.ID) assert.Nil(t, txs) assert.NotNil(t, err) assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) @@ -30,7 +31,7 @@ func TestService_GetTransaction(t *testing.T) { assert.Nil(t, repo.Save(txn)) // pending with no log - txs, err = srv.GetTransactionStatus(identity, txn.ID) + txs, err = srv.GetTransactionStatus(cid, txn.ID) assert.Nil(t, err) assert.NotNil(t, txs) assert.Equal(t, txs.TransactionId, txn.ID.String()) @@ -44,7 +45,7 @@ func TestService_GetTransaction(t *testing.T) { assert.Nil(t, repo.Save(txn)) // log with message - txs, err = srv.GetTransactionStatus(identity, txn.ID) + txs, err = srv.GetTransactionStatus(cid, txn.ID) assert.Nil(t, err) assert.NotNil(t, txs) assert.Equal(t, txs.TransactionId, txn.ID.String()) @@ -55,29 +56,29 @@ func TestService_GetTransaction(t *testing.T) { func TestService_CreateTransaction(t *testing.T) { srv := ctx[BootstrappedService].(Service) - identity := common.Address([20]byte{1}) - tx, err := srv.CreateTransaction(identity, "test") + cid := identity.RandomCentID() + tx, err := srv.CreateTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) - assert.Equal(t, identity.String(), tx.Identity.String()) + assert.Equal(t, cid.String(), tx.CID.String()) } func TestService_WaitForTransaction(t *testing.T) { srv := ctx[BootstrappedService].(Service) repo := ctx[BootstrappedRepo].(Repository) - identity := common.Address([20]byte{1}) + cid := identity.RandomCentID() // failed - tx, err := srv.CreateTransaction(identity, "test") + tx, err := srv.CreateTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) - assert.Equal(t, identity.String(), tx.Identity.String()) + assert.Equal(t, cid.String(), tx.CID.String()) tx.Status = Failed assert.NoError(t, repo.Save(tx)) - assert.Error(t, srv.WaitForTransaction(identity, tx.ID)) + assert.Error(t, srv.WaitForTransaction(cid, tx.ID)) // success tx.Status = Success assert.NoError(t, repo.Save(tx)) - assert.NoError(t, srv.WaitForTransaction(identity, tx.ID)) + assert.NoError(t, srv.WaitForTransaction(cid, tx.ID)) } diff --git a/transactions/transaction.go b/transactions/transaction.go index 2510c2650..3e81b3c18 100644 --- a/transactions/transaction.go +++ b/transactions/transaction.go @@ -5,7 +5,8 @@ import ( "reflect" "time" - "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/satori/go.uuid" ) @@ -38,7 +39,7 @@ func NewLog(action, message string) Log { // Transaction contains details of transaction. type Transaction struct { ID uuid.UUID - Identity common.Address + CID identity.CentID Description string Status Status Logs []Log @@ -62,10 +63,10 @@ func (t *Transaction) Type() reflect.Type { } // NewTransaction returns a new transaction with a pending state -func NewTransaction(identity common.Address, description string) *Transaction { +func NewTransaction(identity identity.CentID, description string) *Transaction { return &Transaction{ ID: uuid.Must(uuid.NewV4()), - Identity: identity, + CID: identity, Description: description, Status: Pending, Metadata: make(map[string]string), From 9bc54acda7bbee08e092d1c1fff1b827b9de455a Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 7 Jan 2019 22:38:40 +0100 Subject: [PATCH 114/220] Anchor uses tenant config (#618) * Anchor uses tenant config * Fix unit test --- anchors/anchor.go | 5 ----- anchors/anchor_repository.go | 5 +++-- anchors/anchor_repository_integration_test.go | 14 +++++++++++-- anchors/ethereum_anchor_repository.go | 21 ++++++++++++++----- config/configstore/service.go | 2 +- coredocument/processor.go | 2 +- coredocument/processor_test.go | 4 ++-- p2p/receiver/handler_integration_test.go | 8 +++++-- transactions/repository.go | 6 +++--- 9 files changed, 44 insertions(+), 23 deletions(-) diff --git a/anchors/anchor.go b/anchors/anchor.go index fac6dc398..aaf1137fc 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -3,15 +3,12 @@ package anchors import ( "math/big" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" "time" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -34,9 +31,7 @@ type AnchorID [AnchorIDLength]byte // Config defines required functions for the package Anchors type Config interface { - GetEthereumDefaultAccountName() string GetEthereumContextWaitTimeout() time.Duration - GetContractAddress(contractName config.ContractName) common.Address } // ToAnchorID convert the bytes into AnchorID type diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index ff1f9b176..043ca40db 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -1,6 +1,7 @@ package anchors import ( + "context" "math/big" "github.com/centrifuge/go-centrifuge/identity" @@ -12,7 +13,7 @@ var log = logging.Logger("anchorRepository") // AnchorRepository defines a set of functions that can be // implemented by any type that stores and retrieves the anchoring, and pre anchoring details. type AnchorRepository interface { - PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (<-chan *WatchPreCommit, error) - CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *WatchCommit, error) + PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) + CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) } diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 957333e57..5367b5560 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -7,6 +7,10 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/anchors" @@ -22,12 +26,14 @@ import ( var ( identityService identity.Service anchorRepo anchors.AnchorRepository + cfg config.Configuration ) func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) identityService = ctx[ethid.BootstrappedIDService].(identity.Service) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -76,7 +82,9 @@ func commitAnchor(t *testing.T, anchorID, centrifugeId, documentRoot, signature docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) centIdFixed, _ := identity.ToCentID(centrifugeId) - confirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) + cfg.Set("identityId", centIdFixed.String()) + ctx := testingconfig.CreateTenantContext(t, cfg) + confirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) } @@ -104,7 +112,9 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { h, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) assert.Nil(t, err, " error must be nil") commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) - confirmationList[ix], err = anchorRepo.CommitAnchor(currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) + cfg.Set("identityId", centIdFixed.String()) + ctx := testingconfig.CreateTenantContext(t, cfg) + confirmationList[ix], err = anchorRepo.CommitAnchor(ctx, currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index c2a38ae1a..958e60b70 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -4,6 +4,8 @@ import ( "context" "math/big" + "github.com/centrifuge/go-centrifuge/contextutil" + "time" "github.com/centrifuge/go-centrifuge/errors" @@ -29,7 +31,6 @@ type watchAnchorPreCommitted interface { } type ethereumAnchorRepository struct { - // TODO [multi-tenancy] replace this with config service config Config anchorRepositoryContract anchorRepositoryContract gethClientFinder func() ethereum.Client @@ -48,9 +49,14 @@ func (ethRepository *ethereumAnchorRepository) GetDocumentRootOf(anchorID Anchor } // PreCommitAnchor will call the transaction PreCommit on the smart contract -func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { +func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { + tc, err := contextutil.Tenant(ctx) + if err != nil { + return nil, err + } + ethRepositoryContract := ethRepository.anchorRepositoryContract - opts, err := ethereum.GetClient().GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) + opts, err := ethereum.GetClient().GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { return confirmations, err } @@ -72,9 +78,14 @@ func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(anchorID AnchorID } // CommitAnchor will send a commit transaction to Ethereum. -func (ethRepository *ethereumAnchorRepository) CommitAnchor(anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { +func (ethRepository *ethereumAnchorRepository) CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { + tc, err := contextutil.Tenant(ctx) + if err != nil { + return nil, err + } + conn := ethereum.GetClient() - opts, err := conn.GetTxOpts(ethRepository.config.GetEthereumDefaultAccountName()) + opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { return nil, err } diff --git a/config/configstore/service.go b/config/configstore/service.go index cbb6630db..77080fbf9 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -64,7 +64,7 @@ func (s service) DeleteTenant(identifier []byte) error { return s.repo.DeleteTenant(identifier) } -// RetrieveConfig retrieves system config giving priority to db store config +// RetrieveConfig retrieves system config giving priority to db stored config func RetrieveConfig(dbOnly bool, ctx map[string]interface{}) (config.Configuration, error) { var cfg config.Configuration var err error diff --git a/coredocument/processor.go b/coredocument/processor.go index f23b400b6..8b4e71d60 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -234,7 +234,7 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model documents.M } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) - confirmations, err := dp.anchorRepository.CommitAnchor(anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) + confirmations, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) if err != nil { return errors.New("failed to commit anchor: %v", err) } diff --git a/coredocument/processor_test.go b/coredocument/processor_test.go index e7a231264..96484e352 100644 --- a/coredocument/processor_test.go +++ b/coredocument/processor_test.go @@ -243,8 +243,8 @@ type mockRepo struct { anchors.AnchorRepository } -func (m mockRepo) CommitAnchor(anchorID anchors.AnchorID, documentRoot anchors.DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (<-chan *anchors.WatchCommit, error) { - args := m.Called(anchorID, documentRoot, centrifugeID, documentProofs, signature) +func (m mockRepo) CommitAnchor(ctx context.Context, anchorID anchors.AnchorID, documentRoot anchors.DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *anchors.WatchCommit, err error) { + args := m.Called(anchorID, documentRoot, centID, documentProofs, signature) c, _ := args.Get(0).(chan *anchors.WatchCommit) return c, args.Error(1) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 0ff384a42..6e1b4df10 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -140,7 +142,8 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + ctx := testingconfig.CreateTenantContext(t, cfg) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations @@ -182,7 +185,8 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchorRepo.CommitAnchor(anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + ctx := testingconfig.CreateTenantContext(t, cfg) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations diff --git a/transactions/repository.go b/transactions/repository.go index de1827963..5e4422aa4 100644 --- a/transactions/repository.go +++ b/transactions/repository.go @@ -17,7 +17,7 @@ const ( // Repository can be implemented by a type that handles storage for transactions. type Repository interface { - Get(identity identity.CentID, id uuid.UUID) (*Transaction, error) + Get(cid identity.CentID, id uuid.UUID) (*Transaction, error) Save(transaction *Transaction) error } @@ -44,8 +44,8 @@ func getKey(cid identity.CentID, id uuid.UUID) ([]byte, error) { } // Get returns the transaction associated with identity and id. -func (r *txRepository) Get(identity identity.CentID, id uuid.UUID) (*Transaction, error) { - key, err := getKey(identity, id) +func (r *txRepository) Get(cid identity.CentID, id uuid.UUID) (*Transaction, error) { + key, err := getKey(cid, id) if err != nil { return nil, errors.NewTypedError(ErrKeyConstructionFailed, err) } From e4c31866cb4b3209d2092573d533d01684146ad1 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 8 Jan 2019 11:08:25 +0100 Subject: [PATCH 115/220] genericDocumentService: added interface and bootstrappers (#610) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests * generated genericdoc package * moved service_test * added CreateProof to model * changed to correct create proofs * formatting * correct flags * added proof methods * moved service_test.go * added tests for createProof in service * implemented remaining methods for document service * fixed broken createProofVersion test case * formatting * added tests for requestSignature * formatting * implemented own interface for generic document * added bootstrapper to generic document service * added bootstrapper for generic service * fixed linting * added bootstrapper for tests * removed derive from cd * removed cyclic dep * formatting * fixed api/server * formatting * formatting * fixed api server * correct testworld flags * formatting --- Gopkg.lock | 1 - api/server_test.go | 5 ++- bootstrap/bootstrappers/bootstrapper.go | 2 + .../testingbootstrap/testing_bootstrap.go | 2 + documents/genericdoc/bootstrapper.go | 38 +++++++++++++++++++ documents/genericdoc/service.go | 32 +++++++++++++--- documents/genericdoc/service_test.go | 18 +++++---- documents/genericdoc/test_bootstrapper.go | 11 ++++++ documents/invoice/bootstrapper.go | 7 +++- documents/invoice/model_test.go | 3 ++ documents/invoice/service.go | 10 ++++- documents/invoice/service_test.go | 4 +- documents/purchaseorder/bootstrapper.go | 8 +++- documents/purchaseorder/model_test.go | 3 ++ documents/purchaseorder/service.go | 7 +++- documents/purchaseorder/service_test.go | 2 +- 16 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 documents/genericdoc/bootstrapper.go create mode 100644 documents/genericdoc/test_bootstrapper.go diff --git a/Gopkg.lock b/Gopkg.lock index e54abf7ba..2c94734f2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1519,7 +1519,6 @@ "github.com/gavv/httpexpect", "github.com/go-errors/errors", "github.com/gogo/protobuf/io", - "github.com/golang/protobuf/jsonpb", "github.com/golang/protobuf/proto", "github.com/golang/protobuf/protoc-gen-go", "github.com/golang/protobuf/ptypes", diff --git a/api/server_test.go b/api/server_test.go index b8b0b49ff..fec971c5c 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -54,6 +56,7 @@ func TestMain(m *testing.M) { ðid.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, + &genericdoc.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, @@ -73,7 +76,7 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(nil, nil, nil, nil, nil)) + registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(nil, nil, nil, nil, nil, nil)) capi := apiServer{config: cfg} ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) startErr := make(chan error) diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 300472943..33f6c07d8 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -44,6 +45,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { documents.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, + &genericdoc.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, coredocument.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 2f1492162..d3dd86476 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -37,6 +38,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ ðid.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, + &genericdoc.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, coredocument.Bootstrapper{}, diff --git a/documents/genericdoc/bootstrapper.go b/documents/genericdoc/bootstrapper.go new file mode 100644 index 000000000..d3fea1a34 --- /dev/null +++ b/documents/genericdoc/bootstrapper.go @@ -0,0 +1,38 @@ +package genericdoc + +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity/ethid" + + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/identity" +) + +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} + +// BootstrappedGenService is a key mapped to the generic document service +const BootstrappedGenService = "BootstrappedGenService " + +// Bootstrap sets the required storage and registers +func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return errors.New("anchor repository not initialised") + } + + idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + + repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) + if !ok { + return errors.New("document db repository not initialised") + } + + ctx[BootstrappedGenService] = DefaultService(repo, anchorRepo, idService) + return nil + +} diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 0a3279300..db5606b7b 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -22,6 +22,31 @@ import ( logging "github.com/ipfs/go-log" ) +// Service provides an interface for generic document methods +type Service interface { + + // GetCurrentVersion reads a document from the database + GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) + + // Exists checks if a document exists + Exists(ctx context.Context, documentID []byte) bool + + // GetVersion reads a document from the database + GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) + + // CreateProofs creates proofs for the latest version document given the fields + CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) + + // CreateProofsForVersion creates proofs for a particular version of the document given the fields + CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) + + // RequestDocumentSignature Validates and Signs document received over the p2p layer + RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) + + // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB + ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error +} + // service implements Service type service struct { repo documents.Repository @@ -34,7 +59,7 @@ var srvLog = logging.Logger("document-service") // DefaultService returns the default implementation of the service func DefaultService(repo documents.Repository, - anchorRepo anchors.AnchorRepository, idService identity.Service) documents.Service { + anchorRepo anchors.AnchorRepository, idService identity.Service) Service { return service{ repo: repo, anchorRepository: anchorRepo, @@ -118,11 +143,6 @@ func (s service) CreateProofsForVersion(ctx context.Context, documentID, version return s.createProofs(model, fields) } -func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { - - return nil, nil -} - func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { idConf, err := contextutil.Self(ctx) if err != nil { diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index 566c9bc12..511b71d05 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -1,12 +1,14 @@ // +build unit -package genericdoc +package genericdoc_test import ( "math/big" "os" "testing" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -58,17 +60,18 @@ func TestMain(m *testing.M) { } func TestService_ReceiveAnchoredDocument(t *testing.T) { - poSrv := service{} + poSrv := genericdoc.DefaultService(nil, nil, nil) ctxh := testingconfig.CreateTenantContext(t, cfg) err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } -func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { +func getServiceWithMockedLayers() (genericdoc.Service, testingcommons.MockIDService) { repo := testRepo() idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - return DefaultService(repo, &mockAnchorRepo{}, &idService), idService + mockAnchor = &mockAnchorRepo{} + return genericdoc.DefaultService(repo, mockAnchor, &idService), idService } type mockAnchorRepo struct { @@ -76,6 +79,8 @@ type mockAnchorRepo struct { anchors.AnchorRepository } +var mockAnchor *mockAnchorRepo + func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { args := r.Called(anchorID) docRoot, _ := args.Get(0).(anchors.DocumentRoot) @@ -176,7 +181,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv } // Functions returns service mocks -func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s documents.Service) testingcommons.MockIDService { +func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s genericdoc.Service) testingcommons.MockIDService { idkey := ðid.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, @@ -184,8 +189,7 @@ func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDServi } anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) - mockRepo := s.(service).anchorRepository.(*mockAnchorRepo) - mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() + mockAnchor.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() id := &testingcommons.MockID{} centID, _ := identity.ToCentID(centIDBytes) idService.On("LookupIdentityForID", centID).Return(id, nil).Once() diff --git a/documents/genericdoc/test_bootstrapper.go b/documents/genericdoc/test_bootstrapper.go new file mode 100644 index 000000000..07c5819bf --- /dev/null +++ b/documents/genericdoc/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build integration unit + +package genericdoc + +func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { + return b.Bootstrap(context) +} + +func (*Bootstrapper) TestTearDown() error { + return nil +} diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 0c287d4d0..d717be04f 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,6 +1,7 @@ package invoice import ( + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -49,11 +50,15 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transaction service not initialised") } + genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + if !ok { + return errors.New("generic service is not initialised") + } // register service srv := DefaultService( repo, anchorRepo, - idService, queueSrv, txService) + idService, queueSrv, txService, genService) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return errors.New("failed to register invoice service: %v", err) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 12ae4b735..1e7d45499 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -8,6 +8,8 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -58,6 +60,7 @@ func TestMain(m *testing.M) { ðid.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, + &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, &Bootstrapper{}, &queue.Starter{}, diff --git a/documents/invoice/service.go b/documents/invoice/service.go index daefe71d4..a46b43f6b 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -5,6 +5,8 @@ import ( "context" "time" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -60,6 +62,7 @@ type service struct { identityService identity.Service queueSrv queue.TaskQueuer txService transactions.Service + genService genericdoc.Service } // DefaultService returns the default implementation of the service. @@ -68,14 +71,17 @@ func DefaultService( anchorRepository anchors.AnchorRepository, identityService identity.Service, queueSrv queue.TaskQueuer, - txService transactions.Service) Service { + txService transactions.Service, + genService genericdoc.Service, +) Service { return service{ repo: repo, notifier: notification.NewWebhookSender(), anchorRepository: anchorRepository, identityService: identityService, queueSrv: queueSrv, - txService: txService} + txService: txService, + genService: genService} } // CreateProofs creates proofs for the latest version document given the fields diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 2baab4de8..4e7975a0b 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -51,7 +51,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func TestDefaultService(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil).Once() - srv := DefaultService(testRepo(), nil, nil, nil, nil) + srv := DefaultService(testRepo(), nil, nil, nil, nil, nil) assert.NotNil(t, srv, "must be non-nil") } @@ -66,7 +66,7 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { testRepo(), &mockAnchorRepo{}, &idService, queueSrv, - ctx[transactions.BootstrappedService].(transactions.Service)) + ctx[transactions.BootstrappedService].(transactions.Service), nil) } func createMockDocument() (*Invoice, error) { diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index ce375c29e..0e1fa3208 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,6 +1,7 @@ package purchaseorder import ( + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -49,8 +50,13 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transaction service not initialised") } + genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + if !ok { + return errors.New("generic service is not initialised") + } + // register service - srv := DefaultService(repo, anchorRepo, idService, queueSrv, txService) + srv := DefaultService(repo, anchorRepo, idService, queueSrv, txService, genService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 39db855cd..e0dc0a036 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -8,6 +8,8 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -59,6 +61,7 @@ func TestMain(m *testing.M) { anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, + &genericdoc.Bootstrapper{}, &Bootstrapper{}, &queue.Starter{}, } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 8f89df22d..83fb9059d 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -5,6 +5,8 @@ import ( "context" "time" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -60,6 +62,7 @@ type service struct { identityService identity.Service queueSrv queue.TaskQueuer txService transactions.Service + genService genericdoc.Service } // DefaultService returns the default implementation of the service @@ -68,7 +71,8 @@ func DefaultService( anchorRepository anchors.AnchorRepository, identityService identity.Service, queueSrv queue.TaskQueuer, - txService transactions.Service) Service { + txService transactions.Service, + genService genericdoc.Service) Service { return service{ repo: repo, notifier: notification.NewWebhookSender(), @@ -76,6 +80,7 @@ func DefaultService( identityService: identityService, queueSrv: queueSrv, txService: txService, + genService: genService, } } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 76440a960..ef11f4194 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -54,7 +54,7 @@ func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) txService := ctx[transactions.BootstrappedService].(transactions.Service) - return idService, DefaultService(testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService) + return idService, DefaultService(testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService, nil) } func TestService_Update(t *testing.T) { From 5e969f80b21397f45e88159f0a5668df6fef7e3b Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 8 Jan 2019 11:53:02 +0100 Subject: [PATCH 116/220] Removing no longer used scripts (#621) --- build/scripts/run_local_node.sh | 15 ------- .../scripts/setup_smart_contract_addresses.sh | 39 ------------------- build/scripts/tests/run_integration_tests.sh | 2 - 3 files changed, 56 deletions(-) delete mode 100755 build/scripts/run_local_node.sh delete mode 100755 build/scripts/setup_smart_contract_addresses.sh diff --git a/build/scripts/run_local_node.sh b/build/scripts/run_local_node.sh deleted file mode 100755 index 4763d6429..000000000 --- a/build/scripts/run_local_node.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -a - -## run this so that latest local code is rebuilt -make install - -# Set local contracts directory -export CENT_ETHEREUM_CONTRACTS_DIR=${PARENT_DIR}/vendor/github.com/centrifuge/centrifuge-ethereum-contracts - -################# Prepare for run ######################## -PARENT_DIR=`pwd` -source "${PARENT_DIR}/build/scripts/setup_smart_contract_addresses.sh" - -centrifuge run --config example/resources/centrifuge_example.yaml diff --git a/build/scripts/setup_smart_contract_addresses.sh b/build/scripts/setup_smart_contract_addresses.sh deleted file mode 100755 index fc21be5d6..000000000 --- a/build/scripts/setup_smart_contract_addresses.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# Get latest Anchor and Identity Registry Addresses from contract json -export TEST_TIMEOUT=${TEST_TIMEOUT:-600s} -export TEST_TARGET_ENVIRONMENT=${TEST_TARGET_ENVIRONMENT:-'localgeth'} -export CENT_CENTRIFUGENETWORK=${CENT_CENTRIFUGENETWORK:-'testing'} - -## Making Env Var Name dynamic -cent_upper_network=`echo $CENT_CENTRIFUGENETWORK | awk '{print toupper($0)}'` -tempIdentityFactory="CENT_NETWORKS_${cent_upper_network}_CONTRACTADDRESSES_IDENTITYFACTORY" -printf -v $tempIdentityFactory `cat $CENT_ETHEREUM_CONTRACTS_DIR/deployments/$TEST_TARGET_ENVIRONMENT.json | jq -r '.contracts.IdentityFactory.address' | tr -d '\n'` -tempIdentityRegistry="CENT_NETWORKS_${cent_upper_network}_CONTRACTADDRESSES_IDENTITYREGISTRY" -printf -v $tempIdentityRegistry `cat $CENT_ETHEREUM_CONTRACTS_DIR/deployments/$TEST_TARGET_ENVIRONMENT.json | jq -r '.contracts.IdentityRegistry.address' | tr -d '\n'` -tempAnchorRepository="CENT_NETWORKS_${cent_upper_network}_CONTRACTADDRESSES_ANCHORREPOSITORY" -printf -v $tempAnchorRepository `cat $CENT_ETHEREUM_CONTRACTS_DIR/deployments/$TEST_TARGET_ENVIRONMENT.json | jq -r '.contracts.AnchorRepository.address' | tr -d '\n'` -tempPaymentObligation="CENT_NETWORKS_${cent_upper_network}_CONTRACTADDRESSES_PAYMENTOBLIGATION" -printf -v $tempPaymentObligation `cat $CENT_ETHEREUM_CONTRACTS_DIR/deployments/$TEST_TARGET_ENVIRONMENT.json | jq -r '.contracts.PaymentObligation.address' | tr -d '\n'` - -export $tempIdentityFactory -export $tempIdentityRegistry -export $tempAnchorRepository -export $tempPaymentObligation - -vtempIdentityFactory=$(eval "echo \"\$$tempIdentityFactory\"") -vtempIdentityRegistry=$(eval "echo \"\$$tempIdentityRegistry\"") -vtempAnchorRepository=$(eval "echo \"\$$tempAnchorRepository\"") -vtempPaymentObligation=$(eval "echo \"\$$tempPaymentObligation\"") -# - -echo "ANCHOR REPOSITORY ADDRESS: ${vtempAnchorRepository}" -echo "IDENTITY REGISTRY ADDRESS: ${vtempIdentityRegistry}" -echo "IDENTITY FACTORY ADDRESS: ${vtempIdentityFactory}" -echo "PAYMENT OBLIGATION ADDRESS: ${vtempPaymentObligation}" - - -if [ -z $vtempIdentityFactory ] || [ -z $vtempIdentityRegistry ] || [ -z $vtempAnchorRepository ] || [ -z $vtempPaymentObligation ]; then - echo "One of the required contract addresses is not set. Aborting." - exit -1 -fi \ No newline at end of file diff --git a/build/scripts/tests/run_integration_tests.sh b/build/scripts/tests/run_integration_tests.sh index f15ee24b3..1fcc4de7a 100755 --- a/build/scripts/tests/run_integration_tests.sh +++ b/build/scripts/tests/run_integration_tests.sh @@ -6,8 +6,6 @@ PARENT_DIR=`pwd` source "${PARENT_DIR}/build/scripts/test-dependencies/test-ethereum/env_vars.sh" ################# Prepare for tests ######################## -source "${PARENT_DIR}/build/scripts/setup_smart_contract_addresses.sh" - echo "Running Integration Tests against [${CENT_ETHEREUM_NODEURL}] with TIMEOUT [${TEST_TIMEOUT}]" status=$? From 6c9dbb481fd9034b7e863349d2445e3b33aec770 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 8 Jan 2019 15:04:59 +0100 Subject: [PATCH 117/220] using generic document service inside invoice service (#620) * added testworld tests for proofs * doc service with get and get version * added test for getVersion * added more tests for service get methods * improved search and tests * improved tests * generated genericdoc package * moved service_test * added CreateProof to model * changed to correct create proofs * formatting * correct flags * added proof methods * moved service_test.go * added tests for createProof in service * implemented remaining methods for document service * fixed broken createProofVersion test case * formatting * added tests for requestSignature * formatting * implemented own interface for generic document * added bootstrapper to generic document service * added bootstrapper for generic service * fixed linting * added bootstrapper for tests * removed derive from cd * replaced getVersion for invoice with generic one * removed cyclic dep * formatting * fixed api/server * formatting * fixed GetLatestVersion invoice * formatting * fixed api server * correct testworld flags * added generic exists to invoice * added generic proof generation to invoice * added generic requestDocumentSignature to invoice * formatting * formatting * removed old tests * using a embedded interface --- documents/genericdoc/service_test.go | 3 +- documents/invoice/model_test.go | 1 + documents/invoice/service.go | 201 +++---------------------- documents/invoice/service_test.go | 212 +++------------------------ resources/data.go | 2 +- 5 files changed, 50 insertions(+), 369 deletions(-) diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index 511b71d05..ca1e6057e 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -20,7 +22,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 1e7d45499..3c8472202 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -62,6 +62,7 @@ func TestMain(m *testing.M) { documents.Bootstrapper{}, &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, + &genericdoc.Bootstrapper{}, &Bootstrapper{}, &queue.Starter{}, } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index a46b43f6b..24852563e 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -1,19 +1,14 @@ package invoice import ( - "bytes" "context" - "time" "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -21,9 +16,7 @@ import ( clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) @@ -62,7 +55,7 @@ type service struct { identityService identity.Service queueSrv queue.TaskQueuer txService transactions.Service - genService genericdoc.Service + genericdoc.Service } // DefaultService returns the default implementation of the service. @@ -81,48 +74,8 @@ func DefaultService( identityService: identityService, queueSrv: queueSrv, txService: txService, - genService: genService} -} - -// CreateProofs creates proofs for the latest version document given the fields -func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(ctx, documentID) - if err != nil { - return nil, err - } - - return s.invoiceProof(model, fields) -} - -// CreateProofsForVersion creates proofs for a particular version of the document given the fields -func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetVersion(ctx, documentID, version) - if err != nil { - return nil, err - } - - return s.invoiceProof(model, fields) -} - -// invoiceProof creates proofs for invoice model fields -func (s service) invoiceProof(model documents.Model, fields []string) (*documents.DocumentProof, error) { - inv, ok := model.(*Invoice) - if !ok { - return nil, documents.ErrDocumentInvalidType + Service: genService, } - - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, inv); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - coreDoc, proofs, err := inv.CreateProofs(fields) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentProof, err) - } - return &documents.DocumentProof{ - DocumentID: coreDoc.DocumentIdentifier, - VersionID: coreDoc.CurrentVersion, - FieldProofs: proofs, - }, nil } // DeriveFromCoreDocument unpacks the core document into a model @@ -252,54 +205,32 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return inv, txID, nil } -// GetVersion returns an invoice for a given version -func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { - inv, err := s.getInvoiceVersion(ctx, documentID, version) - if err != nil { - return nil, err +func (s service) checkType(model documents.Model) (documents.Model, error) { + _, ok := model.(*Invoice) + if !ok { + return nil, documents.ErrDocumentInvalidType } - return inv, nil + return model, nil } -// GetCurrentVersion returns the last known version of an invoice -func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { - inv, err := s.getInvoiceVersion(ctx, documentID, documentID) +// GetVersion returns an invoice for a given version +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (model documents.Model, err error) { + model, err = s.Service.GetVersion(ctx, documentID, version) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, err } - nextVersion := inv.CoreDocument.NextVersion - for nextVersion != nil { - temp, err := s.getInvoiceVersion(ctx, documentID, nextVersion) - if err != nil { - // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration - return inv, nil - } + return s.checkType(model) - inv = temp - nextVersion = inv.CoreDocument.NextVersion - } - return inv, nil } -func (s service) getInvoiceVersion(ctx context.Context, documentID, version []byte) (inv *Invoice, err error) { - self, err := contextutil.Self(ctx) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - doc, err := s.repo.Get(self.ID[:], version) +// GetCurrentVersion returns the last known version of an invoice +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (model documents.Model, err error) { + model, err = s.Service.GetCurrentVersion(ctx, documentID) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) - } - inv, ok := doc.(*Invoice) - if !ok { - return nil, documents.ErrDocumentInvalidType + return nil, err } + return s.checkType(model) - if !bytes.Equal(inv.CoreDocument.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) - } - return inv, nil } // DeriveInvoiceResponse returns create response from invoice model @@ -390,98 +321,14 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv return inv, nil } -// RequestDocumentSignature Validates, Signs document received over the p2p layer and returns Signature -func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { - self, err := contextutil.Self(ctx) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - doc, err := model.PackCoreDocument() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigTenantID - } - - idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] - if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) - } - sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) - doc.Signatures = append(doc.Signatures, sig) - err = model.UnpackCoreDocument(doc) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) - } - - // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(self.ID[:], doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(self.ID[:], doc.DocumentIdentifier, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - } - - err = s.repo.Create(self.ID[:], doc.CurrentVersion, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) - return sig, nil -} - -// ReceiveAnchoredDocument receives a new anchored document, validates and updates the document in DB -func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { - self, err := contextutil.Self(ctx) - if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - doc, err := model.PackCoreDocument() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - err = s.repo.Update(self.ID[:], doc.CurrentVersion, model) - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - ts, _ := ptypes.TimestampProto(time.Now().UTC()) - notificationMsg := ¬ificationpb.NotificationMessage{ - EventType: uint32(notification.ReceivedPayload), - CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), - Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentId: hexutil.Encode(doc.DocumentIdentifier), - } - - // Async until we add queuing - go s.notifier.Send(ctx, notificationMsg) - - return nil -} - // Exists checks if an invoice exists func (s service) Exists(ctx context.Context, documentID []byte) bool { - self, err := contextutil.Self(ctx) - if err != nil { - return false + if s.Service.Exists(ctx, documentID) { + // check if document is an invoice + _, err := s.Service.GetCurrentVersion(ctx, documentID) + if err == nil { + return true + } } - return s.repo.Exists(self.ID[:], documentID) + return false } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 4e7975a0b..51cb3b740 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -6,6 +6,10 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/gocelery" @@ -62,11 +66,15 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) + + repo := testRepo() + mockAnchor := &mockAnchorRepo{} + genService := genericdoc.DefaultService(repo, mockAnchor, &idService) return idService, DefaultService( - testRepo(), - &mockAnchorRepo{}, &idService, + repo, + mockAnchor, &idService, queueSrv, - ctx[transactions.BootstrappedService].(transactions.Service), nil) + ctx[transactions.BootstrappedService].(transactions.Service), genService) } func createMockDocument() (*Invoice, error) { @@ -160,23 +168,26 @@ func TestService_GetLastVersion(t *testing.T) { assert.Equal(t, invLoad2.CoreDocument.NextVersion, thirdIdentifier) } -func TestService_GetVersion_invalid_version(t *testing.T) { +func TestService_GetVersion_wrongTyp(t *testing.T) { _, invSrv := getServiceWithMockedLayers() currentVersion := utils.RandomSlice(32) - inv := &Invoice{ - GrossAmount: 60, + documentIdentifier := utils.RandomSlice(32) + + //should be an invoice + po := &purchaseorder.PurchaseOrder{ + NetAmount: 60, CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: utils.RandomSlice(32), + DocumentIdentifier: documentIdentifier, CurrentVersion: currentVersion, }, } - err := testRepo().Create(tenantID, currentVersion, inv) + err := testRepo().Create(tenantID, currentVersion, po) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) - mod, err := invSrv.GetVersion(ctxh, utils.RandomSlice(32), currentVersion) - assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) - assert.Nil(t, mod) + _, err = invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) + assert.Error(t, err) + } func TestService_GetVersion(t *testing.T) { @@ -299,185 +310,6 @@ func mockSignatureCheck(i *Invoice, idService testingcommons.MockIDService, invS return idService } -func TestService_CreateProofs(t *testing.T) { - idService, invSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, invSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - proof, err := invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) - assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) - assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") -} - -func TestService_CreateProofsValidationFails(t *testing.T) { - idService, invSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - i.CoreDocument.SigningRoot = nil - err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, invSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "signing root missing") -} - -func TestService_CreateProofsInvalidField(t *testing.T) { - idService, invSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, invSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = invSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) -} - -func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { - _, invService := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err := invService.CreateProofs(ctxh, utils.RandomSlice(32), []string{"invoice.invoice_number"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) -} - -func TestService_CreateProofsForVersion(t *testing.T) { - idService, invSrv := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, invSrv) - olderVersion := i.CoreDocument.CurrentVersion - i, err = updatedAnchoredMockDocument(t, i) - assert.Nil(t, err) - proof, err := invSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) - assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, olderVersion, proof.VersionID) - assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") -} - -func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { - i, err := createAnchoredMockDocument(t, false) - _, invSrv := getServiceWithMockedLayers() - assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = invSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) -} - -func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { - idService, invSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, true) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, invSrv) - i.CoreDocument.SigningRoot = nil - signature, err := invSrv.RequestDocumentSignature(testingconfig.CreateTenantContext(t, cfg), i) - assert.NotNil(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) - assert.Nil(t, signature) -} - -func createAnchoredMockDocument(t *testing.T, skipSave bool) (*Invoice, error) { - i := &Invoice{ - InvoiceNumber: "test_invoice", - GrossAmount: 60, - CoreDocument: coredocument.New(), - } - err := i.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the invoice - corDoc, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc) - if err != nil { - return nil, err - } - - centID, err := identity.ToCentID(centIDBytes) - assert.Nil(t, err) - signKey := identity.IDKey{ - PublicKey: key1Pub[:], - PrivateKey: key1, - } - idConfig := &identity.IDConfig{ - ID: centID, - Keys: map[int]identity.IDKey{ - identity.KeyPurposeSigning: signKey, - }, - } - - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) - - corDoc.Signatures = append(corDoc.Signatures, sig) - - err = coredocument.CalculateDocumentRoot(corDoc) - if err != nil { - return nil, err - } - err = i.UnpackCoreDocument(corDoc) - if err != nil { - return nil, err - } - - if !skipSave { - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) - if err != nil { - return nil, err - } - } - - return i, nil -} - -func updatedAnchoredMockDocument(t *testing.T, i *Invoice) (*Invoice, error) { - i.GrossAmount = 50 - err := i.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the invoice - corDoc, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - // hacky update to version - corDoc.CurrentVersion = corDoc.NextVersion - corDoc.NextVersion = utils.RandomSlice(32) - if err != nil { - return nil, err - } - err = coredocument.CalculateSigningRoot(corDoc) - if err != nil { - return nil, err - } - err = coredocument.CalculateDocumentRoot(corDoc) - if err != nil { - return nil, err - } - err = i.UnpackCoreDocument(corDoc) - if err != nil { - return nil, err - } - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) - if err != nil { - return nil, err - } - return i, nil -} - func TestService_DeriveFromUpdatePayload(t *testing.T) { _, invSrv := getServiceWithMockedLayers() // nil payload diff --git a/resources/data.go b/resources/data.go index ab66c7b4b..4550a41ce 100644 --- a/resources/data.go +++ b/resources/data.go @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + From 0e0d274f781188c61e7ce8b68a7bc2ee3ba03f65 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 8 Jan 2019 15:10:40 +0100 Subject: [PATCH 118/220] Identity package uses tenantConfig (#619) * Identity package uses tenantConfig * Fix testworld issue * Fix problem --- anchors/anchor_repository_integration_test.go | 3 ++- cmd/centrifuge/manage_identities.go | 16 +++++++++++++++- cmd/common.go | 19 ++++++++++++++++--- config/configstore/model.go | 16 ++++++++++++++++ identity/ethid/ethereum_identity.go | 11 +++++++++-- .../ethereum_identity_integration_test.go | 13 +++++++++---- identity/identity.go | 2 +- p2p/receiver/handler_integration_test.go | 2 +- testingutils/commons/mock_identity.go | 6 +++--- testingutils/identity/identity.go | 5 ++++- 10 files changed, 76 insertions(+), 17 deletions(-) diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 5367b5560..195eac7aa 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -41,7 +41,8 @@ func TestMain(m *testing.M) { func createIdentityWithKeys(t *testing.T, centrifugeId []byte) []byte { centIdTyped, _ := identity.ToCentID(centrifugeId) - id, confirmations, err := identityService.CreateIdentity(centIdTyped) + cfg.Set("identityId", centIdTyped.String()) + id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centIdTyped) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index f059d72b4..3fa714e85 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -1,8 +1,12 @@ package main import ( + "context" "io/ioutil" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" @@ -34,9 +38,19 @@ var createIdentityCmd = &cobra.Command{ panic(err) } } + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + tc, err := configstore.TempTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) + if err != nil { + panic(err) + } + + tctx, err := contextutil.NewCentrifugeContext(context.Background(), tc) + if err != nil { + panic(err) + } idService := ctx[ethid.BootstrappedIDService].(identity.Service) - _, confirmations, err := idService.CreateIdentity(centID) + _, confirmations, err := idService.CreateIdentity(tctx, centID) if err != nil { panic(err) } diff --git a/cmd/common.go b/cmd/common.go index 16c658d84..103e5b4fc 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,6 +3,9 @@ package cmd import ( "context" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" @@ -21,9 +24,9 @@ import ( var log = logging.Logger("centrifuge-cmd") -func createIdentity(idService identity.Service) (identity.CentID, error) { +func createIdentity(ctx context.Context, idService identity.Service) (identity.CentID, error) { centID := identity.RandomCentID() - _, confirmations, err := idService.CreateIdentity(centID) + _, confirmations, err := idService.CreateIdentity(ctx, centID) if err != nil { return [identity.CentIDLength]byte{}, err } @@ -89,8 +92,18 @@ func CreateConfig( cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) generateKeys(cfg) + tc, err := configstore.TempTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) + if err != nil { + return err + } + + tctx, err := contextutil.NewCentrifugeContext(context.Background(), tc) + if err != nil { + return err + } + idService := ctx[ethid.BootstrappedIDService].(identity.Service) - id, err := createIdentity(idService) + id, err := createIdentity(tctx, idService) if err != nil { return err } diff --git a/config/configstore/model.go b/config/configstore/model.go index 3c3546224..f9cac1faf 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -552,3 +552,19 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (*TenantConf EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil } + +// TempTenantConfig creates a new TenantConfig without id validation, Must only be used for tenant creation. +func TempTenantConfig(ethAccountName string, c config.Configuration) (*TenantConfig, error) { + acc, err := c.GetEthereumAccount(ethAccountName) + if err != nil && ethAccountName != "" { + return nil, err + } + return &TenantConfig{ + EthereumAccount: acc, + EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), + IdentityID: []byte{}, + ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), + SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), + EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), + }, nil +} diff --git a/identity/ethid/ethereum_identity.go b/identity/ethid/ethereum_identity.go index 4e7e94d93..cae6a7dd4 100644 --- a/identity/ethid/ethereum_identity.go +++ b/identity/ethid/ethereum_identity.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/identity" @@ -392,11 +394,16 @@ func (ids *ethereumIdentityService) CheckIdentityExists(centrifugeID identity.Ce } // CreateIdentity creates an identity representing the id on ethereum -func (ids *ethereumIdentityService) CreateIdentity(centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { +func (ids *ethereumIdentityService) CreateIdentity(ctx context.Context, centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) + tc, err := contextutil.Tenant(ctx) + if err != nil { + return nil, confirmations, err + } + id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider) conn := ids.gethClientFinder() - opts, err := conn.GetTxOpts(ids.config.GetEthereumDefaultAccountName()) + opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { return nil, confirmations, err } diff --git a/identity/ethid/ethereum_identity_integration_test.go b/identity/ethid/ethereum_identity_integration_test.go index 56c1d39c7..825927756 100644 --- a/identity/ethid/ethereum_identity_integration_test.go +++ b/identity/ethid/ethereum_identity_integration_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -42,7 +44,8 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { wrongCentrifugeId[3] = 0x0 wrongCentrifugeIdTyped, _ := identity.ToCentID(wrongCentrifugeId) - id, confirmations, err := identityService.CreateIdentity(centrifugeId) + cfg.Set("identityId", centrifugeId.String()) + id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations @@ -84,7 +87,7 @@ func TestAddKeyFromConfig(t *testing.T) { cfg.Set("identityId", centrifugeId.String()) cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - _, confirmations, err := identityService.CreateIdentity(centrifugeId) + _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations @@ -116,8 +119,9 @@ func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { var err error for ix := 0; ix < 5; ix++ { centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + cfg.Set("identityId", centId.String()) centIds[ix] = centId - _, identityConfirmations[ix], err = identityService.CreateIdentity(centId) + _, identityConfirmations[ix], err = identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centId) assert.Nil(t, err, "should not error out upon identity creation") } @@ -131,7 +135,8 @@ func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { func TestEthereumIdentityService_GetIdentityAddress(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - _, confirmations, err := identityService.CreateIdentity(centrifugeId) + cfg.Set("identityId", centrifugeId.String()) + _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") <-confirmations addr, err := identityService.GetIdentityAddress(centrifugeId) diff --git a/identity/identity.go b/identity/identity.go index 618919cdf..5ccd23379 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -110,7 +110,7 @@ type Service interface { LookupIdentityForID(centrifugeID CentID) (id Identity, err error) // CreateIdentity creates an identity representing the id on ethereum - CreateIdentity(centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) + CreateIdentity(ctx context.Context, centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) // CheckIdentityExists checks if the identity represented by id actually exists on ethereum CheckIdentityExists(centrifugeID CentID) (exists bool, err error) diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 6e1b4df10..d2b52ca49 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -204,7 +204,7 @@ func createIdentity(t *testing.T) identity.CentID { // Create Identity centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := idService.CreateIdentity(centrifugeId) + id, confirmations, err := idService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") diff --git a/testingutils/commons/mock_identity.go b/testingutils/commons/mock_identity.go index 34a804630..1153d86db 100644 --- a/testingutils/commons/mock_identity.go +++ b/testingutils/commons/mock_identity.go @@ -66,9 +66,9 @@ func (srv *MockIDService) LookupIdentityForID(centID identity.CentID) (identity. return nil, args.Error(1) } -func (srv *MockIDService) CreateIdentity(centID identity.CentID) (identity.Identity, chan *identity.WatchIdentity, error) { - args := srv.Called(centID) - id, _ := args.Get(0).(identity.Identity) +func (srv *MockIDService) CreateIdentity(ctx context.Context, centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { + args := srv.Called(centrifugeID) + id, _ = args.Get(0).(identity.Identity) watch, _ := args.Get(1).(chan *identity.WatchIdentity) return id, watch, args.Error(2) } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index a33d29c38..6132ff431 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -3,9 +3,12 @@ package testingidentity import ( + "testing" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" ) func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service) identity.CentID { @@ -13,7 +16,7 @@ func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service // only create identity if it doesn't exist id, err := idService.LookupIdentityForID(idConfig.ID) if err != nil { - _, confirmations, _ := idService.CreateIdentity(idConfig.ID) + _, confirmations, _ := idService.CreateIdentity(testingconfig.CreateTenantContext(&testing.T{}, cfg), idConfig.ID) <-confirmations // LookupIdentityForId id, _ = idService.LookupIdentityForID(idConfig.ID) From 69944c9f6c4ba7ad392e35f9f114c309cf09bacc Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 8 Jan 2019 16:08:54 +0100 Subject: [PATCH 119/220] NFT: using generic document service (#622) * added testworld tests for proofs * implemented NFT with generic service * correct flags for testworld * fixed nft error tests --- documents/registry.go | 15 --------------- documents/registry_test.go | 14 -------------- nft/bootstrapper.go | 8 ++++++++ nft/ethereum_payment_obligation.go | 13 +++++++------ nft/ethereum_payment_obligation_test.go | 3 +-- testworld/nft_test.go | 2 +- testworld/payloads.go | 14 ++++++-------- 7 files changed, 23 insertions(+), 46 deletions(-) diff --git a/documents/registry.go b/documents/registry.go index 1ef2060ae..c3015688a 100644 --- a/documents/registry.go +++ b/documents/registry.go @@ -1,7 +1,6 @@ package documents import ( - "context" "sync" "github.com/centrifuge/go-centrifuge/errors" @@ -43,17 +42,3 @@ func (s *ServiceRegistry) LocateService(serviceID string) (Service, error) { } return s.services[serviceID], nil } - -// FindService will search the service based on the documentID -func (s *ServiceRegistry) FindService(ctx context.Context, documentID []byte) (Service, error) { - s.mutex.RLock() - defer s.mutex.RUnlock() - - for _, service := range s.services { - exists := service.Exists(ctx, documentID) - if exists { - return service, nil - } - } - return nil, errors.New("no service exists for provided documentID") -} diff --git a/documents/registry_test.go b/documents/registry_test.go index d9abab538..d102e57bf 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -12,20 +12,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestServiceRegistry_FindService(t *testing.T) { - registry := documents.NewServiceRegistry() - a := &testingdocuments.MockService{} - b := &testingdocuments.MockService{} - a.On("Exists").Return(true) - b.On("Exists").Return(false) - err := registry.Register("a service", a) - err = registry.Register("b service", b) - - service, err := registry.FindService(nil, []byte{}) - assert.Nil(t, err, "findService should be successful") - assert.Equal(t, a, service, "service a should be returned") -} - func TestRegistry_Register_LocateService_successful(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index b238e8076..81bd76fb5 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -3,6 +3,8 @@ package nft import ( "context" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -52,12 +54,18 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transactions repository not initialised") } + genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + if !ok { + return errors.New("generic service is not initialised") + } + client := ethereum.GetClient() ctx[BootstrappedPayObService] = newEthereumPaymentObligation( registry, idService, client, queueSrv, + genService, bindContract, txService, func() (uint64, error) { h, err := client.GetEthClient().HeaderByNumber(context.Background(), nil) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index b0d3f7bd1..1617ec728 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -5,6 +5,8 @@ import ( "encoding/hex" "math/big" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" @@ -37,6 +39,7 @@ type ethereumPaymentObligation struct { identityService identity.Service ethClient ethereum.Client queue queue.TaskQueuer + genService genericdoc.Service bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) txService transactions.Service blockHeightFunc func() (height uint64, err error) @@ -48,6 +51,7 @@ func newEthereumPaymentObligation( identityService identity.Service, ethClient ethereum.Client, queue queue.TaskQueuer, + genService genericdoc.Service, bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error), txService transactions.Service, blockHeightFunc func() (uint64, error)) *ethereumPaymentObligation { @@ -57,18 +61,15 @@ func newEthereumPaymentObligation( ethClient: ethClient, bindContract: bindContract, queue: queue, + genService: genService, txService: txService, blockHeightFunc: blockHeightFunc, } } func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { - docService, err := s.registry.FindService(ctx, documentID) - if err != nil { - return nil, err - } - model, err := docService.GetCurrentVersion(ctx, documentID) + model, err := s.genService.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -78,7 +79,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, docu return nil, err } - proofs, err := docService.CreateProofs(ctx, documentID, proofFields) + proofs, err := s.genService.CreateProofs(ctx, documentID, proofFields) if err != nil { return nil, err } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 629c5dfba..882ed1fbb 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -155,7 +155,6 @@ func TestPaymentObligationService(t *testing.T) { docServiceMock := testingdocuments.MockService{} docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocument: coreDoc}, nil) docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) - docServiceMock.On("Exists").Return(true) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIDService{} ethClientMock := testingcommons.MockEthClient{} @@ -192,7 +191,7 @@ func TestPaymentObligationService(t *testing.T) { docService, paymentOb, idService, ethClient, mockCfg, queueSrv := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton registry.Register(test.name, &docService) - service := newEthereumPaymentObligation(registry, &idService, ðClient, queueSrv, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + service := newEthereumPaymentObligation(registry, &idService, ðClient, queueSrv, &docService, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil }, txService, func() (uint64, error) { return 10, nil }) ctxh := testingconfig.CreateTenantContext(t, &mockCfg) diff --git a/testworld/nft_test.go b/testworld/nft_test.go index c16f43e83..1fd48b5d2 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -100,7 +100,7 @@ func TestPaymentObligationMint_errors(t *testing.T) { }, }, { - "no service exists for provided documentID", + "document not found in the system database", http.StatusInternalServerError, map[string]interface{}{ diff --git a/testworld/payloads.go b/testworld/payloads.go index 684d6ae76..8084f79bd 100644 --- a/testworld/payloads.go +++ b/testworld/payloads.go @@ -57,12 +57,11 @@ func invoiceNFTPayload(collaborators []string) map[string]interface{} { } -func pONFTPayload(collaborators []string) map[string]interface{} { +func poNFTPayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ "po_number": "123245", "due_date": "2018-09-26T23:12:37.902198664Z", - "gross_amount": "40", "currency": "USD", "net_amount": "40", "document_type": "po", @@ -78,7 +77,7 @@ func defaultNFTPayload(documentType string, collaborators []string) map[string]i case typeInvoice: return invoiceNFTPayload(collaborators) case typePO: - return pONFTPayload(collaborators) + return poNFTPayload(collaborators) default: return invoiceNFTPayload(collaborators) } @@ -99,11 +98,10 @@ func updatedDocumentPayload(documentType string, collaborators []string) map[str func updatedPOPayload(collaborators []string) map[string]interface{} { return map[string]interface{}{ "data": map[string]interface{}{ - "po_number": "12324", - "due_date": "2018-09-26T23:12:37.902198664Z", - "gross_amount": "40", - "currency": "EUR", - "net_amount": "42", + "po_number": "12324", + "due_date": "2018-09-26T23:12:37.902198664Z", + "currency": "EUR", + "net_amount": "42", }, "collaborators": collaborators, } From 6b1b8ef7a8f9a9b465fd85d803549c968a789fca Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 8 Jan 2019 16:18:25 +0100 Subject: [PATCH 120/220] po service using generic service (#623) * added testworld tests for proofs * po service uses generic service * removed old po tests --- documents/invoice/service_test.go | 20 -- documents/purchaseorder/service.go | 187 ++--------------- documents/purchaseorder/service_test.go | 259 +++--------------------- 3 files changed, 50 insertions(+), 416 deletions(-) diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 51cb3b740..e2c185576 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -3,14 +3,12 @@ package invoice import ( - "math/big" "testing" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/gocelery" @@ -292,24 +290,6 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { assert.Equal(t, resp.Data, payload.Data, "data mismatch") } -// Functions returns service mocks -func mockSignatureCheck(i *Invoice, idService testingcommons.MockIDService, invSrv Service) testingcommons.MockIDService { - idkey := ðid.EthereumIdentityKey{ - Key: key1Pub, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) - docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) - mockRepo := invSrv.(service).anchorRepository.(*mockAnchorRepo) - mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - id := &testingcommons.MockID{} - centID, _ := identity.ToCentID(centIDBytes) - idService.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() - return idService -} - func TestService_DeriveFromUpdatePayload(t *testing.T) { _, invSrv := getServiceWithMockedLayers() // nil payload diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 83fb9059d..8f0475500 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -1,19 +1,14 @@ package purchaseorder import ( - "bytes" "context" - "time" "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -21,9 +16,7 @@ import ( clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes" logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) @@ -62,7 +55,7 @@ type service struct { identityService identity.Service queueSrv queue.TaskQueuer txService transactions.Service - genService genericdoc.Service + genericdoc.Service } // DefaultService returns the default implementation of the service @@ -80,7 +73,7 @@ func DefaultService( identityService: identityService, queueSrv: queueSrv, txService: txService, - genService: genService, + Service: genService, } } @@ -290,185 +283,41 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P }, nil } -func (s service) getPurchaseOrderVersion(ctx context.Context, documentID, version []byte) (model *PurchaseOrder, err error) { - self, err := contextutil.Self(ctx) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - doc, err := s.repo.Get(self.ID[:], version) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) - } - model, ok := doc.(*PurchaseOrder) +func (s service) checkType(model documents.Model) (documents.Model, error) { + _, ok := model.(*PurchaseOrder) if !ok { return nil, documents.ErrDocumentInvalidType } - - if !bytes.Equal(model.CoreDocument.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) - } return model, nil } // GetLastVersion returns the latest version of the document -func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { - model, err := s.getPurchaseOrderVersion(ctx, documentID, documentID) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) - } - nextVersion := model.CoreDocument.NextVersion - for nextVersion != nil { - temp, err := s.getPurchaseOrderVersion(ctx, documentID, nextVersion) - if err != nil { - // here the err is returned as nil because it is expected that the nextVersion is not available in the db at some stage of the iteration - return model, nil - } - - model = temp - nextVersion = model.CoreDocument.NextVersion - } - return model, nil -} - -// GetVersion returns the specific version of the document -func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { - po, err := s.getPurchaseOrderVersion(ctx, documentID, version) +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (model documents.Model, err error) { + model, err = s.Service.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } - return po, nil - -} - -// purchaseOrderProof creates proofs for purchaseOrder model fields -func (s service) purchaseOrderProof(model documents.Model, fields []string) (*documents.DocumentProof, error) { - po, ok := model.(*PurchaseOrder) - if !ok { - return nil, documents.ErrDocumentInvalidType - } - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, po); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - coreDoc, proofs, err := po.CreateProofs(fields) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentProof, err) - } - return &documents.DocumentProof{ - DocumentID: coreDoc.DocumentIdentifier, - VersionID: coreDoc.CurrentVersion, - FieldProofs: proofs, - }, nil + return s.checkType(model) } -// CreateProofs generates proofs for given document -func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(ctx, documentID) +// GetVersion returns the specific version of the document +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (model documents.Model, err error) { + model, err = s.Service.GetVersion(ctx, documentID, version) if err != nil { return nil, err } - return s.purchaseOrderProof(model, fields) -} + return s.checkType(model) -// CreateProofsForVersion generates proofs for specific version of the document -func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetVersion(ctx, documentID, version) - if err != nil { - return nil, err - } - return s.purchaseOrderProof(model, fields) -} - -// RequestDocumentSignature validates the document and returns the signature -// Note: this is document agnostic. But since we do not have a common implementation, adding it here. -// will remove this once we have a common implementation for documents.Service -func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { - if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - srvLog.Infof("coredoc received %x with signing root %x", cd.DocumentIdentifier, cd.SigningRoot) - - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigTenantID - } - - idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] - if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) - } - sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, cd.SigningRoot) - cd.Signatures = append(cd.Signatures, sig) - err = model.UnpackCoreDocument(cd) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) - } - - tenantID := idConf.ID[:] - // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(tenantID, cd.DocumentIdentifier) && !utils.IsSameByteSlice(cd.DocumentIdentifier, cd.CurrentVersion) { - err = s.repo.Create(tenantID, cd.DocumentIdentifier, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - } - - err = s.repo.Create(tenantID, cd.CurrentVersion, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - srvLog.Infof("signed coredoc %x with version %x", cd.DocumentIdentifier, cd.CurrentVersion) - return sig, nil -} - -// ReceiveAnchoredDocument validates the anchored document and updates it on DB -// Note: this is document agnostic. But since we do not have a common implementation, adding it here. -// will remove this once we have a common implementation for documents.Service -func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { - self, err := contextutil.Self(ctx) - if err != nil { - return errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) - } - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - doc, err := model.PackCoreDocument() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - err = s.repo.Update(self.ID[:], doc.CurrentVersion, model) - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - ts, _ := ptypes.TimestampProto(time.Now().UTC()) - notificationMsg := ¬ificationpb.NotificationMessage{ - EventType: uint32(notification.ReceivedPayload), - CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), - Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentId: hexutil.Encode(doc.DocumentIdentifier), - } - - // Async until we add queuing - go s.notifier.Send(ctx, notificationMsg) - - return nil } // Exists checks if an purchase order exists func (s service) Exists(ctx context.Context, documentID []byte) bool { - self, err := contextutil.Self(ctx) - if err != nil { - return false + if s.Service.Exists(ctx, documentID) { + // check if document is an po + _, err := s.Service.GetCurrentVersion(ctx, documentID) + if err == nil { + return true + } } - return s.repo.Exists(self.ID[:], documentID) + return false } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index ef11f4194..8c404cdf3 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -3,10 +3,10 @@ package purchaseorder import ( - "math/big" "testing" - "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" @@ -54,7 +54,11 @@ func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) txService := ctx[transactions.BootstrappedService].(transactions.Service) - return idService, DefaultService(testRepo(), &mockAnchorRepo{}, idService, queueSrv, txService, nil) + repo := testRepo() + mockAnchor := &mockAnchorRepo{} + genService := genericdoc.DefaultService(repo, mockAnchor, idService) + + return idService, DefaultService(repo, mockAnchor, idService, queueSrv, txService, genService) } func TestService_Update(t *testing.T) { @@ -131,7 +135,7 @@ func TestService_Update(t *testing.T) { func TestService_DeriveFromUpdatePayload(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{repo: testRepo()} + _, poSrv := getServiceWithMockedLayers() ctxh := testingconfig.CreateTenantContext(t, cfg) // nil payload @@ -291,191 +295,6 @@ func TestService_Create(t *testing.T) { assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) } -func createAnchoredMockDocument(t *testing.T, skipSave bool) (*PurchaseOrder, error) { - i := &PurchaseOrder{ - PoNumber: "test_po", - OrderAmount: 42, - CoreDocument: coredocument.New(), - } - err := i.calculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the purchase order - corDoc, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc) - if err != nil { - return nil, err - } - - centID, err := identity.ToCentID(centIDBytes) - assert.Nil(t, err) - signKey := identity.IDKey{ - PublicKey: key1Pub[:], - PrivateKey: key1, - } - idConfig := &identity.IDConfig{ - ID: centID, - Keys: map[int]identity.IDKey{ - identity.KeyPurposeSigning: signKey, - }, - } - - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) - - corDoc.Signatures = append(corDoc.Signatures, sig) - - err = coredocument.CalculateDocumentRoot(corDoc) - if err != nil { - return nil, err - } - err = i.UnpackCoreDocument(corDoc) - if err != nil { - return nil, err - } - - if !skipSave { - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) - if err != nil { - return nil, err - } - } - - return i, nil -} - -// Functions returns service mocks -func mockSignatureCheck(i *PurchaseOrder, srv *testingcommons.MockIDService, poSrv Service) *testingcommons.MockIDService { - idkey := ðid.EthereumIdentityKey{ - Key: key1Pub, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } - anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) - docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) - mockRepo := poSrv.(service).anchorRepository.(*mockAnchorRepo) - mockRepo.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - id := &testingcommons.MockID{} - centID, _ := identity.ToCentID(centIDBytes) - srv.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() - return srv -} - -func TestService_CreateProofs(t *testing.T) { - idService, poSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, poSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - proof, err := poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) - assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) - assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "po.po_number") -} - -func TestService_CreateProofsValidationFails(t *testing.T) { - idService, poSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - i.CoreDocument.SigningRoot = nil - err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, poSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"po.po_number"}) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "signing root missing") -} - -func TestService_CreateProofsInvalidField(t *testing.T) { - idService, poSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, poSrv) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = poSrv.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) -} - -func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { - _, poSrv := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err := poSrv.CreateProofs(ctxh, utils.RandomSlice(32), []string{"po.po_number"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) -} - -func updatedAnchoredMockDocument(t *testing.T, model *PurchaseOrder) (*PurchaseOrder, error) { - model.OrderAmount = 50 - err := model.calculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the purchase order - corDoc, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - // hacky update to version - corDoc.CurrentVersion = corDoc.NextVersion - corDoc.NextVersion = utils.RandomSlice(32) - if err != nil { - return nil, err - } - err = coredocument.CalculateSigningRoot(corDoc) - if err != nil { - return nil, err - } - err = coredocument.CalculateDocumentRoot(corDoc) - if err != nil { - return nil, err - } - err = model.UnpackCoreDocument(corDoc) - if err != nil { - return nil, err - } - err = testRepo().Create(tenantID, model.CoreDocument.CurrentVersion, model) - if err != nil { - return nil, err - } - return model, nil -} - -func TestService_CreateProofsForVersion(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) - idService, poSrv := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, poSrv) - olderVersion := i.CoreDocument.CurrentVersion - i, err = updatedAnchoredMockDocument(t, i) - assert.Nil(t, err) - proof, err := poSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"po.po_number"}) - assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, olderVersion, proof.VersionID) - assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "po.po_number") -} - -func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { - i, err := createAnchoredMockDocument(t, false) - _, poSrv := getServiceWithMockedLayers() - assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) - _, err = poSrv.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"po.po_number"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) -} - func TestService_DerivePurchaseOrderData(t *testing.T) { var m documents.Model _, poSrv := getServiceWithMockedLayers() @@ -556,10 +375,32 @@ func createMockDocument() (*PurchaseOrder, error) { return model, err } +func TestService_GetVersion_wrongTyp(t *testing.T) { + _, poSrv := getServiceWithMockedLayers() + currentVersion := utils.RandomSlice(32) + documentIdentifier := utils.RandomSlice(32) + + //should be an po + po := &invoice.Invoice{ + GrossAmount: 60, + CoreDocument: &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + }, + } + err := testRepo().Create(tenantID, currentVersion, po) + assert.Nil(t, err) + + ctxh := testingconfig.CreateTenantContext(t, cfg) + _, err = poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) + assert.Error(t, err) + +} + func TestService_GetCurrentVersion(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{repo: testRepo()} + _, poSrv := getServiceWithMockedLayers() thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) @@ -591,32 +432,10 @@ func TestService_GetCurrentVersion(t *testing.T) { assert.Equal(t, poLoad2.CoreDocument.NextVersion, thirdIdentifier) } -func TestService_GetVersion_invalid_version(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{repo: testRepo()} - currentVersion := utils.RandomSlice(32) - - po := &PurchaseOrder{ - OrderAmount: 42, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: utils.RandomSlice(32), - CurrentVersion: currentVersion, - }, - } - err := testRepo().Create(tenantID, currentVersion, po) - assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) - - mod, err := poSrv.GetVersion(ctxh, utils.RandomSlice(32), currentVersion) - assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) - assert.Nil(t, mod) -} - func TestService_GetVersion(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - poSrv := service{repo: testRepo()} + _, poSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) @@ -663,20 +482,6 @@ func TestService_Exists(t *testing.T) { } -func TestService_ReceiveAnchoredDocument(t *testing.T) { - poSrv := service{} - ctxh := testingconfig.CreateTenantContext(t, cfg) - err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) - assert.Error(t, err) -} - -func TestService_RequestDocumentSignature(t *testing.T) { - poSrv := service{} - s, err := poSrv.RequestDocumentSignature(testingconfig.CreateTenantContext(t, cfg), nil) - assert.Nil(t, s) - assert.Error(t, err) -} - func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) From b9be2d5322ef150684450bc5ab4c6095489c6e51 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 9 Jan 2019 11:36:45 +0100 Subject: [PATCH 121/220] P2P review updates (#624) * P2P review updates * review comments * review comments * Final rename --- p2p/bootstrapper.go | 2 +- p2p/client.go | 16 +++++++------- p2p/client_test.go | 20 ++++++++--------- p2p/messenger.go | 50 ++++++++++++++++++++++++------------------- p2p/messenger_test.go | 23 +++++++++++++------- p2p/server.go | 18 ++++++++-------- p2p/server_test.go | 10 ++++----- 7 files changed, 76 insertions(+), 63 deletions(-) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index b802915cf..d381d339a 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -23,7 +23,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("registry not initialised") } - srv := &p2pServer{config: cfg, handlerCreator: func() *receiver.Handler { + srv := &peer{config: cfg, handlerCreator: func() *receiver.Handler { return receiver.New(cfg, registry) }} ctx[bootstrap.BootstrappedP2PServer] = srv diff --git a/p2p/client.go b/p2p/client.go index c4d828331..5693dccb1 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -18,7 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/version" - "github.com/libp2p/go-libp2p-peer" + libp2pPeer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" ma "github.com/multiformats/go-multiaddr" ) @@ -33,7 +33,7 @@ type Client interface { SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) } -func (s *p2pServer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { pid, err := s.getPeerID(id) if err != nil { return nil, err @@ -66,7 +66,7 @@ func (s *p2pServer) SendAnchoredDocument(ctx context.Context, id identity.Identi } // OpenClient returns P2PServiceClient to contact the remote peer -func (s *p2pServer) getPeerID(id identity.Identity) (peer.ID, error) { +func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { lastB58Key, err := id.CurrentP2PKey() if err != nil { return "", errors.New("error fetching p2p key: %v", err) @@ -83,7 +83,7 @@ func (s *p2pServer) getPeerID(id identity.Identity) (peer.ID, error) { return "", err } - peerID, err := peer.IDB58Decode(pid) + peerID, err := libp2pPeer.IDB58Decode(pid) if err != nil { return "", err } @@ -101,7 +101,7 @@ func (s *p2pServer) getPeerID(id identity.Identity) (peer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *p2pServer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer peer.ID, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer libp2pPeer.ID, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { senderID, err := s.config.GetIdentityID() if err != nil { return nil, err @@ -156,7 +156,7 @@ type signatureResponseWrap struct { err error } -func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer peer.ID, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { +func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer libp2pPeer.ID, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { resp, err := s.getSignatureForDocument(ctx, identityService, doc, receiverPeer, receiverCentID) out <- signatureResponseWrap{ resp: resp, @@ -165,7 +165,7 @@ func (s *p2pServer) getSignatureAsync(ctx context.Context, identityService ident } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) @@ -220,7 +220,7 @@ func (s *p2pServer) GetSignaturesForDocument(ctx context.Context, identityServic return nil } -func (s *p2pServer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { +func (s *peer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { h := p2ppb.CentrifugeHeader{ NetworkIdentifier: s.config.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), diff --git a/p2p/client_test.go b/p2p/client_test.go index e16569799..5c2318423 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -11,7 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - "github.com/libp2p/go-libp2p-peer" + libp2pPeer "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -28,7 +28,7 @@ type MockMessenger struct { mock.Mock } -func (mm *MockMessenger) addHandler(mType protocolpb.MessageType, handler func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *protocolpb.P2PEnvelope) (*protocolpb.P2PEnvelope, error)) { +func (mm *MockMessenger) addHandler(mType protocolpb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *protocolpb.P2PEnvelope) (*protocolpb.P2PEnvelope, error)) { mm.Called(mType, handler) } @@ -36,7 +36,7 @@ func (mm *MockMessenger) init(id ...protocol.ID) { mm.Called(id) } -func (mm *MockMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *protocolpb.P2PEnvelope, protoc protocol.ID) (*protocolpb.P2PEnvelope, error) { +func (mm *MockMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *protocolpb.P2PEnvelope, protoc protocol.ID) (*protocolpb.P2PEnvelope, error) { args := mm.Called(ctx, p, pmes, protoc) resp, _ := args.Get(0).(*protocolpb.P2PEnvelope) return resp, args.Error(1) @@ -44,7 +44,7 @@ func (mm *MockMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *proto func TestGetSignatureForDocument_fail_connect(t *testing.T) { m := &MockMessenger{} - testClient := &p2pServer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() @@ -56,7 +56,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(nil, errors.New("some error")) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(nil, errors.New("some error")) resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -65,7 +65,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { func TestGetSignatureForDocument_fail_version_check(t *testing.T) { m := &MockMessenger{} - testClient := &p2pServer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} @@ -78,7 +78,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp("", nil), nil) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp("", nil), nil) resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -88,7 +88,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { m := &MockMessenger{} - testClient := &p2pServer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() ctx := context.Background() @@ -102,7 +102,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, peer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) @@ -113,7 +113,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } -func (s *p2pServer) createSignatureResp(centNodeVer string, signature *coredocumentpb.Signature) *protocolpb.P2PEnvelope { +func (s *peer) createSignatureResp(centNodeVer string, signature *coredocumentpb.Signature) *protocolpb.P2PEnvelope { req := &p2ppb.SignatureResponse{ CentNodeVersion: centNodeVer, Signature: signature, diff --git a/p2p/messenger.go b/p2p/messenger.go index b3ca4fd93..ac7283252 100644 --- a/p2p/messenger.go +++ b/p2p/messenger.go @@ -16,14 +16,20 @@ import ( ggio "github.com/gogo/protobuf/io" "github.com/jbenet/go-context/io" inet "github.com/libp2p/go-libp2p-net" - "github.com/libp2p/go-libp2p-peer" + libp2pPeer "github.com/libp2p/go-libp2p-peer" ) -// ErrReadTimeout must be used when receiving timeout while reading -const ErrReadTimeout = errors.Error("timed out reading response") +const ( -// ErrInvalidatedMessageSender must be used when the message sender object created is no longer valid (connection has dropped) -const ErrInvalidatedMessageSender = errors.Error("message sender has been invalidated") + // MessageSizeMax is a soft maximum for network messages. + MessageSizeMax = 1 << 25 // 32 MB + + // ErrReadTimeout must be used when receiving timeout while reading + ErrReadTimeout = errors.Error("timed out reading response") + + // ErrInvalidatedMessageSender must be used when the message sender object created is no longer valid (connection has dropped) + ErrInvalidatedMessageSender = errors.Error("message sender has been invalidated") +) type bufferedWriteCloser interface { ggio.WriteCloser @@ -51,18 +57,18 @@ func (w *bufferedDelimitedWriter) Flush() error { } type p2pMessenger struct { - host host.Host // the network services we need - self peer.ID // Local peer (yourself) + host host.Host // the network services we need + self libp2pPeer.ID // Local peer (yourself) - timout time.Duration - ctx context.Context + timeout time.Duration + ctx context.Context - strmap map[peer.ID]map[protocol.ID]*messageSender + strmap map[libp2pPeer.ID]map[protocol.ID]*messageSender smlk sync.Mutex plk sync.Mutex - msgHandlers map[pb.MessageType]func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) + msgHandlers map[pb.MessageType]func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) } func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration) *p2pMessenger { @@ -70,9 +76,9 @@ func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Durati ctx: ctx, host: host, self: host.ID(), - timout: p2pTimeout, - strmap: make(map[peer.ID]map[protocol.ID]*messageSender), - msgHandlers: make(map[pb.MessageType]func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error))} + timeout: p2pTimeout, + strmap: make(map[libp2pPeer.ID]map[protocol.ID]*messageSender), + msgHandlers: make(map[pb.MessageType]func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error))} } // init initiates listening to given set of protocol streams @@ -83,7 +89,7 @@ func (mes *p2pMessenger) init(protocols ...protocol.ID) { } // addHandler adds a message handler for a specific message type -func (mes *p2pMessenger) addHandler(mType pb.MessageType, handler func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) { +func (mes *p2pMessenger) addHandler(mType pb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) { mes.msgHandlers[mType] = handler } @@ -99,7 +105,7 @@ func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { cw := ctxio.NewWriter(ctx, s) // delimited readers and writers to set length of the protobuf messages to the stream - r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax) + r := ggio.NewDelimitedReader(cr, MessageSizeMax) w := newBufferedDelimitedWriter(cw) mPeer := s.Conn().RemotePeer() @@ -153,7 +159,7 @@ func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { } // sendMessage sends out a request -func (mes *p2pMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) { +func (mes *p2pMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) { ms, err := mes.messageSenderForPeerAndProto(p, protoc) if err != nil { return nil, err @@ -167,7 +173,7 @@ func (mes *p2pMessenger) sendMessage(ctx context.Context, p peer.ID, pmes *pb.P2 return rpmes, nil } -func (mes *p2pMessenger) messageSenderForPeerAndProto(p peer.ID, protoc protocol.ID) (*messageSender, error) { +func (mes *p2pMessenger) messageSenderForPeerAndProto(p libp2pPeer.ID, protoc protocol.ID) (*messageSender, error) { mes.smlk.Lock() ms, ok := mes.strmap[p][protoc] if ok { @@ -209,7 +215,7 @@ type messageSender struct { r ggio.ReadCloser w bufferedWriteCloser lk sync.Mutex - p peer.ID + p libp2pPeer.ID protoc protocol.ID mes *p2pMessenger @@ -247,14 +253,14 @@ func (ms *messageSender) prep() error { } // set the p2p timeout as the connection timeout - timeoutCtx, canc := context.WithTimeout(ms.mes.ctx, ms.mes.timout) + timeoutCtx, canc := context.WithTimeout(ms.mes.ctx, ms.mes.timeout) nstr, err := ms.mes.host.NewStream(timeoutCtx, ms.p, ms.protoc) if err != nil { canc() return err } - ms.r = ggio.NewDelimitedReader(nstr, inet.MessageSizeMax) + ms.r = ggio.NewDelimitedReader(nstr, MessageSizeMax) ms.w = newBufferedDelimitedWriter(nstr) ms.s = nstr @@ -328,7 +334,7 @@ func (ms *messageSender) ctxReadMsg(ctx context.Context, mes *pb.P2PEnvelope) er errc <- r.ReadMsg(mes) }(ms.r) - t := time.NewTimer(ms.mes.timout) + t := time.NewTimer(ms.mes.timeout) defer t.Stop() select { diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go index d23b28463..1456159a3 100644 --- a/p2p/messenger_test.go +++ b/p2p/messenger_test.go @@ -16,7 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/libp2p/go-libp2p-crypto" "github.com/libp2p/go-libp2p-host" - "github.com/libp2p/go-libp2p-peer" + libp2pPeer "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" "github.com/stretchr/testify/assert" ) @@ -38,22 +38,22 @@ func TestHandleNewMessage(t *testing.T) { _ = runDHT(c, h1, []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", p2, h2.ID().Pretty())}) m1 := newP2PMessenger(c, h1, 1*time.Second) - m1.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + m1.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP}, nil }) m2 := newP2PMessenger(c, h2, 1*time.Second) - m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP}, nil }) - m2.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + m2.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC}, nil }) // error - m2.addHandler(pb.MessageType_MESSAGE_TYPE_ERROR, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + m2.addHandler(pb.MessageType_MESSAGE_TYPE_ERROR, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { return nil, errors.New("dummy error") }) // nil response - message type here is irrelevant using the reply type for convenience - m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { return nil, nil }) @@ -62,8 +62,8 @@ func TestHandleNewMessage(t *testing.T) { m2.init(MessengerDummyProtocol2) // 1. happy path - // from h1 to h2 - msg, err := m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + // from h1 to h2 (with a message size ~ MessageSizeMax, has to be less because of the length bytes) + msg, err := m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(MessageSizeMax - 7)}, MessengerDummyProtocol) assert.NoError(t, err) assert.Equal(t, pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, msg.Type) // from h1 to h2 different protocol - intentionally setting reply-response in opposite for differentiation @@ -104,6 +104,13 @@ func TestHandleNewMessage(t *testing.T) { if assert.Error(t, err) { assert.Equal(t, "timed out reading response", err.Error()) } + + // 7. message size more than the max + // from h1 to h2 (with a message size > MessageSizeMax) + msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(MessageSizeMax)}, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } canc() } diff --git a/p2p/server.go b/p2p/server.go index d58550788..5a4558314 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -22,7 +22,7 @@ import ( "github.com/libp2p/go-libp2p-crypto" "github.com/libp2p/go-libp2p-host" "github.com/libp2p/go-libp2p-kad-dht" - "github.com/libp2p/go-libp2p-peer" + libp2pPeer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" ma "github.com/multiformats/go-multiaddr" mh "github.com/multiformats/go-multihash" @@ -46,15 +46,15 @@ type Config interface { // messenger is an interface to wrap p2p messaging implementation type messenger interface { - addHandler(mType pb.MessageType, handler func(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) + addHandler(mType pb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) init(protocols ...protocol.ID) - sendMessage(ctx context.Context, p peer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) + sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) } -// p2pServer implements api.Server -type p2pServer struct { +// peer implements node.Server +type peer struct { // TODO [multi-tenancy] replace this with config service config Config host host.Host @@ -63,12 +63,12 @@ type p2pServer struct { } // Name returns the P2PServer -func (*p2pServer) Name() string { +func (*peer) Name() string { return "P2PServer" } // Start starts the DHT and libp2p host -func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { +func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { defer wg.Done() if s.config.GetP2PPort() == 0 { @@ -101,7 +101,7 @@ func (s *p2pServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr ch } -func (s *p2pServer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { +func (s *peer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { // Create the signing key for the host publicKey, privateKey, err := cented25519.GetSigningKeyPair(s.config.GetSigningKeyPair()) if err != nil { @@ -128,7 +128,7 @@ func makeBasicHost(priv crypto.PrivKey, pub crypto.PubKey, externalIP string, li // secio when adding the pub and pvt keys, fail as id+pub/pvt key is checked to match and method defaults to // IDFromPublicKey(pk) //pid, err := peer.IDFromEd25519PublicKey(pub) - pid, err := peer.IDFromPublicKey(pub) + pid, err := libp2pPeer.IDFromPublicKey(pub) if err != nil { return nil, err } diff --git a/p2p/server_test.go b/p2p/server_test.go index 790424827..0c216d218 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -49,7 +49,7 @@ func TestMain(m *testing.M) { func TestCentP2PServer_StartContextCancel(t *testing.T) { cfg.Set("p2p.port", 38203) - cp2p := &p2pServer{config: cfg, handlerCreator: func() *receiver.Handler { + cp2p := &peer{config: cfg, handlerCreator: func() *receiver.Handler { return receiver.New(cfg, nil) }} ctx, canc := context.WithCancel(context.Background()) @@ -67,7 +67,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { func TestCentP2PServer_StartListenError(t *testing.T) { // cause an error by using an invalid port cfg.Set("p2p.port", 100000000) - cp2p := &p2pServer{config: cfg} + cp2p := &peer{config: cfg} ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -81,7 +81,7 @@ func TestCentP2PServer_StartListenError(t *testing.T) { func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { listenPort := 38202 - cp2p := &p2pServer{config: cfg} + cp2p := &peer{config: cfg} priv, pub, err := cp2p.createSigningKey() h, err := makeBasicHost(priv, pub, "", listenPort) assert.Nil(t, err) @@ -91,7 +91,7 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 - cp2p := &p2pServer{config: cfg} + cp2p := &peer{config: cfg} priv, pub, err := cp2p.createSigningKey() h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.Nil(t, err) @@ -105,7 +105,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 - cp2p := &p2pServer{config: cfg} + cp2p := &peer{config: cfg} priv, pub, err := cp2p.createSigningKey() h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.NotNil(t, err) From 8697a9b75b6b6021c274ebf7815a2e85f713d44a Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 10 Jan 2019 08:50:59 +0100 Subject: [PATCH 122/220] P2P - tenant <--> protocol mapping (#626) --- p2p/bootstrapper.go | 9 ++- p2p/client.go | 28 ++++++-- p2p/client_test.go | 31 ++++++--- p2p/receiver/handler.go | 87 ++++++++++++------------ p2p/receiver/handler_integration_test.go | 39 +++++++---- p2p/receiver/handler_test.go | 12 ++-- p2p/receiver/protocol.go | 24 +++++++ p2p/receiver/protocol_test.go | 26 +++++++ p2p/receiver/validator.go | 3 +- p2p/receiver/validator_test.go | 2 +- p2p/server.go | 58 +++++++++------- p2p/server_test.go | 45 ++++++++---- resources/data.go | 2 +- 13 files changed, 245 insertions(+), 121 deletions(-) create mode 100644 p2p/receiver/protocol.go create mode 100644 p2p/receiver/protocol_test.go diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index d381d339a..2b3318399 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -18,13 +18,18 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } + cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + if !ok { + return errors.New("configstore not initialised") + } + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { return errors.New("registry not initialised") } - srv := &peer{config: cfg, handlerCreator: func() *receiver.Handler { - return receiver.New(cfg, registry) + srv := &peer{config: cfgService, handlerCreator: func() *receiver.Handler { + return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) }} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[bootstrap.BootstrappedP2PClient] = srv diff --git a/p2p/client.go b/p2p/client.go index 5693dccb1..22e23cfa0 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/golang/protobuf/proto" @@ -43,8 +45,10 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i return nil, err } - // TODO [multi-tenancy] modify the protocol id here to include the centID of the receiving node - recv, err := s.mes.sendMessage(ctx, pid, &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, CentrifugeProtocol) + recv, err := s.mes.sendMessage( + ctx, pid, + &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, + receiver.ProtocolForCID(id.CentID())) if err != nil { return nil, err } @@ -102,18 +106,18 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { // getSignatureForDocument requests the target node to sign the document func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer libp2pPeer.ID, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { - senderID, err := s.config.GetIdentityID() + self, err := contextutil.Self(ctx) if err != nil { return nil, err } - req, err := s.createSignatureRequest(senderID, &doc) + req, err := s.createSignatureRequest(self.ID[:], &doc) if err != nil { return nil, err } log.Infof("Requesting signature from %s\n", receiverCentID) - recv, err := s.mes.sendMessage(ctx, receiverPeer, req, CentrifugeProtocol) + recv, err := s.mes.sendMessage(ctx, receiverPeer, req, receiver.ProtocolForCID(receiverCentID)) if err != nil { return nil, err } @@ -169,6 +173,11 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide in := make(chan signatureResponseWrap) defer close(in) + nc, err := s.config.GetConfig() + if err != nil { + return err + } + self, err := contextutil.Self(ctx) if err != nil { return centerrors.Wrap(err, "failed to get self") @@ -199,7 +208,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide // for now going with context.background, once we have a timeout for request // we can use context.Timeout for that count++ - c, _ := context.WithTimeout(ctx, s.config.GetP2PConnectionTimeout()) + c, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) go s.getSignatureAsync(c, identityService, *doc, receiverPeer, collaboratorID, in) } @@ -221,8 +230,13 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide } func (s *peer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { + nc, err := s.config.GetConfig() + if err != nil { + return nil, err + } + h := p2ppb.CentrifugeHeader{ - NetworkIdentifier: s.config.GetNetworkID(), + NetworkIdentifier: nc.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), SenderCentrifugeId: senderID, } diff --git a/p2p/client_test.go b/p2p/client_test.go index 5c2318423..428c32a4e 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -6,6 +6,10 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/golang/protobuf/proto" "github.com/centrifuge/go-centrifuge/errors" @@ -46,17 +50,20 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { m := &MockMessenger{} testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() - ctx := context.Background() + c, err := cfg.GetConfig() + assert.NoError(t, err) + ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - sender, err := cfg.GetIdentityID() + assert.NoError(t, err) + sender, err := c.GetIdentityID() assert.Nil(t, err, "sender centrifugeId not initialized correctly ") r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(nil, errors.New("some error")) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -67,18 +74,21 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { m := &MockMessenger{} testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() - ctx := context.Background() + c, err := cfg.GetConfig() + assert.NoError(t, err) + ctx := testingconfig.CreateTenantContext(t, c) resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - sender, err := cfg.GetIdentityID() + assert.NoError(t, err) + sender, err := c.GetIdentityID() assert.Nil(t, err, "sender centrifugeId not initialized correctly ") r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp("", nil), nil) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -90,19 +100,22 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { m := &MockMessenger{} testClient := &peer{config: cfg, mes: m} coreDoc := testingcoredocument.GenerateCoreDocument() - ctx := context.Background() + c, err := cfg.GetConfig() + assert.NoError(t, err) + ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") - sender, err := cfg.GetIdentityID() + assert.NoError(t, err) + sender, err := c.GetIdentityID() assert.Nil(t, err, "sender centrifugeId not initialized correctly ") r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, CentrifugeProtocol).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 89b6605ed..db9323afb 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -2,31 +2,25 @@ package receiver import ( "context" - "fmt" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/version" - logging "github.com/ipfs/go-log" ) -var log = logging.Logger("grpc") - // getService looks up the specific registry, derives service from core document func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { if cd == nil { @@ -50,15 +44,16 @@ func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb. return srv, model, nil } -// Handler implements the grpc interface +// Handler implements protocol message handlers type Handler struct { - registry *documents.ServiceRegistry - config config.Configuration + registry *documents.ServiceRegistry + config configstore.Service + handshakeValidator ValidatorGroup } // New returns an implementation of P2PServiceServer -func New(config config.Configuration, registry *documents.ServiceRegistry) *Handler { - return &Handler{registry: registry, config: config} +func New(config configstore.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup) *Handler { + return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator} } // HandleRequestDocumentSignature handles the RequestDocumentSignature message @@ -66,7 +61,22 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee m := new(p2ppb.SignatureRequest) err := proto.Unmarshal(msg.Body, m) if err != nil { - return nil, err + return convertToErrorEnvelop(err) + } + + cid, err := ExtractCID(protoc) + if err != nil { + return convertToErrorEnvelop(err) + } + + tc, err := srv.config.GetTenant(cid[:]) + if err != nil { + return convertToErrorEnvelop(err) + } + + ctx, err = contextutil.NewCentrifugeContext(ctx, tc) + if err != nil { + return convertToErrorEnvelop(err) } res, err := srv.RequestDocumentSignature(ctx, m) @@ -76,7 +86,7 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee resp, err := proto.Marshal(res) if err != nil { - return nil, err + return convertToErrorEnvelop(err) } return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, Body: resp}, nil } @@ -86,18 +96,7 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", srv.config) - if err != nil { - log.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) - if err != nil { - log.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - err = handshakeValidator(srv.config.GetNetworkID()).Validate(sigReq.Header) + err := srv.handshakeValidator.Validate(sigReq.Header) if err != nil { return nil, err } @@ -107,7 +106,7 @@ func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb. return nil, centerrors.New(code.DocumentInvalid, err.Error()) } - signature, err := svc.RequestDocumentSignature(ctxHeader, model) + signature, err := svc.RequestDocumentSignature(ctx, model) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -123,7 +122,22 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID m := new(p2ppb.AnchorDocumentRequest) err := proto.Unmarshal(msg.Body, m) if err != nil { - return nil, err + return convertToErrorEnvelop(err) + } + + cid, err := ExtractCID(protoc) + if err != nil { + return convertToErrorEnvelop(err) + } + + tc, err := srv.config.GetTenant(cid[:]) + if err != nil { + return convertToErrorEnvelop(err) + } + + ctx, err = contextutil.NewCentrifugeContext(ctx, tc) + if err != nil { + return convertToErrorEnvelop(err) } res, err := srv.SendAnchoredDocument(ctx, m) @@ -133,25 +147,14 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID resp, err := proto.Marshal(res) if err != nil { - return nil, err + return convertToErrorEnvelop(err) } return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, Body: resp}, nil } // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { - // TODO [multi-tenancy] remove following and read the config from the context - tc, err := configstore.NewTenantConfig("", srv.config) - if err != nil { - log.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - ctxHeader, err := contextutil.NewCentrifugeContext(ctx, tc) - if err != nil { - log.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - err = handshakeValidator(srv.config.GetNetworkID()).Validate(docReq.Header) + err := srv.handshakeValidator.Validate(docReq.Header) if err != nil { return nil, err } @@ -161,7 +164,7 @@ func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.Anch return nil, centerrors.New(code.DocumentInvalid, err.Error()) } - err = svc.ReceiveAnchoredDocument(ctxHeader, model, docReq.Header) + err = svc.ReceiveAnchoredDocument(ctx, model, docReq.Header) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index d2b52ca49..0f6e8b18a 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -38,7 +40,7 @@ import ( ) var ( - handler p2ppb.P2PServiceServer + handler *receiver.Handler anchorRepo anchors.AnchorRepository cfg config.Configuration idService identity.Service @@ -48,10 +50,11 @@ func TestMain(m *testing.M) { flag.Parse() ctx := cc.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[ethid.BootstrappedIDService].(identity.Service) - handler = receiver.New(cfg, registry) + handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() cc.TestFunctionalEthereumTearDown() @@ -59,10 +62,11 @@ func TestMain(m *testing.M) { } func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) doc.SigningRoot = nil req := getSignatureRequest(doc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.NotNil(t, err, "must be non nil") assert.Nil(t, resp, "must be nil") assert.Contains(t, err.Error(), "signing root missing") @@ -71,20 +75,22 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + ctxh := testingconfig.CreateTenantContext(t, cfg) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") req = getSignatureRequest(doc) - resp, err = handler.RequestDocumentSignature(context.Background(), req) + resp, err = handler.RequestDocumentSignature(ctxh, req) assert.NotNil(t, err, "must not be nil") assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists.Error()) } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") @@ -96,7 +102,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { updateDocumentForP2Phandler(t, newDoc) newDoc = prepareDocumentForP2PHandler(t, newDoc) req = getSignatureRequest(newDoc) - resp, err = handler.RequestDocumentSignature(context.Background(), req) + resp, err = handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") @@ -105,6 +111,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { } func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) newDoc, err := coredocument.PrepareNewVersion(*doc, nil) assert.Nil(t, err) @@ -112,7 +119,7 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T updateDocumentForP2Phandler(t, newDoc) newDoc = prepareDocumentForP2PHandler(t, newDoc) req := getSignatureRequest(newDoc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") @@ -121,9 +128,10 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T } func TestHandler_RequestDocumentSignature(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") @@ -150,27 +158,29 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") anchorReq := getAnchoredRequest(doc) - anchorResp, err := handler.SendAnchoredDocument(context.Background(), anchorReq) + anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) assert.Nil(t, anchorResp) } func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getAnchoredRequest(doc) req.Document = nil - resp, err := handler.SendAnchoredDocument(context.Background(), req) + resp, err := handler.SendAnchoredDocument(ctxh, req) assert.NotNil(t, err) assert.Nil(t, resp, "must be nil") } func TestHandler_SendAnchoredDocument(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) centrifugeId := createIdentity(t) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) - resp, err := handler.RequestDocumentSignature(context.Background(), req) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) assert.NotNil(t, resp) @@ -185,15 +195,14 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - ctx := testingconfig.CreateTenantContext(t, cfg) - anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") anchorReq := getAnchoredRequest(doc) - anchorResp, err := handler.SendAnchoredDocument(context.Background(), anchorReq) + anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") assert.True(t, anchorResp.Accepted) diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 72d1ba48f..89d1b7e34 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -8,6 +8,8 @@ import ( "strconv" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -40,6 +42,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, documents.Bootstrapper{}, @@ -47,12 +50,9 @@ func TestMain(m *testing.M) { ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.signing.publicKey", "../../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") + cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - grpcHandler = New(cfg, registry) + grpcHandler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -150,7 +150,7 @@ func TestP2PService_basicChecks(t *testing.T) { } for _, c := range tests { - err := handshakeValidator(cfg.GetNetworkID()).Validate(c.header) + err := HandshakeValidator(cfg.GetNetworkID()).Validate(c.header) if err != nil { if c.err == nil { t.Fatalf("unexpected error: %v\n", err) diff --git a/p2p/receiver/protocol.go b/p2p/receiver/protocol.go new file mode 100644 index 000000000..0cf8786e2 --- /dev/null +++ b/p2p/receiver/protocol.go @@ -0,0 +1,24 @@ +package receiver + +import ( + "fmt" + "strings" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/libp2p/go-libp2p-protocol" +) + +// CentrifugeProtocol is the centrifuge wire protocol +const CentrifugeProtocol protocol.ID = "/centrifuge/0.0.1" + +// ProtocolForCID creates the protocol string for the given CID +func ProtocolForCID(CID identity.CentID) protocol.ID { + return protocol.ID(fmt.Sprintf("%s/%s", CentrifugeProtocol, CID.String())) +} + +// ExtractCID extracts CID from a protocol string +func ExtractCID(id protocol.ID) (identity.CentID, error) { + parts := strings.Split(string(id), "/") + cidHexStr := parts[len(parts)-1] + return identity.CentIDFromString(cidHexStr) +} diff --git a/p2p/receiver/protocol_test.go b/p2p/receiver/protocol_test.go new file mode 100644 index 000000000..8a98bdf92 --- /dev/null +++ b/p2p/receiver/protocol_test.go @@ -0,0 +1,26 @@ +package receiver + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/libp2p/go-libp2p-protocol" + "github.com/stretchr/testify/assert" +) + +func TestExtractCID(t *testing.T) { + p := protocol.ID("/centrifuge/0.0.1/0xd9f72e705074") + cid, err := ExtractCID(p) + assert.NoError(t, err) + assert.Equal(t, "0xd9f72e705074", cid.String()) +} + +func TestProtocolForCID(t *testing.T) { + cid := identity.RandomCentID() + p := ProtocolForCID(cid) + assert.Contains(t, p, cid.String()) + cidE, err := ExtractCID(p) + assert.NoError(t, err) + assert.Equal(t, cid.String(), cidE.String()) +} diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 84bdd7003..0bfe03ca8 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -63,7 +63,8 @@ func networkValidator(networkID uint32) Validator { }) } -func handshakeValidator(networkID uint32) ValidatorGroup { +// HandshakeValidator validates the p2p handshake details +func HandshakeValidator(networkID uint32) ValidatorGroup { return ValidatorGroup{ versionValidator(), networkValidator(networkID), diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index c21b89482..5d8ac9329 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -61,7 +61,7 @@ func TestValidate_networkValidator(t *testing.T) { } func TestValidate_handshakeValidator(t *testing.T) { - hv := handshakeValidator(cfg.GetNetworkID()) + hv := HandshakeValidator(cfg.GetNetworkID()) // Incompatible version and network header := &p2ppb.CentrifugeHeader{ diff --git a/p2p/server.go b/p2p/server.go index 5a4558314..252ad66ee 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -6,6 +6,10 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/p2p/receiver" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" @@ -30,20 +34,6 @@ import ( var log = logging.Logger("p2p-server") -// CentrifugeProtocol is the centrifuge wire protocol -const CentrifugeProtocol protocol.ID = "/centrifuge/0.0.1" - -// Config defines methods that are required for the package p2p. -type Config interface { - GetP2PExternalIP() string - GetP2PPort() int - GetBootstrapPeers() []string - GetP2PConnectionTimeout() time.Duration - GetNetworkID() uint32 - GetIdentityID() ([]byte, error) - GetSigningKeyPair() (pub, priv string) -} - // messenger is an interface to wrap p2p messaging implementation type messenger interface { addHandler(mType pb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) @@ -55,8 +45,7 @@ type messenger interface { // peer implements node.Server type peer struct { - // TODO [multi-tenancy] replace this with config service - config Config + config configstore.Service host host.Host handlerCreator func() *receiver.Handler mes messenger @@ -71,39 +60,60 @@ func (*peer) Name() string { func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- error) { defer wg.Done() - if s.config.GetP2PPort() == 0 { + nc, err := s.config.GetConfig() + if err != nil { + startupErr <- err + return + } + + if nc.GetP2PPort() == 0 { startupErr <- errors.New("please provide a port to bind on") return } // Make a host that listens on the given multiaddress // first obtain the keys configured - priv, pub, err := s.createSigningKey() + priv, pub, err := s.createSigningKey(nc.GetSigningKeyPair()) if err != nil { startupErr <- err return } - s.host, err = makeBasicHost(priv, pub, s.config.GetP2PExternalIP(), s.config.GetP2PPort()) + s.host, err = makeBasicHost(priv, pub, nc.GetP2PExternalIP(), nc.GetP2PPort()) if err != nil { startupErr <- err return } - s.mes = newP2PMessenger(ctx, s.host, s.config.GetP2PConnectionTimeout()) + s.mes = newP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout()) handler := s.handlerCreator() s.mes.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, handler.HandleSendAnchoredDocument) s.mes.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, handler.HandleRequestDocumentSignature) - s.mes.init(CentrifugeProtocol) + + tcs, err := s.config.GetAllTenants() + if err != nil { + startupErr <- err + return + } + var protocols []protocol.ID + for _, t := range tcs { + CID, err := identity.ToCentID(t.IdentityID) + if err != nil { + startupErr <- err + return + } + protocols = append(protocols, receiver.ProtocolForCID(CID)) + } + s.mes.init(protocols...) // Start DHT and properly ignore errors :) - _ = runDHT(ctx, s.host, s.config.GetBootstrapPeers()) + _ = runDHT(ctx, s.host, nc.GetBootstrapPeers()) <-ctx.Done() } -func (s *peer) createSigningKey() (priv crypto.PrivKey, pub crypto.PubKey, err error) { +func (s *peer) createSigningKey(pubKey, privKey string) (priv crypto.PrivKey, pub crypto.PubKey, err error) { // Create the signing key for the host - publicKey, privateKey, err := cented25519.GetSigningKeyPair(s.config.GetSigningKeyPair()) + publicKey, privateKey, err := cented25519.GetSigningKeyPair(pubKey, privKey) if err != nil { return nil, nil, errors.New("failed to get keys: %v", err) } diff --git a/p2p/server_test.go b/p2p/server_test.go index 0c216d218..b4f021902 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" @@ -23,7 +25,7 @@ import ( ) var ( - cfg config.Configuration + cfg configstore.Service ) func TestMain(m *testing.M) { @@ -31,26 +33,33 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &storage.Bootstrapper{}, + &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, documents.Bootstrapper{}, } ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + cfg = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + c, _ := cfg.GetConfig() + c.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" + c.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" + c.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" + c.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" + cfg.UpdateConfig(c) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) } func TestCentP2PServer_StartContextCancel(t *testing.T) { - cfg.Set("p2p.port", 38203) + c, err := cfg.GetConfig() + assert.NoError(t, err) + c.P2PPort = 38203 + _, err = cfg.UpdateConfig(c) + assert.NoError(t, err) cp2p := &peer{config: cfg, handlerCreator: func() *receiver.Handler { - return receiver.New(cfg, nil) + return receiver.New(cfg, nil, receiver.HandshakeValidator(c.NetworkID)) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) @@ -66,33 +75,41 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { func TestCentP2PServer_StartListenError(t *testing.T) { // cause an error by using an invalid port - cfg.Set("p2p.port", 100000000) + c, err := cfg.GetConfig() + assert.NoError(t, err) + c.P2PPort = 100000000 + _, err = cfg.UpdateConfig(c) + assert.NoError(t, err) cp2p := &peer{config: cfg} ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup wg.Add(1) go cp2p.Start(ctx, &wg, startErr) - err := <-startErr + err = <-startErr wg.Wait() assert.NotNil(t, err, "Error should be not nil") assert.Equal(t, "failed to parse tcp: 100000000 failed to parse port addr: greater than 65536", err.Error()) } func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { + c, err := cfg.GetConfig() + assert.NoError(t, err) listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey() + priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) h, err := makeBasicHost(priv, pub, "", listenPort) assert.Nil(t, err) assert.NotNil(t, h) } func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { + c, err := cfg.GetConfig() + assert.NoError(t, err) externalIP := "100.100.100.100" listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey() + priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -103,10 +120,12 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { } func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { + c, err := cfg.GetConfig() + assert.NoError(t, err) externalIP := "100.200.300.400" listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey() + priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.NotNil(t, err) assert.Nil(t, h) diff --git a/resources/data.go b/resources/data.go index 4550a41ce..ab66c7b4b 100644 --- a/resources/data.go +++ b/resources/data.go @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - From 958e306b6fae52541050d263063e7fb54e938f7e Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 10 Jan 2019 17:00:51 +0100 Subject: [PATCH 123/220] NFT: fix async testcase (#628) * added testworld tests for proofs * async nft testcase --- testworld/nft_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 1fd48b5d2..a7d2c72d4 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/assert" ) -const tokenIdLength = 77 - func TestPaymentObligationMint_invoice_successful(t *testing.T) { t.Parallel() paymentObligationMint(t, typeInvoice) @@ -68,8 +66,11 @@ func paymentObligationMint(t *testing.T, documentType string) { } response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + txID = getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) + assert.Nil(t, err, "mintNFT should be successful") - assert.True(t, len(response.Value("token_id").String().Raw()) >= tokenIdLength, "successful tokenId should have length 77") + assert.True(t, len(response.Value("token_id").String().Raw()) > 0, "successful tokenId should have length 77") } From 76afa1061d36510a1713d44d04e6b565a2fa6965 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 11 Jan 2019 14:49:28 +0100 Subject: [PATCH 124/220] Support local tenant loops (#627) * P2P - tenant <--> protocol mapping * Support local tenant loops * Add tests * Fix test * Fix test * Review comments --- p2p/client.go | 112 +++++++++++++++------- p2p/client_integration_test.go | 115 +++++++++++++++++++++++ p2p/client_test.go | 34 ++++--- p2p/receiver/handler_integration_test.go | 6 +- p2p/server.go | 9 +- testingutils/identity/identity.go | 36 +++++++ 6 files changed, 259 insertions(+), 53 deletions(-) create mode 100644 p2p/client_integration_test.go diff --git a/p2p/client.go b/p2p/client.go index 22e23cfa0..fa2ff2325 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -36,17 +36,38 @@ type Client interface { } func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { + nc, err := s.config.GetConfig() + if err != nil { + return nil, err + } + + peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) + cid := id.CentID() + tc, err := s.config.GetTenant(cid[:]) + if err == nil { + // this is a local tenant + h := s.handlerCreator() + // the following context has to be different from the parent context since its initiating a local peer call + localCtx, err := contextutil.NewCentrifugeContext(peerCtx, tc) + if err != nil { + return nil, err + } + return h.SendAnchoredDocument(localCtx, in) + } + + // this is a remote tenant pid, err := s.getPeerID(id) if err != nil { return nil, err } + marshalledRequest, err := proto.Marshal(in) if err != nil { return nil, err } recv, err := s.mes.sendMessage( - ctx, pid, + peerCtx, pid, &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, receiver.ProtocolForCID(id.CentID())) if err != nil { @@ -92,26 +113,54 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { return "", err } - // Decapsulate the /ipfs/ part from the target - // /ip4//ipfs/ becomes /ip4/ - targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", pid)) - targetAddr := ipfsAddr.Decapsulate(targetPeerAddr) - - // We have a peer ID and a targetAddr so we add it to the peer store - // so LibP2P knows how to contact it - s.host.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) + if !s.disablePeerStore { + // Decapsulate the /ipfs/ part from the target + // /ip4//ipfs/ becomes /ip4/ + targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", pid)) + targetAddr := ipfsAddr.Decapsulate(targetPeerAddr) + // We have a peer ID and a targetAddr so we add it to the peer store + // so LibP2P knows how to contact it + s.host.Peerstore().AddAddr(peerID, targetAddr, pstore.PermanentAddrTTL) + } return peerID, nil } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer libp2pPeer.ID, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { self, err := contextutil.Self(ctx) if err != nil { return nil, err } + tc, err := s.config.GetTenant(receiverCentID[:]) + if err == nil { + // this is a local tenant + h := s.handlerCreator() + // create a context with receiving tenant value + localPeerCtx, err := contextutil.NewCentrifugeContext(ctx, tc) + if err != nil { + return nil, err + } + req, err := s.sigRequest(self.ID[:], doc) + if err != nil { + return nil, err + } + + return h.RequestDocumentSignature(localPeerCtx, req) + } + + // this is a remote tenant + id, err := identityService.LookupIdentityForID(receiverCentID) + if err != nil { + return nil, err + } + + receiverPeer, err := s.getPeerID(id) + if err != nil { + return nil, err + } - req, err := s.createSignatureRequest(self.ID[:], &doc) + req, err := s.createSignatureRequest(self.ID[:], doc) if err != nil { return nil, err } @@ -160,8 +209,8 @@ type signatureResponseWrap struct { err error } -func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverPeer libp2pPeer.ID, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, identityService, doc, receiverPeer, receiverCentID) +func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, identityService, doc, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, @@ -189,27 +238,14 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide } var count int + peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) for _, collaborator := range extCollaborators { collaboratorID, err := identity.ToCentID(collaborator) if err != nil { return centerrors.Wrap(err, "failed to convert to CentID") } - id, err := identityService.LookupIdentityForID(collaboratorID) - if err != nil { - return centerrors.Wrap(err, "error fetching collaborator identity") - } - - receiverPeer, err := s.getPeerID(id) - if err != nil { - log.Error(centerrors.Wrap(err, "failed to connect to target")) - continue - } - - // for now going with context.background, once we have a timeout for request - // we can use context.Timeout for that count++ - c, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) - go s.getSignatureAsync(c, identityService, *doc, receiverPeer, collaboratorID, in) + go s.getSignatureAsync(peerCtx, identityService, doc, collaboratorID, in) } var responses []signatureResponseWrap @@ -230,11 +266,22 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide } func (s *peer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { - nc, err := s.config.GetConfig() + req, err := s.sigRequest(senderID, doc) + if err != nil { + return nil, err + } + reqB, err := proto.Marshal(req) if err != nil { return nil, err } + return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: reqB}, nil +} +func (s *peer) sigRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*p2ppb.SignatureRequest, error) { + nc, err := s.config.GetConfig() + if err != nil { + return nil, err + } h := p2ppb.CentrifugeHeader{ NetworkIdentifier: nc.GetNetworkID(), CentNodeVersion: version.GetVersion().String(), @@ -244,12 +291,7 @@ func (s *peer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreD Header: &h, Document: doc, } - - reqB, err := proto.Marshal(req) - if err != nil { - return nil, err - } - return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: reqB}, nil + return req, nil } func convertClientError(recv *protocolpb.P2PEnvelope) error { diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go new file mode 100644 index 000000000..9aa345575 --- /dev/null +++ b/p2p/client_integration_test.go @@ -0,0 +1,115 @@ +// +build integration + +package p2p_test + +import ( + "flag" + "os" + "testing" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/version" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/golang/protobuf/ptypes/any" + "github.com/stretchr/testify/assert" +) + +var ( + client p2p.Client + cfg config.Configuration + idService identity.Service + cfgStore configstore.Service +) + +func TestMain(m *testing.M) { + flag.Parse() + ctx := testingbootstrap.TestFunctionalEthereumBootstrap() + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfgStore = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + idService = ctx[ethid.BootstrappedIDService].(identity.Service) + client = ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) + testingidentity.CreateIdentityWithKeys(cfg, idService) + result := m.Run() + testingbootstrap.TestFunctionalEthereumTearDown() + os.Exit(result) +} + +func TestClient_GetSignaturesForDocument(t *testing.T) { + tc, _, err := createLocalCollaborator(t) + ctxh := testingconfig.CreateTenantContext(t, cfg) + doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + err = client.GetSignaturesForDocument(ctxh, idService, doc) + assert.NoError(t, err) + assert.Equal(t, 2, len(doc.Signatures)) +} + +func TestClient_SendAnchoredDocument(t *testing.T) { + tc, cid, err := createLocalCollaborator(t) + ctxh := testingconfig.CreateTenantContext(t, cfg) + doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + self, err := cfg.GetIdentityID() + assert.NoError(t, err) + p2pheader := &p2ppb.CentrifugeHeader{ + SenderCentrifugeId: self, + CentNodeVersion: version.GetVersion().String(), + NetworkIdentifier: cfg.GetNetworkID(), + } + _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: doc, Header: p2pheader}) + if assert.Error(t, err) { + assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) + } +} + +func createLocalCollaborator(t *testing.T) (*configstore.TenantConfig, identity.Identity, error) { + tcID := identity.RandomCentID() + tc, err := configstore.TempTenantConfig("", cfg) + assert.NoError(t, err) + tc.IdentityID = tcID[:] + tc, err = cfgStore.CreateTenant(tc) + assert.NoError(t, err) + id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tc, idService) + return tc, id, err +} + +func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *coredocumentpb.CoreDocument { + idConfig, err := identity.GetIdentityConfig(cfg) + assert.Nil(t, err) + identifier := utils.RandomSlice(32) + salts := &coredocumentpb.CoreDocumentSalts{} + doc := &coredocumentpb.CoreDocument{ + Collaborators: collaborators, + DataRoot: utils.RandomSlice(32), + DocumentIdentifier: identifier, + CurrentVersion: identifier, + NextVersion: utils.RandomSlice(32), + CoredocumentSalts: salts, + EmbeddedData: &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + }, + EmbeddedDataSalts: &any.Any{ + TypeUrl: documenttypes.InvoiceSaltsTypeUrl, + }, + } + err = proofs.FillSalts(doc, salts) + assert.Nil(t, err) + tree, _ := coredocument.GetDocumentSigningTree(doc) + doc.SigningRoot = tree.RootHash() + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) + doc.Signatures = append(doc.Signatures, sig) + tree, _ = coredocument.GetDocumentRootTree(doc) + doc.DocumentRoot = tree.RootHash() + return doc +} diff --git a/p2p/client_test.go b/p2p/client_test.go index 428c32a4e..ba0b5421c 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -48,13 +50,14 @@ func (mm *MockMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes func TestGetSignatureForDocument_fail_connect(t *testing.T) { m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") assert.NoError(t, err) @@ -63,23 +66,23 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) - resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) + m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) + resp, err := testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") } func TestGetSignatureForDocument_fail_version_check(t *testing.T) { + centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + idService := getIDMocks(centrifugeId) m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} - - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) assert.Nil(t, err, "centrifugeId not initialized correctly ") assert.NoError(t, err) @@ -88,8 +91,8 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { r, err := testClient.createSignatureRequest(sender, coreDoc) assert.Nil(t, err, "signature request could not be created") - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) - resp, err = testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) + m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) + resp, err = testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -98,13 +101,14 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m} + testClient := &peer{config: cfg, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") assert.NoError(t, err) @@ -115,9 +119,9 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, libp2pPeer.ID("peerID"), r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - resp, err := testClient.getSignatureForDocument(ctx, nil, *coreDoc, "peerID", centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") @@ -126,6 +130,14 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } +func getIDMocks(centrifugeId identity.CentID) *testingcommons.MockIDService { + idService := &testingcommons.MockIDService{} + id := &testingcommons.MockID{} + id.On("CurrentP2PKey").Return("5dsgvJGnvAfiR3K6HCBc4hcokSfmjj", nil) + idService.On("LookupIdentityForID", centrifugeId).Return(id, nil) + return idService +} + func (s *peer) createSignatureResp(centNodeVer string, signature *coredocumentpb.Signature) *protocolpb.P2PEnvelope { req := &p2ppb.SignatureResponse{ CentNodeVersion: centNodeVer, diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 0f6e8b18a..195b5029c 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -22,7 +22,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" - cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" @@ -48,7 +48,7 @@ var ( func TestMain(m *testing.M) { flag.Parse() - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) @@ -57,7 +57,7 @@ func TestMain(m *testing.M) { handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() - cc.TestFunctionalEthereumTearDown() + testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) } diff --git a/p2p/server.go b/p2p/server.go index 252ad66ee..7184a3e71 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -45,10 +45,11 @@ type messenger interface { // peer implements node.Server type peer struct { - config configstore.Service - host host.Host - handlerCreator func() *receiver.Handler - mes messenger + disablePeerStore bool + config configstore.Service + host host.Host + handlerCreator func() *receiver.Handler + mes messenger } // Name returns the P2PServer diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 6132ff431..213b70daf 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -3,7 +3,12 @@ package testingidentity import ( + "context" "testing" + "time" + + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" @@ -40,3 +45,34 @@ func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service return idConfig.ID } + +func CreateTenantIDWithKeys(contextTimeout time.Duration, cfg *configstore.TenantConfig, idService identity.Service) identity.Identity { + ctxh, _ := contextutil.NewCentrifugeContext(context.Background(), cfg) + idConfig, _ := identity.GetIdentityConfig(cfg) + // only create identity if it doesn't exist + id, err := idService.LookupIdentityForID(idConfig.ID) + if err != nil { + _, confirmations, _ := idService.CreateIdentity(ctxh, idConfig.ID) + <-confirmations + // LookupIdentityForId + id, _ = idService.LookupIdentityForID(idConfig.ID) + } + + // only add key if it doesn't exist + _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) + ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(contextTimeout) + defer cancel() + if err != nil { + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) + <-confirmations + } + _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) + ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext(contextTimeout) + defer cancel() + if err != nil { + confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) + <-confirmations + } + + return id +} From 819ff576abeda20a621edf1d4e0005b8348445d6 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 11 Jan 2019 17:28:05 +0100 Subject: [PATCH 125/220] Add basic Read rules to CoreDocument (#611) This PR will add basic read rules derived from the collaborators passed. Fixes #587 --- Gopkg.lock | 9 +-- Gopkg.toml | 5 +- coredocument/coredocument.go | 74 +++++++++++++++++--- coredocument/coredocument_test.go | 93 +++++++++++++++++++++++-- coredocument/read_acls.go | 56 +++++++++++++++ coredocument/read_acls_test.go | 29 ++++++++ documents/invoice/model.go | 2 +- documents/invoice/service_test.go | 4 +- documents/purchaseorder/model.go | 2 +- documents/purchaseorder/service_test.go | 4 +- 10 files changed, 250 insertions(+), 28 deletions(-) create mode 100644 coredocument/read_acls.go create mode 100644 coredocument/read_acls_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 2c94734f2..6cfccf072 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:d12e66a9500785cff8a8245bd8a138efff96ed3c1d0551b845cecdc25af57f90" + digest = "1:2893c4f8dca2362d6ba7f94bfecc2702c55c8ae5fec8754d3e8c6cde05ab19c9" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,8 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "34ce7eaff0b89ac4a34e60654d34297747e5a7b4" + revision = "c7b507c0f7510c97ee52fd9b78df185ff07e3512" + source = "github.com/vedhavyas/centrifuge-protobufs" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" @@ -86,14 +87,14 @@ revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" [[projects]] - digest = "1:f84321c62605dab82f35a0795dfe30981199e28ea8a0652e5e7ba9af66575fef" + digest = "1:a145dca8eb072174d0bce9c21771ec19885bdaa04fe2f9026de4664811b1caf7" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "d0df6e2ed059de47375ef8281529a500cd920261" + revision = "8c3b6a26b7929ec269302dc50d17c9ceb9772dda" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" diff --git a/Gopkg.toml b/Gopkg.toml index f7b695419..fc060c87a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,8 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "34ce7eaff0b89ac4a34e60654d34297747e5a7b4" + revision = "c7b507c0f7510c97ee52fd9b78df185ff07e3512" + source = "github.com/vedhavyas/centrifuge-protobufs" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" @@ -40,7 +41,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/centrifuge/precise-proofs" - revision = "d0df6e2ed059de47375ef8281529a500cd920261" + revision = "8c3b6a26b7929ec269302dc50d17c9ceb9772dda" [[constraint]] name = "github.com/centrifuge/gocelery" diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index d3bb495d9..772a5bca7 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -11,6 +11,7 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common/hexutil" ) // getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used @@ -100,7 +101,7 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do leaf := proofs.LeafNode{ Hash: payload[:], Hashed: true, - Property: sigProperty.ElemProp(proofs.FieldNum(i)), + Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), } leaf.HashNode(h, false) sigLeafList[i+1] = leaf @@ -150,9 +151,28 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs // PrepareNewVersion creates a copy of the passed coreDocument with the version fields updated // Adds collaborators and fills salts -// Note: ignores any collaborators in the oldCD +// Note: new collaborators are added to the list with old collaborators. func PrepareNewVersion(oldCD coredocumentpb.CoreDocument, collaborators []string) (*coredocumentpb.CoreDocument, error) { - newCD, err := NewWithCollaborators(collaborators) + ncd := New() + ucs, err := fetchUniqueCollaborators(oldCD.Collaborators, collaborators) + if err != nil { + return nil, errors.New("failed to decode collaborator: %v", err) + } + + cs := oldCD.Collaborators + for _, c := range ucs { + c := c + cs = append(cs, c[:]) + } + + ncd.Collaborators = cs + + // copy read rules and roles + ncd.Roles = oldCD.Roles + ncd.ReadRules = oldCD.ReadRules + addCollaboratorsToReadSignRules(ncd, ucs) + + err = FillSalts(ncd) if err != nil { return nil, err } @@ -160,23 +180,23 @@ func PrepareNewVersion(oldCD coredocumentpb.CoreDocument, collaborators []string if oldCD.DocumentIdentifier == nil { return nil, errors.New("coredocument.DocumentIdentifier is nil") } - newCD.DocumentIdentifier = oldCD.DocumentIdentifier + ncd.DocumentIdentifier = oldCD.DocumentIdentifier if oldCD.CurrentVersion == nil { return nil, errors.New("coredocument.CurrentVersion is nil") } - newCD.PreviousVersion = oldCD.CurrentVersion + ncd.PreviousVersion = oldCD.CurrentVersion if oldCD.NextVersion == nil { return nil, errors.New("coredocument.NextVersion is nil") } - newCD.CurrentVersion = oldCD.NextVersion - newCD.NextVersion = utils.RandomSlice(32) + ncd.CurrentVersion = oldCD.NextVersion + ncd.NextVersion = utils.RandomSlice(32) if oldCD.DocumentRoot == nil { return nil, errors.New("coredocument.DocumentRoot is nil") } - newCD.PreviousRoot = oldCD.DocumentRoot - return newCD, nil + ncd.PreviousRoot = oldCD.DocumentRoot + return ncd, nil } // New returns a new core document @@ -190,7 +210,7 @@ func New() *coredocumentpb.CoreDocument { } } -// NewWithCollaborators generates new core document, adds collaborators, and fills salts +// NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, error) { cd := New() ids, err := identity.CentIDsFromStrings(collaborators) @@ -202,6 +222,11 @@ func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, cd.Collaborators = append(cd.Collaborators, ids[i][:]) } + err = initReadRules(cd, ids) + if err != nil { + return nil, errors.New("failed to init read rules: %v", err) + } + err = FillSalts(cd) if err != nil { return nil, err @@ -229,7 +254,7 @@ func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.Co // FillSalts creates a new coredocument.Salts and fills it func FillSalts(doc *coredocumentpb.CoreDocument) error { - salts := &coredocumentpb.CoreDocumentSalts{} + salts := new(coredocumentpb.CoreDocumentSalts) err := proofs.FillSalts(doc, salts) if err != nil { return errors.New("failed to fill coredocument salts: %v", err) @@ -295,3 +320,30 @@ func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDoc return proofs, nil } + +func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.CentID, err error) { + ocsm := make(map[string]struct{}) + for _, c := range oldCollabs { + ocsm[hexutil.Encode(c)] = struct{}{} + } + + var uc []string + for _, c := range newCollabs { + if _, ok := ocsm[c]; ok { + continue + } + + uc = append(uc, c) + } + + for _, c := range uc { + id, err := identity.CentIDFromString(c) + if err != nil { + return nil, err + } + + ids = append(ids, id) + } + + return ids, nil +} diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index a763f1bbf..d2404f06a 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -8,14 +8,13 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -101,7 +100,7 @@ func TestGetDataProofHashes(t *testing.T) { hashes, err := getDataProofHashes(cd) assert.Nil(t, err) - assert.Equal(t, 4, len(hashes)) + assert.Equal(t, 5, len(hashes)) valid, err := proofs.ValidateProofSortedHashes(cd.DataRoot, hashes, cd.DocumentRoot, sha256.New()) assert.True(t, valid) @@ -264,3 +263,87 @@ func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { _, err = GetExternalCollaborators(self.ID, cd) assert.NotNil(t, err) } + +func Test_fetchUniqueCollaborators(t *testing.T) { + tests := []struct { + old [][]byte + new []string + result []identity.CentID + err bool + }{ + { + new: []string{"0x010203040506"}, + result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}}, + new: []string{"0x010203040506"}, + result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + new: []string{"0x010203040506"}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + }, + + // new collaborator with wrong format + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + new: []string{"0x0102030405"}, + err: true, + }, + } + + for _, c := range tests { + uc, err := fetchUniqueCollaborators(c.old, c.new) + if err != nil { + if c.err { + continue + } + + t.Fatal(err) + } + + assert.Equal(t, c.result, uc) + } +} + +func TestPrepareNewVersion_read_rules(t *testing.T) { + cd, err := NewWithCollaborators([]string{"0x010203040506"}) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) + assert.Equal(t, cd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + cd.DocumentRoot = utils.RandomSlice(32) + + // prepare with zero collaborators + ncd, err := PrepareNewVersion(*cd, nil) + assert.NoError(t, err) + assert.NotNil(t, ncd) + assert.Len(t, ncd.ReadRules, 1) + assert.Len(t, ncd.Roles, 1) + assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + + // prepare with no unique one + ncd, err = PrepareNewVersion(*cd, []string{"0x010203040506"}) + assert.NoError(t, err) + assert.NotNil(t, ncd) + assert.Len(t, ncd.ReadRules, 1) + assert.Len(t, ncd.Roles, 1) + assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + + // prepare with unique collaborators + ncd, err = PrepareNewVersion(*cd, []string{"0x010202030203", "0x020301020304"}) + assert.NoError(t, err) + assert.NotNil(t, ncd) + assert.Len(t, ncd.ReadRules, 2) + assert.Len(t, ncd.Roles, 2) + assert.Equal(t, ncd.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}, {1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) + assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + assert.Equal(t, ncd.Roles[1].Role.Collaborators, [][]byte{{1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) +} diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go new file mode 100644 index 000000000..facf541ea --- /dev/null +++ b/coredocument/read_acls.go @@ -0,0 +1,56 @@ +package coredocument + +import ( + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" +) + +// ErrZeroCollaborators error when no collaborators are passed +const ErrZeroCollaborators = errors.Error("require at least one collaborator") + +// initReadRules initiates the read rules for a given coredocument. +// Collaborators are given Read_Sign action. +// if the rules are created already, this is a no-op. +func initReadRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { + if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { + return nil + } + + if len(collabs) < 1 { + return ErrZeroCollaborators + } + + addCollaboratorsToReadSignRules(cd, collabs) + return nil +} + +func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) { + if len(collabs) == 0 { + return + } + + // create a role for given collaborators + role := new(coredocumentpb.Role) + for _, c := range collabs { + c := c + role.Collaborators = append(role.Collaborators, c[:]) + } + + // add the role to Roles + cd.Roles = appendRole(cd.Roles, role) + + // create a rule + rule := new(coredocumentpb.ReadRule) + rule.Roles = append(rule.Roles, cd.Roles[len(cd.Roles)-1].RoleKey) + rule.Action = coredocumentpb.Action_ACTION_READ_SIGN + cd.ReadRules = append(cd.ReadRules, rule) +} + +// appendRole appends the roles to role entry +func appendRole(roles []*coredocumentpb.RoleEntry, role *coredocumentpb.Role) []*coredocumentpb.RoleEntry { + return append(roles, &coredocumentpb.RoleEntry{ + RoleKey: uint32(len(roles)), + Role: role, + }) +} diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go new file mode 100644 index 000000000..55607fe97 --- /dev/null +++ b/coredocument/read_acls_test.go @@ -0,0 +1,29 @@ +// +build unit + +package coredocument + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/stretchr/testify/assert" +) + +func TestReadACLs_initReadRules(t *testing.T) { + cd := New() + err := initReadRules(cd, nil) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) + + cs := []identity.CentID{identity.RandomCentID()} + err = initReadRules(cd, cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) + + err = initReadRules(cd, cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) +} diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 0aaf19a6f..3eaed570e 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -363,7 +363,7 @@ func (i *Invoice) CalculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: &prop}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop}) invoiceData := i.createP2PProtobuf() err = t.AddLeavesFromDocument(invoiceData, i.getInvoiceSalts(invoiceData)) if err != nil { diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index e2c185576..4ccb219e7 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -360,8 +360,8 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.NotNil(t, doc) cd, err := doc.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, wantCollab, cd.Collaborators[1]) - assert.Len(t, cd.Collaborators, 2) + assert.Equal(t, wantCollab, cd.Collaborators[2]) + assert.Len(t, cd.Collaborators, 3) oldCD, err := old.PackCoreDocument() assert.Nil(t, err) assert.Equal(t, oldCD.DocumentIdentifier, cd.DocumentIdentifier) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 5f272d660..cccaa5d42 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -349,7 +349,7 @@ func (p *PurchaseOrder) calculateDataRoot() error { // getDocumentDataTree creates precise-proofs data tree for the model func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: &prop}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop}) poData := p.createP2PProtobuf() err = t.AddLeavesFromDocument(poData, p.getPurchaseOrderSalts(poData)) if err != nil { diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 8c404cdf3..f1bd4de20 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -203,8 +203,8 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.NotNil(t, doc) cd, err := doc.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, wantCollab, cd.Collaborators[1]) - assert.Len(t, cd.Collaborators, 2) + assert.Equal(t, wantCollab, cd.Collaborators[2]) + assert.Len(t, cd.Collaborators, 3) oldCD, err := old.PackCoreDocument() assert.Nil(t, err) assert.Equal(t, oldCD.DocumentIdentifier, cd.DocumentIdentifier) From 5fb352c57bdf9fc3a9ee6d96820a0ff8d4de6ead Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 11 Jan 2019 18:53:41 +0100 Subject: [PATCH 126/220] identity: gocelery task for successful transaction (#632) * added testworld tests for proofs * added transaction status task * added protobuf header transaction. * removed nft confirm task * implemented getTransactionStatus * formatting * formatting * removed testoutput * formatting * added swagger --- ethereum/transaction_status_task.go | 160 ++++++++++++++++++ nft/bootstrapper.go | 6 +- nft/ethereum_payment_obligation.go | 34 ++-- nft/handler.go | 4 +- protobufs/gen/go/nft/service.pb.go | 121 ++++++++----- protobufs/gen/swagger.json | 2 +- .../gen/swagger/nft/service.swagger.json | 10 +- protobufs/nft/service.proto | 8 +- testworld/httputils.go | 1 + testworld/nft_test.go | 4 +- 10 files changed, 281 insertions(+), 69 deletions(-) create mode 100644 ethereum/transaction_status_task.go diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go new file mode 100644 index 000000000..65de86467 --- /dev/null +++ b/ethereum/transaction_status_task.go @@ -0,0 +1,160 @@ +package ethereum + +import ( + "context" + "time" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/gocelery" + "github.com/ethereum/go-ethereum/common" +) + +const ( + // TransactionStatusTaskName contains the name of the task + TransactionStatusTaskName string = "TransactionStatusTask" + // TransactionTxHashParam contains the name of the parameter + TransactionTxHashParam string = "TxHashParam" + // TransactionAccountParam contains the name of the account + TransactionAccountParam string = "Account ID" + transactionStatusSuccess uint64 = 1 +) + +// TransactionStatusTask is struct for the task to check an Ethereum transaction +type TransactionStatusTask struct { + transactions.BaseTask + timeout time.Duration + //state + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) + + //task parameter + txHash string + tenantID identity.CentID +} + +// NewTransactionStatusTask returns a the struct for the task +func NewTransactionStatusTask( + timeout time.Duration, + txService transactions.Service, + ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), + +) *TransactionStatusTask { + return &TransactionStatusTask{ + timeout: timeout, + BaseTask: transactions.BaseTask{TxService: txService}, + ethContextInitializer: ethContextInitializer, + } +} + +// TaskTypeName returns mintingConfirmationTaskName +func (nftc *TransactionStatusTask) TaskTypeName() string { + return TransactionStatusTaskName +} + +// Copy returns a new instance of mintingConfirmationTask +func (nftc *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { + return &TransactionStatusTask{ + timeout: nftc.timeout, + txHash: nftc.txHash, + tenantID: nftc.tenantID, + ethContextInitializer: nftc.ethContextInitializer, + BaseTask: transactions.BaseTask{TxService: nftc.TxService}, + }, nil +} + +// ParseKwargs - define a method to parse CentID +func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + err = nftc.ParseTransactionID(kwargs) + if err != nil { + return err + } + + tenantID, ok := kwargs[TransactionAccountParam].(string) + if !ok { + return errors.New("missing tenant ID") + } + + nftc.tenantID, err = identity.CentIDFromString(tenantID) + if err != nil { + return err + } + + // parse txHash + txHash, ok := kwargs[TransactionTxHashParam] + if !ok { + return errors.New("undefined kwarg " + TransactionTxHashParam) + } + nftc.txHash, ok = txHash.(string) + if !ok { + return errors.New("malformed kwarg [%s]", TransactionTxHashParam) + } + + // override TimeoutParam if provided + tdRaw, ok := kwargs[queue.TimeoutParam] + if ok { + td, err := queue.GetDuration(tdRaw) + if err != nil { + return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) + } + nftc.timeout = td + } + + return nil +} + +func getTransactionStatus(ctx context.Context, client Client, txHash string) (bool, error) { + receipt, err := client.GetEthClient().TransactionReceipt(ctx, common.HexToHash(txHash)) + + if err != nil { + return false, err + } + + if receipt.Status == transactionStatusSuccess { + return true, nil + } + + return false, errors.New("Transaction failed") + +} + +// RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. +func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { + ctx, cancelF := nftc.ethContextInitializer(nftc.timeout) + defer cancelF() + defer func() { + if err != nil { + log.Infof("Transaction failed: %v\n", nftc.txHash) + } else { + log.Infof("Transaction successful:%v\n", nftc.txHash) + } + + err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) + }() + + isPending := true + client := GetClient() + for isPending { + _, isPending, err = client.GetEthClient().TransactionByHash(ctx, common.HexToHash(nftc.txHash)) + if err != nil { + return nil, err + } + + if isPending == false { + successful, err := getTransactionStatus(ctx, GetClient(), nftc.txHash) + if err != nil { + return nil, err + } + + if successful { + return nil, nil + + } + } + time.Sleep(100 * time.Millisecond) + } + + return nil, nil + +} diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 81bd76fb5..c3588c646 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -77,7 +77,9 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { }) // queue task - task := newMintingConfirmationTask(cfg.GetEthereumContextWaitTimeout(), ethereum.DefaultWaitForTransactionMiningContext, txService) - queueSrv.RegisterTaskType(task.TaskTypeName(), task) + + ethTransTask := ethereum.NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, ethereum.DefaultWaitForTransactionMiningContext) + + queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) return nil } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 1617ec728..25699f7af 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -2,7 +2,6 @@ package nft import ( "context" - "encoding/hex" "math/big" "github.com/centrifuge/go-centrifuge/documents/genericdoc" @@ -132,12 +131,13 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, err } - txID, err := s.queueTask(cid, requestData.TokenID, registryAddress) + txHash, err := s.sendMintTransaction(contract, opts, requestData) if err != nil { - return nil, errors.New("failed to queue task: %v", err) + return nil, errors.New("failed to send transaction: %v", err) } - err = s.sendMintTransaction(contract, opts, requestData) + txID, err := s.queueTaskTransaction(cid, txHash) + if err != nil { return nil, err } @@ -148,38 +148,34 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by }, nil } -func (s *ethereumPaymentObligation) queueTask(tenantID identity.CentID, tokenID *big.Int, registryAddress string) (txID uuid.UUID, err error) { - height, err := s.blockHeightFunc() - if err != nil { - return txID, err - } +func (s *ethereumPaymentObligation) queueTaskTransaction(tenantID identity.CentID, txHash string) (txID uuid.UUID, err error) { tx, err := s.txService.CreateTransaction(tenantID, "Mint NFT") if err != nil { return txID, err } - - _, err = s.queue.EnqueueJob(mintingConfirmationTaskName, map[string]interface{}{ - transactions.TxIDParam: tx.ID.String(), - tenantIDParam: tenantID.String(), - tokenIDParam: hex.EncodeToString(tokenID.Bytes()), - queue.BlockHeightParam: height, - registryAddressParam: registryAddress, + _, err = s.queue.EnqueueJob(ethereum.TransactionStatusTaskName, map[string]interface{}{ + transactions.TxIDParam: tx.ID.String(), + ethereum.TransactionAccountParam: tenantID.String(), + ethereum.TransactionTxHashParam: txHash, }) return tx.ID, err } // sendMintTransaction sends the actual transaction to mint the NFT -func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) error { +func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (string, error) { tx, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { - return err + return "", err } + + txHash := tx.Hash() + log.Infof("Sent off tx to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", requestData.TokenID, requestData.AnchorID, requestData.To, tx.Hash(), tx.Nonce(), tx.CheckNonce()) log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return nil + return txHash.String(), nil } // MintRequest holds the data needed to mint and NFT from a Centrifuge document diff --git a/nft/handler.go b/nft/handler.go index ed23091b1..26585612f 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -51,8 +51,8 @@ func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) } return &nftpb.NFTMintResponse{ - TokenId: resp.TokenID, - TransactionId: resp.TransactionID, + TokenId: resp.TokenID, + Header: &nftpb.ResponseHeader{TransactionId: resp.TransactionID}, }, nil } diff --git a/protobufs/gen/go/nft/service.pb.go b/protobufs/gen/go/nft/service.pb.go index 2cf544291..a6163d15d 100644 --- a/protobufs/gen/go/nft/service.pb.go +++ b/protobufs/gen/go/nft/service.pb.go @@ -25,6 +25,44 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type ResponseHeader struct { + TransactionId string `protobuf:"bytes,5,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } +func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } +func (*ResponseHeader) ProtoMessage() {} +func (*ResponseHeader) Descriptor() ([]byte, []int) { + return fileDescriptor_service_15c9f80dd06d1ac1, []int{0} +} +func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) +} +func (m *ResponseHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseHeader.Marshal(b, m, deterministic) +} +func (dst *ResponseHeader) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseHeader.Merge(dst, src) +} +func (m *ResponseHeader) XXX_Size() int { + return xxx_messageInfo_ResponseHeader.Size(m) +} +func (m *ResponseHeader) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseHeader.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseHeader proto.InternalMessageInfo + +func (m *ResponseHeader) GetTransactionId() string { + if m != nil { + return m.TransactionId + } + return "" +} + type NFTMintRequest struct { // Document identifier Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` @@ -41,7 +79,7 @@ func (m *NFTMintRequest) Reset() { *m = NFTMintRequest{} } func (m *NFTMintRequest) String() string { return proto.CompactTextString(m) } func (*NFTMintRequest) ProtoMessage() {} func (*NFTMintRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_66d4e2152d82b027, []int{0} + return fileDescriptor_service_15c9f80dd06d1ac1, []int{1} } func (m *NFTMintRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintRequest.Unmarshal(m, b) @@ -90,18 +128,18 @@ func (m *NFTMintRequest) GetProofFields() []string { } type NFTMintResponse struct { - TokenId string `protobuf:"bytes,1,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *NFTMintResponse) Reset() { *m = NFTMintResponse{} } func (m *NFTMintResponse) String() string { return proto.CompactTextString(m) } func (*NFTMintResponse) ProtoMessage() {} func (*NFTMintResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_66d4e2152d82b027, []int{1} + return fileDescriptor_service_15c9f80dd06d1ac1, []int{2} } func (m *NFTMintResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintResponse.Unmarshal(m, b) @@ -121,21 +159,22 @@ func (m *NFTMintResponse) XXX_DiscardUnknown() { var xxx_messageInfo_NFTMintResponse proto.InternalMessageInfo -func (m *NFTMintResponse) GetTokenId() string { +func (m *NFTMintResponse) GetHeader() *ResponseHeader { if m != nil { - return m.TokenId + return m.Header } - return "" + return nil } -func (m *NFTMintResponse) GetTransactionId() string { +func (m *NFTMintResponse) GetTokenId() string { if m != nil { - return m.TransactionId + return m.TokenId } return "" } func init() { + proto.RegisterType((*ResponseHeader)(nil), "nft.ResponseHeader") proto.RegisterType((*NFTMintRequest)(nil), "nft.NFTMintRequest") proto.RegisterType((*NFTMintResponse)(nil), "nft.NFTMintResponse") } @@ -212,32 +251,34 @@ var _NFTService_serviceDesc = grpc.ServiceDesc{ Metadata: "nft/service.proto", } -func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_66d4e2152d82b027) } - -var fileDescriptor_service_66d4e2152d82b027 = []byte{ - // 377 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x8e, 0xd3, 0x30, - 0x14, 0x40, 0x95, 0x29, 0x50, 0xc6, 0x33, 0xb4, 0x83, 0x61, 0x51, 0x22, 0x84, 0x4c, 0x24, 0xa0, - 0x20, 0xa6, 0x91, 0x60, 0xc7, 0xae, 0x03, 0x8a, 0x34, 0x0b, 0xa2, 0x51, 0x9b, 0x15, 0x9b, 0xca, - 0x8d, 0xbf, 0x23, 0x8b, 0xe6, 0x3b, 0xd8, 0xbf, 0x54, 0x6c, 0x91, 0xb8, 0x00, 0x1c, 0x82, 0x03, - 0x71, 0x05, 0x0e, 0x82, 0xe2, 0xb4, 0x55, 0x2b, 0x56, 0x51, 0x9e, 0x9e, 0xec, 0xe7, 0xff, 0xd9, - 0x7d, 0xd4, 0x94, 0x7a, 0x70, 0x5f, 0x4d, 0x09, 0x93, 0xc6, 0x59, 0xb2, 0xbc, 0x87, 0x9a, 0xe2, - 0xc7, 0x95, 0xb5, 0xd5, 0x0a, 0x52, 0xd9, 0x98, 0x54, 0x22, 0x5a, 0x92, 0x64, 0x2c, 0xfa, 0x4e, - 0x89, 0x5f, 0x87, 0x4f, 0x79, 0x59, 0x01, 0x5e, 0xfa, 0x8d, 0xac, 0x2a, 0x70, 0xa9, 0x6d, 0x82, - 0xf1, 0xbf, 0x9d, 0xfc, 0x8e, 0xd8, 0x20, 0xcf, 0x8a, 0x8f, 0x06, 0x69, 0x06, 0x5f, 0xd6, 0xe0, - 0x89, 0x3f, 0x61, 0xcc, 0x28, 0x40, 0x32, 0xda, 0x80, 0x1b, 0x45, 0x22, 0x1a, 0x9f, 0xce, 0x0e, - 0x08, 0x7f, 0xc9, 0x2e, 0x1c, 0x54, 0xc6, 0x93, 0xfb, 0xb6, 0x90, 0x4a, 0x39, 0xf0, 0x7e, 0x74, - 0x12, 0xac, 0xe1, 0x8e, 0x4f, 0x3b, 0xcc, 0x5f, 0xb0, 0xa1, 0x82, 0xc6, 0x7a, 0x43, 0x7b, 0xb3, - 0x17, 0xcc, 0xc1, 0x16, 0xef, 0xc4, 0xa7, 0xec, 0xbc, 0x71, 0xd6, 0xea, 0x85, 0x36, 0xb0, 0x52, - 0x7e, 0x74, 0x4b, 0xf4, 0xc6, 0xa7, 0xb3, 0xb3, 0xc0, 0xb2, 0x80, 0x92, 0x39, 0x1b, 0xee, 0x43, - 0x7d, 0x63, 0xd1, 0x03, 0x7f, 0xc4, 0xee, 0x92, 0xfd, 0x0c, 0xb8, 0x30, 0x6a, 0xdb, 0xd9, 0x0f, - 0xff, 0xd7, 0x8a, 0x3f, 0x63, 0x03, 0x72, 0x12, 0xbd, 0x2c, 0xdb, 0xd7, 0xb6, 0x42, 0x97, 0x78, - 0xef, 0x80, 0x5e, 0xab, 0x37, 0x3f, 0x22, 0xc6, 0xf2, 0xac, 0x98, 0x77, 0x43, 0xe6, 0x1b, 0xd6, - 0x6f, 0x2f, 0xc8, 0xb3, 0x82, 0x3f, 0x98, 0xa0, 0xa6, 0xc9, 0xf1, 0x68, 0xe2, 0x87, 0xc7, 0xb0, - 0xcb, 0x48, 0xa6, 0x3f, 0xa7, 0xe3, 0xf8, 0x79, 0x8b, 0x84, 0x44, 0x91, 0x67, 0x85, 0xd0, 0xce, - 0xd6, 0x42, 0x8a, 0xf7, 0x80, 0xe4, 0x8c, 0x5e, 0x57, 0x20, 0x3e, 0xd8, 0x72, 0x5d, 0x03, 0xd2, - 0xf7, 0x3f, 0x7f, 0x7f, 0x9d, 0x5c, 0x24, 0x67, 0x69, 0x08, 0x4d, 0x6b, 0x83, 0xf4, 0x2e, 0x7a, - 0x75, 0x25, 0x58, 0xbf, 0xb4, 0x75, 0x7b, 0xfa, 0xd5, 0xf9, 0x36, 0xe6, 0xa6, 0xdd, 0xcf, 0x4d, - 0xf4, 0xe9, 0x36, 0x6a, 0x6a, 0x96, 0xcb, 0x3b, 0x61, 0x5f, 0x6f, 0xff, 0x05, 0x00, 0x00, 0xff, - 0xff, 0x3c, 0xa0, 0x02, 0xa5, 0x15, 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_15c9f80dd06d1ac1) } + +var fileDescriptor_service_15c9f80dd06d1ac1 = []byte{ + // 410 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0x87, 0xe5, 0x86, 0x36, 0x74, 0x52, 0x92, 0xb2, 0x70, 0x08, 0x11, 0x42, 0x8b, 0x25, 0x20, + 0xfc, 0x69, 0x2c, 0x95, 0x03, 0x12, 0xb7, 0x14, 0x64, 0xd1, 0x03, 0x51, 0x65, 0x72, 0x81, 0x4b, + 0xb4, 0xf5, 0xce, 0x9a, 0x15, 0xcd, 0xac, 0xd9, 0x9d, 0x50, 0x71, 0x45, 0xe2, 0x05, 0xe0, 0x21, + 0x78, 0x20, 0x5e, 0x81, 0x07, 0x41, 0x5e, 0xa7, 0x55, 0xa3, 0x9e, 0x2c, 0x7f, 0xfa, 0x76, 0xe6, + 0x37, 0x33, 0x70, 0x9b, 0x0c, 0x67, 0x01, 0xfd, 0x37, 0x5b, 0xe2, 0xa4, 0xf6, 0x8e, 0x9d, 0xe8, + 0x90, 0xe1, 0xd1, 0xfd, 0xca, 0xb9, 0xea, 0x0c, 0x33, 0x55, 0xdb, 0x4c, 0x11, 0x39, 0x56, 0x6c, + 0x1d, 0x85, 0x56, 0x19, 0xbd, 0x88, 0x9f, 0xf2, 0xa0, 0x42, 0x3a, 0x08, 0xe7, 0xaa, 0xaa, 0xd0, + 0x67, 0xae, 0x8e, 0xc6, 0x75, 0x3b, 0x7d, 0x05, 0xfd, 0x02, 0x43, 0xed, 0x28, 0xe0, 0x3b, 0x54, + 0x1a, 0xbd, 0x78, 0x04, 0x7d, 0xf6, 0x8a, 0x82, 0x2a, 0x1b, 0x6f, 0x61, 0xf5, 0x70, 0x5b, 0x26, + 0xe3, 0xdd, 0xe2, 0xd6, 0x15, 0x7a, 0xac, 0xd3, 0x3f, 0x09, 0xf4, 0x67, 0xf9, 0xfc, 0xbd, 0x25, + 0x2e, 0xf0, 0xeb, 0x0a, 0x03, 0x8b, 0x07, 0x00, 0x56, 0x23, 0xb1, 0x35, 0x16, 0xfd, 0x30, 0x89, + 0xaf, 0xae, 0x10, 0xf1, 0x14, 0xf6, 0x3d, 0x56, 0x36, 0xb0, 0xff, 0xbe, 0x50, 0x5a, 0x7b, 0x0c, + 0x61, 0xb8, 0x15, 0xad, 0xc1, 0x05, 0x9f, 0xb6, 0x58, 0x3c, 0x81, 0x81, 0xc6, 0xda, 0x05, 0xcb, + 0x97, 0x66, 0x27, 0x9a, 0xfd, 0x35, 0xbe, 0x10, 0x1f, 0xc2, 0x5e, 0xed, 0x9d, 0x33, 0x0b, 0x63, + 0xf1, 0x4c, 0x87, 0xe1, 0x0d, 0xd9, 0x19, 0xef, 0x16, 0xbd, 0xc8, 0xf2, 0x88, 0xd2, 0x8f, 0x30, + 0xb8, 0x0c, 0xda, 0x4e, 0x2a, 0x9e, 0xc3, 0xce, 0xe7, 0x38, 0x6d, 0x4c, 0xd9, 0x3b, 0xbc, 0x33, + 0x21, 0xc3, 0x93, 0xcd, 0x45, 0x14, 0x6b, 0x45, 0xdc, 0x83, 0x9b, 0xec, 0xbe, 0x60, 0x5c, 0x45, + 0x1b, 0xb7, 0x1b, 0xff, 0x8f, 0xf5, 0xe1, 0xcf, 0x04, 0x60, 0x96, 0xcf, 0x3f, 0xb4, 0x37, 0x12, + 0xe7, 0xd0, 0x6d, 0xda, 0xcc, 0xf2, 0xb9, 0x68, 0x2b, 0x6e, 0x2e, 0x68, 0x74, 0x77, 0x13, 0xb6, + 0xdd, 0xd2, 0xe9, 0xaf, 0xe9, 0x78, 0xf4, 0xb8, 0x41, 0x52, 0x91, 0x9c, 0xe5, 0x73, 0x69, 0xbc, + 0x5b, 0x4a, 0x25, 0xdf, 0x20, 0xb1, 0xb7, 0x66, 0x55, 0xa1, 0x7c, 0xeb, 0xca, 0xd5, 0x12, 0x89, + 0x7f, 0xfc, 0xfd, 0xf7, 0x7b, 0x6b, 0x3f, 0xed, 0x65, 0x31, 0x41, 0xb6, 0xb4, 0xc4, 0xaf, 0x93, + 0x67, 0x47, 0x12, 0xba, 0xa5, 0x5b, 0x36, 0xd5, 0x8f, 0xf6, 0xd6, 0x61, 0x4e, 0x9a, 0xf3, 0x9e, + 0x24, 0x9f, 0xb6, 0xc9, 0x70, 0x7d, 0x7a, 0xba, 0x13, 0xcf, 0xfd, 0xf2, 0x7f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xbb, 0x61, 0xbb, 0x11, 0x54, 0x02, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 19838a823..0da34343c 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"token_id":{"type":"string"},"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/nft/service.swagger.json b/protobufs/gen/swagger/nft/service.swagger.json index 4027d8127..86836a122 100644 --- a/protobufs/gen/swagger/nft/service.swagger.json +++ b/protobufs/gen/swagger/nft/service.swagger.json @@ -69,9 +69,17 @@ "nftNFTMintResponse": { "type": "object", "properties": { + "header": { + "$ref": "#/definitions/nftResponseHeader" + }, "token_id": { "type": "string" - }, + } + } + }, + "nftResponseHeader": { + "type": "object", + "properties": { "transaction_id": { "type": "string" } diff --git a/protobufs/nft/service.proto b/protobufs/nft/service.proto index 807276b98..a0c8315c2 100644 --- a/protobufs/nft/service.proto +++ b/protobufs/nft/service.proto @@ -23,6 +23,10 @@ service NFTService { } } +message ResponseHeader { + string transaction_id = 5; +} + message NFTMintRequest { // Document identifier string identifier = 1; @@ -33,6 +37,6 @@ message NFTMintRequest { } message NFTMintResponse { - string token_id = 1; - string transaction_id = 2; + ResponseHeader header = 1; + string token_id = 2; } diff --git a/testworld/httputils.go b/testworld/httputils.go index fd4d80bb7..20bc640ba 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -130,6 +130,7 @@ func waitTillSuccess(t *testing.T, e *httpexpect.Expect, txID string) { for { resp := e.GET("/transactions/" + txID).Expect().Status(200).JSON().Object() status := resp.Path("$.status").String().Raw() + if status == "pending" { time.Sleep(1 * time.Second) continue diff --git a/testworld/nft_test.go b/testworld/nft_test.go index a7d2c72d4..a7f5c565a 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -12,7 +12,6 @@ import ( func TestPaymentObligationMint_invoice_successful(t *testing.T) { t.Parallel() paymentObligationMint(t, typeInvoice) - } /* TODO: testcase not stable @@ -31,6 +30,7 @@ func paymentObligationMint(t *testing.T, documentType string) { // Alice shares document with Bob res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultNFTPayload(documentType, []string{bob.id.String()})) txID := getTransactionID(t, res) + waitTillSuccess(t, alice.httpExpect, txID) docIdentifier := getDocumentIdentifier(t, res) @@ -66,7 +66,7 @@ func paymentObligationMint(t *testing.T, documentType string) { } response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) - txID = getTransactionID(t, res) + txID = getTransactionID(t, response) waitTillSuccess(t, alice.httpExpect, txID) assert.Nil(t, err, "mintNFT should be successful") From 612b76edc55135eccd2407d6abbd23afd3a4bc9c Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Sun, 13 Jan 2019 11:49:06 +0100 Subject: [PATCH 127/220] Fix p2p validation check for local (#634) * Fix p2p validation check for local * Fix p2p validation check for local --- p2p/client.go | 100 +++++++++++++++++++-------------- p2p/client_integration_test.go | 21 +++++-- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/p2p/client.go b/p2p/client.go index fa2ff2325..804725e67 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -132,6 +132,8 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden if err != nil { return nil, err } + + var resp *p2ppb.SignatureResponse tc, err := s.config.GetTenant(receiverCentID[:]) if err == nil { // this is a local tenant @@ -146,60 +148,53 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden return nil, err } - return h.RequestDocumentSignature(localPeerCtx, req) - } + resp, err = h.RequestDocumentSignature(localPeerCtx, req) + if err != nil { + return nil, err + } + } else { + // this is a remote tenant + id, err := identityService.LookupIdentityForID(receiverCentID) + if err != nil { + return nil, err + } - // this is a remote tenant - id, err := identityService.LookupIdentityForID(receiverCentID) - if err != nil { - return nil, err - } + receiverPeer, err := s.getPeerID(id) + if err != nil { + return nil, err + } - receiverPeer, err := s.getPeerID(id) - if err != nil { - return nil, err - } + req, err := s.createSignatureRequest(self.ID[:], doc) + if err != nil { + return nil, err + } - req, err := s.createSignatureRequest(self.ID[:], doc) - if err != nil { - return nil, err - } + log.Infof("Requesting signature from %s\n", receiverCentID) + recv, err := s.mes.sendMessage(ctx, receiverPeer, req, receiver.ProtocolForCID(receiverCentID)) + if err != nil { + return nil, err + } - log.Infof("Requesting signature from %s\n", receiverCentID) - recv, err := s.mes.sendMessage(ctx, receiverPeer, req, receiver.ProtocolForCID(receiverCentID)) - if err != nil { - return nil, err - } + // handle client error + if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { + return nil, convertClientError(recv) + } - // handle client error - if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { - return nil, convertClientError(recv) + if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP { + return nil, errors.New("the received request signature response is incorrect") + } + resp = new(p2ppb.SignatureResponse) + err = proto.Unmarshal(recv.Body, resp) + if err != nil { + return nil, err + } } - if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP { - return nil, errors.New("the received request signature response is incorrect") - } - resp := new(p2ppb.SignatureResponse) - err = proto.Unmarshal(recv.Body, resp) + err = validateSignatureResp(identityService, receiverCentID, doc, resp) if err != nil { return nil, err } - compatible := version.CheckVersion(resp.CentNodeVersion) - if !compatible { - return nil, version.IncompatibleVersionError(resp.CentNodeVersion) - } - - err = identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiverCentID) - if err != nil { - return nil, centerrors.New(code.AuthenticationFailed, err.Error()) - } - - err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) - if err != nil { - return nil, centerrors.New(code.AuthenticationFailed, "signature invalid") - } - log.Infof("Signature successfully received from %s\n", receiverCentID) return resp, nil } @@ -255,6 +250,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide for _, resp := range responses { if resp.err != nil { + // this error is ignored since we would still anchor the document log.Error(resp.err) continue } @@ -302,3 +298,21 @@ func convertClientError(recv *protocolpb.P2PEnvelope) error { } return errors.New(resp.Message) } + +func validateSignatureResp(identityService identity.Service, receiver identity.CentID, doc *coredocumentpb.CoreDocument, resp *p2ppb.SignatureResponse) error { + compatible := version.CheckVersion(resp.CentNodeVersion) + if !compatible { + return version.IncompatibleVersionError(resp.CentNodeVersion) + } + + err := identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiver) + if err != nil { + return centerrors.New(code.AuthenticationFailed, err.Error()) + } + + err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) + if err != nil { + return centerrors.New(code.AuthenticationFailed, "signature invalid") + } + return nil +} diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 9aa345575..afba01db6 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -48,7 +48,7 @@ func TestMain(m *testing.M) { } func TestClient_GetSignaturesForDocument(t *testing.T) { - tc, _, err := createLocalCollaborator(t) + tc, _, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) err = client.GetSignaturesForDocument(ctxh, idService, doc) @@ -56,8 +56,18 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { assert.Equal(t, 2, len(doc.Signatures)) } +func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { + tc, _, err := createLocalCollaborator(t, true) + ctxh := testingconfig.CreateTenantContext(t, cfg) + doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + err = client.GetSignaturesForDocument(ctxh, idService, doc) + assert.NoError(t, err) + // one signature would be missing + assert.Equal(t, 1, len(doc.Signatures)) +} + func TestClient_SendAnchoredDocument(t *testing.T) { - tc, cid, err := createLocalCollaborator(t) + tc, cid, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) self, err := cfg.GetIdentityID() @@ -73,14 +83,17 @@ func TestClient_SendAnchoredDocument(t *testing.T) { } } -func createLocalCollaborator(t *testing.T) (*configstore.TenantConfig, identity.Identity, error) { +func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.TenantConfig, identity.Identity, error) { tcID := identity.RandomCentID() tc, err := configstore.TempTenantConfig("", cfg) assert.NoError(t, err) tc.IdentityID = tcID[:] + id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tc, idService) + if corruptID { + tc.IdentityID = utils.RandomSlice(identity.CentIDLength) + } tc, err = cfgStore.CreateTenant(tc) assert.NoError(t, err) - id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tc, idService) return tc, id, err } From 49a18e2ed63b847d721ccb20ab41d02cc7f56f28 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Sun, 13 Jan 2019 20:04:12 +0100 Subject: [PATCH 128/220] Added Generic handler + new p2p envelope (#629) * envelope + handler * rename proto * format + tests * timeout * fix * address comments --- Gopkg.lock | 5 +- Gopkg.toml | 3 +- coredocument/processor.go | 18 +-- documents/genericdoc/service.go | 7 +- documents/purchaseorder/service.go | 3 +- documents/service.go | 3 +- p2p/client.go | 105 ++++++-------- p2p/client_integration_test.go | 11 +- p2p/client_test.go | 64 ++++----- p2p/common/protocol.go | 131 +++++++++++++++++ p2p/common/protocol_test.go | 115 +++++++++++++++ p2p/messenger.go | 33 ++--- p2p/messenger_test.go | 102 ++++++++----- p2p/receiver/handler.go | 109 ++++++++------ p2p/receiver/handler_integration_test.go | 20 +-- p2p/receiver/handler_test.go | 174 +++++++++++++++-------- p2p/receiver/protocol.go | 24 ---- p2p/receiver/protocol_test.go | 26 ---- p2p/receiver/validator.go | 16 +-- p2p/receiver/validator_test.go | 16 +-- p2p/server.go | 13 +- protobufs/gen/go/protocol/protocol.pb.go | 74 ++-------- protobufs/protocol/protocol.proto | 11 -- testingutils/commons/mock_p2p.go | 16 --- testingutils/config/config.go | 7 +- testingutils/documents/documents.go | 3 +- 26 files changed, 635 insertions(+), 474 deletions(-) create mode 100644 p2p/common/protocol.go create mode 100644 p2p/common/protocol_test.go delete mode 100644 p2p/receiver/protocol.go delete mode 100644 p2p/receiver/protocol_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 6cfccf072..8546c404e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:2893c4f8dca2362d6ba7f94bfecc2702c55c8ae5fec8754d3e8c6cde05ab19c9" + digest = "1:68feb6f4b546c63e2b1089484d8905d46389a47af9858434a5636438ff16c09e" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,8 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "c7b507c0f7510c97ee52fd9b78df185ff07e3512" - source = "github.com/vedhavyas/centrifuge-protobufs" + revision = "1a7c385dace67bd54096f2c8379fab514f2a41d3" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" diff --git a/Gopkg.toml b/Gopkg.toml index fc060c87a..c91c2d022 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,8 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "c7b507c0f7510c97ee52fd9b78df185ff07e3512" - source = "github.com/vedhavyas/centrifuge-protobufs" + revision = "1a7c385dace67bd54096f2c8379fab514f2a41d3" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/coredocument/processor.go b/coredocument/processor.go index 8b4e71d60..daed38976 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/go-centrifuge/version" logging "github.com/ipfs/go-log" ) @@ -75,25 +74,14 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp return errors.New("error fetching receiver identity: %v", err) } - self, err := contextutil.Self(ctx) - if err != nil { - return err - } - - log.Infof("Done opening connection against recipient [%x]\n", recipient) - centIDBytes := self.ID[:] - p2pheader := &p2ppb.CentrifugeHeader{ - SenderCentrifugeId: centIDBytes, - CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: dp.config.GetNetworkID(), - } - c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) - resp, err := dp.p2pClient.SendAnchoredDocument(c, id, &p2ppb.AnchorDocumentRequest{Document: coreDocument, Header: p2pheader}) + resp, err := dp.p2pClient.SendAnchoredDocument(c, id, &p2ppb.AnchorDocumentRequest{Document: coreDocument}) if err != nil || !resp.Accepted { return errors.New("failed to send document to the node: %v", err) } + log.Infof("Done opening connection against recipient [%x]\n", recipient) + return nil } diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index db5606b7b..252eeb04b 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -7,7 +7,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" @@ -44,7 +43,7 @@ type Service interface { RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB - ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error + ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error } // service implements Service @@ -190,7 +189,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return sig, nil } -func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error { idConf, err := contextutil.Self(ctx) if err != nil { return documents.ErrDocumentConfigTenantID @@ -213,7 +212,7 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Mo ts, _ := ptypes.TimestampProto(time.Now().UTC()) notificationMsg := ¬ificationpb.NotificationMessage{ EventType: uint32(notification.ReceivedPayload), - CentrifugeId: hexutil.Encode(headers.SenderCentrifugeId), + CentrifugeId: hexutil.Encode(senderID), Recorded: ts, DocumentType: doc.EmbeddedData.TypeUrl, DocumentId: hexutil.Encode(doc.DocumentIdentifier), diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 8f0475500..ef4751788 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -65,7 +65,8 @@ func DefaultService( identityService identity.Service, queueSrv queue.TaskQueuer, txService transactions.Service, - genService genericdoc.Service) Service { + genService genericdoc.Service, +) Service { return service{ repo: repo, notifier: notification.NewWebhookSender(), diff --git a/documents/service.go b/documents/service.go index c2abd782c..1c60461da 100644 --- a/documents/service.go +++ b/documents/service.go @@ -4,7 +4,6 @@ import ( "context" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/precise-proofs/proofs/proto" ) @@ -41,5 +40,5 @@ type Service interface { RequestDocumentSignature(ctx context.Context, model Model) (*coredocumentpb.Signature, error) // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB - ReceiveAnchoredDocument(ctx context.Context, model Model, headers *p2ppb.CentrifugeHeader) error + ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error } diff --git a/p2p/client.go b/p2p/client.go index 804725e67..6ec4a9cbe 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,9 +4,8 @@ import ( "context" "fmt" - "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/golang/protobuf/proto" "github.com/centrifuge/go-centrifuge/contextutil" @@ -52,7 +51,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i if err != nil { return nil, err } - return h.SendAnchoredDocument(localCtx, in) + return h.SendAnchoredDocument(localCtx, in, cid[:]) } // this is a remote tenant @@ -61,32 +60,39 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i return nil, err } - marshalledRequest, err := proto.Marshal(in) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeSendAnchoredDoc, in) if err != nil { return nil, err } recv, err := s.mes.sendMessage( - peerCtx, pid, - &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: marshalledRequest}, - receiver.ProtocolForCID(id.CentID())) + ctx, pid, + envelope, + p2pcommon.ProtocolForCID(id.CentID())) + if err != nil { + return nil, err + } + + recvEnvelope, err := p2pcommon.ResolveDataEnvelope(recv) if err != nil { return nil, err } // handle client error - if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { - return nil, convertClientError(recv) + if p2pcommon.MessageTypeError.Equals(recvEnvelope.Header.Type) { + return nil, convertClientError(recvEnvelope) } - if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP { + if !p2pcommon.MessageTypeSendAnchoredDocRep.Equals(recvEnvelope.Header.Type) { return nil, errors.New("the received send anchored document response is incorrect") } + r := new(p2ppb.AnchorDocumentResponse) - err = proto.Unmarshal(recv.Body, r) + err = proto.Unmarshal(recvEnvelope.Body, r) if err != nil { return nil, err } + return r, nil } @@ -127,13 +133,15 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { - self, err := contextutil.Self(ctx) +func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { + nc, err := s.config.GetConfig() if err != nil { return nil, err } var resp *p2ppb.SignatureResponse + var header *p2ppb.Header + tc, err := s.config.GetTenant(receiverCentID[:]) if err == nil { // this is a local tenant @@ -143,15 +151,12 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden if err != nil { return nil, err } - req, err := s.sigRequest(self.ID[:], doc) - if err != nil { - return nil, err - } - resp, err = h.RequestDocumentSignature(localPeerCtx, req) + resp, err = h.RequestDocumentSignature(localPeerCtx, &p2ppb.SignatureRequest{Document: &doc}) if err != nil { return nil, err } + header = &p2ppb.Header{NodeVersion: version.GetVersion().String()} } else { // this is a remote tenant id, err := identityService.LookupIdentityForID(receiverCentID) @@ -163,34 +168,35 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden if err != nil { return nil, err } - - req, err := s.createSignatureRequest(self.ID[:], doc) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &doc}) if err != nil { return nil, err } - - log.Infof("Requesting signature from %s\n", receiverCentID) - recv, err := s.mes.sendMessage(ctx, receiverPeer, req, receiver.ProtocolForCID(receiverCentID)) + log.Infof("Requesting signature from %s\n", receiverPeer) + recv, err := s.mes.sendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForCID(receiverCentID)) + if err != nil { + return nil, err + } + recvEnvelope, err := p2pcommon.ResolveDataEnvelope(recv) if err != nil { return nil, err } - // handle client error - if recv.Type == protocolpb.MessageType_MESSAGE_TYPE_ERROR { - return nil, convertClientError(recv) + if p2pcommon.MessageTypeError.Equals(recvEnvelope.Header.Type) { + return nil, convertClientError(recvEnvelope) } - - if recv.Type != protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP { + if !p2pcommon.MessageTypeRequestSignatureRep.Equals(recvEnvelope.Header.Type) { return nil, errors.New("the received request signature response is incorrect") } resp = new(p2ppb.SignatureResponse) - err = proto.Unmarshal(recv.Body, resp) + err = proto.Unmarshal(recvEnvelope.Body, resp) if err != nil { return nil, err } + header = recvEnvelope.Header } - err = validateSignatureResp(identityService, receiverCentID, doc, resp) + err = validateSignatureResp(identityService, receiverCentID, &doc, header, resp) if err != nil { return nil, err } @@ -205,7 +211,7 @@ type signatureResponseWrap struct { } func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, identityService, doc, receiverCentID) + resp, err := s.getSignatureForDocument(ctx, identityService, *doc, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, @@ -261,36 +267,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide return nil } -func (s *peer) createSignatureRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*protocolpb.P2PEnvelope, error) { - req, err := s.sigRequest(senderID, doc) - if err != nil { - return nil, err - } - reqB, err := proto.Marshal(req) - if err != nil { - return nil, err - } - return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: reqB}, nil -} - -func (s *peer) sigRequest(senderID []byte, doc *coredocumentpb.CoreDocument) (*p2ppb.SignatureRequest, error) { - nc, err := s.config.GetConfig() - if err != nil { - return nil, err - } - h := p2ppb.CentrifugeHeader{ - NetworkIdentifier: nc.GetNetworkID(), - CentNodeVersion: version.GetVersion().String(), - SenderCentrifugeId: senderID, - } - req := &p2ppb.SignatureRequest{ - Header: &h, - Document: doc, - } - return req, nil -} - -func convertClientError(recv *protocolpb.P2PEnvelope) error { +func convertClientError(recv *p2ppb.Envelope) error { resp := new(errorspb.Error) err := proto.Unmarshal(recv.Body, resp) if err != nil { @@ -299,10 +276,10 @@ func convertClientError(recv *protocolpb.P2PEnvelope) error { return errors.New(resp.Message) } -func validateSignatureResp(identityService identity.Service, receiver identity.CentID, doc *coredocumentpb.CoreDocument, resp *p2ppb.SignatureResponse) error { - compatible := version.CheckVersion(resp.CentNodeVersion) +func validateSignatureResp(identityService identity.Service, receiver identity.CentID, doc *coredocumentpb.CoreDocument, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { + compatible := version.CheckVersion(header.NodeVersion) if !compatible { - return version.IncompatibleVersionError(resp.CentNodeVersion) + return version.IncompatibleVersionError(header.NodeVersion) } err := identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiver) diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index afba01db6..7bb442999 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -21,7 +21,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/go-centrifuge/version" "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" @@ -70,14 +69,8 @@ func TestClient_SendAnchoredDocument(t *testing.T) { tc, cid, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - self, err := cfg.GetIdentityID() - assert.NoError(t, err) - p2pheader := &p2ppb.CentrifugeHeader{ - SenderCentrifugeId: self, - CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: cfg.GetNetworkID(), - } - _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: doc, Header: p2pheader}) + + _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: doc}) if assert.Error(t, err) { assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) } diff --git a/p2p/client_test.go b/p2p/client_test.go index ba0b5421c..6e2f4344e 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -8,9 +8,9 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/golang/protobuf/proto" @@ -34,10 +34,6 @@ type MockMessenger struct { mock.Mock } -func (mm *MockMessenger) addHandler(mType protocolpb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *protocolpb.P2PEnvelope) (*protocolpb.P2PEnvelope, error)) { - mm.Called(mType, handler) -} - func (mm *MockMessenger) init(id ...protocol.ID) { mm.Called(id) } @@ -60,14 +56,11 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - assert.NoError(t, err) - sender, err := c.GetIdentityID() - assert.Nil(t, err, "sender centrifugeId not initialized correctly ") - r, err := testClient.createSignatureRequest(sender, coreDoc) - assert.Nil(t, err, "signature request could not be created") + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) - resp, err := testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) + m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) + resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -75,6 +68,8 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { func TestGetSignatureForDocument_fail_version_check(t *testing.T) { centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + assert.Nil(t, err, "centrifugeId not initialized correctly ") + idService := getIDMocks(centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, mes: m, disablePeerStore: true} @@ -82,17 +77,12 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) - resp := &p2ppb.SignatureResponse{CentNodeVersion: "1.0.0"} - assert.Nil(t, err, "centrifugeId not initialized correctly ") - assert.NoError(t, err) - sender, err := c.GetIdentityID() - assert.Nil(t, err, "sender centrifugeId not initialized correctly ") - r, err := testClient.createSignatureRequest(sender, coreDoc) - assert.Nil(t, err, "signature request could not be created") + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) - resp, err = testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) + m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) + resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -111,17 +101,14 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - assert.NoError(t, err) - sender, err := c.GetIdentityID() - assert.Nil(t, err, "sender centrifugeId not initialized correctly ") - r, err := testClient.createSignatureRequest(sender, coreDoc) - assert.Nil(t, err, "signature request could not be created") + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + assert.NoError(t, err, "signature request could not be created") randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, mock.Anything, r, receiver.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - resp, err := testClient.getSignatureForDocument(ctx, idService, coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") @@ -139,14 +126,23 @@ func getIDMocks(centrifugeId identity.CentID) *testingcommons.MockIDService { } func (s *peer) createSignatureResp(centNodeVer string, signature *coredocumentpb.Signature) *protocolpb.P2PEnvelope { - req := &p2ppb.SignatureResponse{ - CentNodeVersion: centNodeVer, - Signature: signature, + req, err := proto.Marshal(&p2ppb.SignatureResponse{Signature: signature}) + if err != nil { + return nil } - reqB, err := proto.Marshal(req) + dataReq := &p2ppb.Envelope{ + Header: &p2ppb.Header{ + NodeVersion: centNodeVer, + Type: p2pcommon.MessageTypeRequestSignatureRep.String(), + }, + Body: req, + } + + reqB, err := proto.Marshal(dataReq) if err != nil { return nil } - return &protocolpb.P2PEnvelope{Type: protocolpb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, Body: reqB} + + return &protocolpb.P2PEnvelope{Body: reqB} } diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go new file mode 100644 index 000000000..1d7c8a997 --- /dev/null +++ b/p2p/common/protocol.go @@ -0,0 +1,131 @@ +package p2pcommon + +import ( + "context" + "fmt" + "strings" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/centrifuge/go-centrifuge/version" + "github.com/golang/protobuf/proto" + "github.com/libp2p/go-libp2p-protocol" +) + +// MessageType holds the protocol message type +type MessageType string + +const ( + // CentrifugeProtocol is the centrifuge wire protocol + CentrifugeProtocol protocol.ID = "/centrifuge/0.0.1" + + // MessageTypeError defines any protocol error + MessageTypeError MessageType = "MessageTypeError" + // MessageTypeInvalid defines invalid protocol type + MessageTypeInvalid MessageType = "MessageTypeInvalid" + // MessageTypeRequestSignature defines RequestSignature type + MessageTypeRequestSignature MessageType = "MessageTypeRequestSignature" + // MessageTypeRequestSignatureRep defines RequestSignature response type + MessageTypeRequestSignatureRep MessageType = "MessageTypeRequestSignatureRep" + // MessageTypeSendAnchoredDoc defines SendAnchored type + MessageTypeSendAnchoredDoc MessageType = "MessageTypeSendAnchoredDoc" + // MessageTypeSendAnchoredDocRep defines SendAnchored response type + MessageTypeSendAnchoredDocRep MessageType = "MessageTypeSendAnchoredDocRep" +) + +// Equals compares if string is of a particular MessageType +func (mt MessageType) Equals(mt2 string) bool { + return mt.String() == mt2 +} + +// String representation +func (mt MessageType) String() string { + return string(mt) +} + +// MessageTypeFromString Resolves MessageType out of string +func MessageTypeFromString(mt string) MessageType { + var found MessageType + if MessageTypeError.Equals(mt) { + found = MessageTypeError + } else if MessageTypeInvalid.Equals(mt) { + found = MessageTypeInvalid + } else if MessageTypeRequestSignature.Equals(mt) { + found = MessageTypeRequestSignature + } else if MessageTypeRequestSignatureRep.Equals(mt) { + found = MessageTypeRequestSignatureRep + } else if MessageTypeSendAnchoredDoc.Equals(mt) { + found = MessageTypeSendAnchoredDoc + } else if MessageTypeSendAnchoredDocRep.Equals(mt) { + found = MessageTypeSendAnchoredDocRep + } + return found +} + +// ProtocolForCID creates the protocol string for the given CID +func ProtocolForCID(CID identity.CentID) protocol.ID { + return protocol.ID(fmt.Sprintf("%s/%s", CentrifugeProtocol, CID.String())) +} + +// ExtractCID extracts CID from a protocol string +func ExtractCID(id protocol.ID) (identity.CentID, error) { + parts := strings.Split(string(id), "/") + cidHexStr := parts[len(parts)-1] + return identity.CentIDFromString(cidHexStr) +} + +// ResolveDataEnvelope unwraps Content Envelope out of p2pEnvelope +func ResolveDataEnvelope(mes proto.Message) (*p2ppb.Envelope, error) { + recv, ok := mes.(*protocolpb.P2PEnvelope) + if !ok { + return nil, errors.New("cannot cast proto.Message to protocolpb.P2PEnvelope: %v", recv) + } + recvEnvelope := new(p2ppb.Envelope) + err := proto.Unmarshal(recv.Body, recvEnvelope) + if err != nil { + return nil, err + } + + // Validate at least not-nil fields + if recvEnvelope.Header == nil { + return nil, errors.New("Header field is empty") + } + + return recvEnvelope, nil +} + +// PrepareP2PEnvelope wraps content message into p2p envelope +func PrepareP2PEnvelope(ctx context.Context, networkID uint32, messageType MessageType, mes proto.Message) (*protocolpb.P2PEnvelope, error) { + self, err := contextutil.Self(ctx) + if err != nil { + return nil, err + } + + centIDBytes := self.ID[:] + p2pheader := &p2ppb.Header{ + SenderId: centIDBytes, + NodeVersion: version.GetVersion().String(), + NetworkIdentifier: networkID, + Type: messageType.String(), + } + + body, err := proto.Marshal(mes) + if err != nil { + return nil, err + } + + envelope := &p2ppb.Envelope{ + Header: p2pheader, + Body: body, + } + + marshalledRequest, err := proto.Marshal(envelope) + if err != nil { + return nil, err + } + + return &protocolpb.P2PEnvelope{Body: marshalledRequest}, nil +} diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go new file mode 100644 index 000000000..836a61b32 --- /dev/null +++ b/p2p/common/protocol_test.go @@ -0,0 +1,115 @@ +// +build unit + +package p2pcommon + +import ( + "context" + "os" + "testing" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/golang/protobuf/proto" + + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/libp2p/go-libp2p-protocol" + "github.com/stretchr/testify/assert" +) + +var cfg config.Configuration + +func TestMain(m *testing.M) { + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + } + ctx := make(map[string]interface{}) + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + +func TestExtractCID(t *testing.T) { + p := protocol.ID("/centrifuge/0.0.1/0xd9f72e705074") + cid, err := ExtractCID(p) + assert.NoError(t, err) + assert.Equal(t, "0xd9f72e705074", cid.String()) +} + +func TestProtocolForCID(t *testing.T) { + cid := identity.RandomCentID() + p := ProtocolForCID(cid) + assert.Contains(t, p, cid.String()) + cidE, err := ExtractCID(p) + assert.NoError(t, err) + assert.Equal(t, cid.String(), cidE.String()) +} + +func TestResolveDataEnvelope(t *testing.T) { + // Nil Payload + dataEnv, err := ResolveDataEnvelope(nil) + assert.Nil(t, dataEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "cannot cast proto.Message to protocolpb.P2PEnvelope") + + // Missing Header field + body, err := proto.Marshal(&p2ppb.Envelope{}) + msg := &protocolpb.P2PEnvelope{ + Body: body, + } + dataEnv, err = ResolveDataEnvelope(msg) + assert.Nil(t, dataEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "Header field is empty") + + // Success + body, err = proto.Marshal(&p2ppb.Envelope{Header: &p2ppb.Header{Type: "messageType"}}) + msg = &protocolpb.P2PEnvelope{ + Body: body, + } + dataEnv, err = ResolveDataEnvelope(msg) + assert.Nil(t, err) + assert.Equal(t, "messageType", dataEnv.Header.Type) +} + +func TestPrepareP2PEnvelope(t *testing.T) { + // Missing Self + p2pEnv, err := PrepareP2PEnvelope(context.Background(), uint32(0), MessageTypeRequestSignature, nil) + assert.Error(t, err) + assert.Nil(t, p2pEnv) + + id, _ := cfg.GetIdentityID() + spk, ssk := cfg.GetSigningKeyPair() + tc := &configstore.TenantConfig{ + IdentityID: id, + SigningKeyPair: configstore.KeyPair{ + Priv: ssk, + Pub: spk, + }, + EthAuthKeyPair: configstore.KeyPair{ + Priv: ssk, + Pub: spk, + }, + } + ctx, _ := contextutil.NewCentrifugeContext(context.Background(), tc) + assert.NotNil(t, ctx) + + // Nil proto.Message + p2pEnv, err = PrepareP2PEnvelope(ctx, uint32(0), MessageTypeRequestSignature, nil) + assert.Error(t, err) + + // Success + msg := &protocolpb.P2PEnvelope{Body: utils.RandomSlice(3)} + p2pEnv, err = PrepareP2PEnvelope(ctx, uint32(0), MessageTypeRequestSignature, msg) + assert.NoError(t, err) + assert.NotNil(t, p2pEnv) +} diff --git a/p2p/messenger.go b/p2p/messenger.go index ac7283252..89105cc93 100644 --- a/p2p/messenger.go +++ b/p2p/messenger.go @@ -7,6 +7,8 @@ import ( "sync" "time" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/go-centrifuge/errors" "github.com/libp2p/go-libp2p-host" @@ -68,17 +70,19 @@ type p2pMessenger struct { plk sync.Mutex - msgHandlers map[pb.MessageType]func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) + handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) } -func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration) *p2pMessenger { +func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration, + handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) *p2pMessenger { return &p2pMessenger{ - ctx: ctx, - host: host, - self: host.ID(), - timeout: p2pTimeout, - strmap: make(map[libp2pPeer.ID]map[protocol.ID]*messageSender), - msgHandlers: make(map[pb.MessageType]func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error))} + ctx: ctx, + host: host, + self: host.ID(), + timeout: p2pTimeout, + strmap: make(map[libp2pPeer.ID]map[protocol.ID]*messageSender), + handler: handler, + } } // init initiates listening to given set of protocol streams @@ -88,11 +92,6 @@ func (mes *p2pMessenger) init(protocols ...protocol.ID) { } } -// addHandler adds a message handler for a specific message type -func (mes *p2pMessenger) addHandler(mType pb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) { - mes.msgHandlers[mType] = handler -} - // handleNewStream implements the inet.StreamHandler func (mes *p2pMessenger) handleNewStream(s inet.Stream) { go mes.handleNewMessage(s) @@ -123,16 +122,14 @@ func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { return } - // get handler for this msg type. - handler := mes.msgHandlers[pmes.GetType()] - if handler == nil { + if mes.handler == nil { s.Reset() log.Warning("got back nil handler from handlerForMsgType") return } // dispatch handler. - rpmes, err := handler(ctx, mPeer, s.Protocol(), pmes) + rpmes, err := mes.handler(ctx, mPeer, s.Protocol(), pmes) if err != nil { s.Reset() log.Errorf("handle message error: %s", err) @@ -321,7 +318,7 @@ func (ms *messageSender) sendMessage(ctx context.Context, pmes *pb.P2PEnvelope) } } -func (ms *messageSender) writeMsg(pmes *pb.P2PEnvelope) error { +func (ms *messageSender) writeMsg(pmes proto.Message) error { if err := ms.w.WriteMsg(pmes); err != nil { return err } diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go index 1456159a3..62d481261 100644 --- a/p2p/messenger_test.go +++ b/p2p/messenger_test.go @@ -10,6 +10,10 @@ import ( "testing" "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/errors" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" @@ -24,9 +28,34 @@ import ( const MessengerDummyProtocol protocol.ID = "/messeger/dummy/0.0.1" const MessengerDummyProtocol2 protocol.ID = "/messeger/dummy/0.0.2" +var mockedHandler = func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) + if err != nil { + return nil, err + } + if p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDocRep.String() + } else if p2pcommon.MessageTypeRequestSignature.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeRequestSignatureRep.String() + } else if p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDoc.String() + } else if p2pcommon.MessageTypeError.Equals(dataEnv.Header.Type) { + return nil, errors.New("dummy error") + } else if p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type) { + return nil, nil + } else if p2pcommon.MessageTypeInvalid.Equals(dataEnv.Header.Type) { + return nil, errors.New("invalid data") + } + + return p2pcommon.PrepareP2PEnvelope(ctx, uint32(0), p2pcommon.MessageTypeFromString(dataEnv.Header.Type), dataEnv) +} + // Using a single test for all cases to use the same hosts in a synchronous way func TestHandleNewMessage(t *testing.T) { - c, canc := context.WithCancel(context.Background()) + cfg, err := cfg.GetConfig() + assert.NoError(t, err) + ctx, canc := context.WithCancel(context.Background()) + c := testingconfig.CreateTenantContextWithContext(t, ctx, cfg) r := rand.Reader p1 := 35000 p2 := 35001 @@ -37,25 +66,8 @@ func TestHandleNewMessage(t *testing.T) { // set h2 as the bootnode for h1 _ = runDHT(c, h1, []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", p2, h2.ID().Pretty())}) - m1 := newP2PMessenger(c, h1, 1*time.Second) - m1.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP}, nil - }) - m2 := newP2PMessenger(c, h2, 1*time.Second) - m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP}, nil - }) - m2.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC}, nil - }) - // error - m2.addHandler(pb.MessageType_MESSAGE_TYPE_ERROR, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - return nil, errors.New("dummy error") - }) - // nil response - message type here is irrelevant using the reply type for convenience - m2.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - return nil, nil - }) + m1 := newP2PMessenger(c, h1, 5*time.Second, mockedHandler) + m2 := newP2PMessenger(c, h2, 5*time.Second, mockedHandler) m1.init(MessengerDummyProtocol) m2.init(MessengerDummyProtocol) @@ -63,51 +75,77 @@ func TestHandleNewMessage(t *testing.T) { // 1. happy path // from h1 to h2 (with a message size ~ MessageSizeMax, has to be less because of the length bytes) - msg, err := m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(MessageSizeMax - 7)}, MessengerDummyProtocol) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax - 200)}) + assert.NoError(t, err) + msg, err := m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) + assert.NoError(t, err) + dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) assert.NoError(t, err) - assert.Equal(t, pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, msg.Type) + assert.True(t, p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type)) + // from h1 to h2 different protocol - intentionally setting reply-response in opposite for differentiation - msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, Body: utils.RandomSlice(3)}, MessengerDummyProtocol2) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDocRep, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol2) + assert.NoError(t, err) + dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) assert.NoError(t, err) - assert.Equal(t, pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, msg.Type) + assert.True(t, p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type)) + // from h2 to h1 - msg, err = m2.sendMessage(c, h1.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDoc, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m2.sendMessage(c, h1.ID(), p2pEnv, MessengerDummyProtocol) + assert.NoError(t, err) + dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) assert.NoError(t, err) - assert.Equal(t, pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, msg.Type) + assert.True(t, p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type)) // 2. unrecognized protocol - msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, "wrong") + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, "wrong") if assert.Error(t, err) { assert.Equal(t, "protocol not supported", err.Error()) } // 3. unrecognized message type - stream would be reset by the peer - msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_INVALID, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeInvalid, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) if assert.Error(t, err) { assert.Equal(t, "stream reset", err.Error()) } // 4. handler error - msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_ERROR, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeError, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) if assert.Error(t, err) { assert.Equal(t, "stream reset", err.Error()) } // 5. can't find host - h3 - msg, err = m1.sendMessage(c, h3.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(3)}, MessengerDummyProtocol) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h3.ID(), p2pEnv, MessengerDummyProtocol) if assert.Error(t, err) { assert.Contains(t, err.Error(), "dial attempt failed: failed to dial MessageSizeMax) - msg, err = m1.sendMessage(c, h2.ID(), &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, Body: utils.RandomSlice(MessageSizeMax)}, MessengerDummyProtocol) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax)}) + assert.NoError(t, err) + msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) if assert.Error(t, err) { assert.Equal(t, "stream reset", err.Error()) } diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index db9323afb..4e9b6a768 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -3,6 +3,8 @@ package receiver import ( "context" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" @@ -18,7 +20,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - "github.com/centrifuge/go-centrifuge/version" ) // getService looks up the specific registry, derives service from core document @@ -56,15 +57,17 @@ func New(config configstore.Service, registry *documents.ServiceRegistry, handsh return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator} } -// HandleRequestDocumentSignature handles the RequestDocumentSignature message -func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) { - m := new(p2ppb.SignatureRequest) - err := proto.Unmarshal(msg.Body, m) +// HandleInterceptor acts as main entry point for all message types, routes the request to the correct handler +func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) { + if msg == nil { + return convertToErrorEnvelop(errors.New("nil payload provided")) + } + envelope, err := p2pcommon.ResolveDataEnvelope(msg) if err != nil { return convertToErrorEnvelop(err) } - cid, err := ExtractCID(protoc) + cid, err := p2pcommon.ExtractCID(protoc) if err != nil { return convertToErrorEnvelop(err) } @@ -79,16 +82,46 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee return convertToErrorEnvelop(err) } - res, err := srv.RequestDocumentSignature(ctx, m) + err = srv.handshakeValidator.Validate(envelope.Header) if err != nil { return convertToErrorEnvelop(err) } - resp, err := proto.Marshal(res) + switch p2pcommon.MessageTypeFromString(envelope.Header.Type) { + case p2pcommon.MessageTypeRequestSignature: + return srv.HandleRequestDocumentSignature(ctx, peer, protoc, envelope) + case p2pcommon.MessageTypeSendAnchoredDoc: + return srv.HandleSendAnchoredDocument(ctx, peer, protoc, envelope) + default: + return convertToErrorEnvelop(errors.New("MessageType [%s] not found", envelope.Header.Type)) + } + +} + +// HandleRequestDocumentSignature handles the RequestDocumentSignature message +func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *p2ppb.Envelope) (*pb.P2PEnvelope, error) { + req := new(p2ppb.SignatureRequest) + err := proto.Unmarshal(msg.Body, req) if err != nil { return convertToErrorEnvelop(err) } - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP, Body: resp}, nil + + res, err := srv.RequestDocumentSignature(ctx, req) + if err != nil { + return convertToErrorEnvelop(err) + } + + nc, err := srv.config.GetConfig() + if err != nil { + return convertToErrorEnvelop(err) + } + + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeRequestSignatureRep, res) + if err != nil { + return convertToErrorEnvelop(err) + } + + return p2pEnv, nil } // RequestDocumentSignature signs the received document and returns the signature of the signingRoot @@ -96,11 +129,6 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - err := srv.handshakeValidator.Validate(sigReq.Header) - if err != nil { - return nil, err - } - svc, model, err := getServiceAndModel(srv.registry, sigReq.Document) if err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) @@ -111,68 +139,48 @@ func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb. return nil, centerrors.New(code.Unknown, err.Error()) } - return &p2ppb.SignatureResponse{ - CentNodeVersion: version.GetVersion().String(), - Signature: signature, - }, nil + return &p2ppb.SignatureResponse{Signature: signature}, nil } // HandleSendAnchoredDocument handles the SendAnchoredDocument message -func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) { +func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *p2ppb.Envelope) (*pb.P2PEnvelope, error) { m := new(p2ppb.AnchorDocumentRequest) err := proto.Unmarshal(msg.Body, m) if err != nil { return convertToErrorEnvelop(err) } - cid, err := ExtractCID(protoc) - if err != nil { - return convertToErrorEnvelop(err) - } - - tc, err := srv.config.GetTenant(cid[:]) + res, err := srv.SendAnchoredDocument(ctx, m, msg.Header.SenderId) if err != nil { return convertToErrorEnvelop(err) } - ctx, err = contextutil.NewCentrifugeContext(ctx, tc) + nc, err := srv.config.GetConfig() if err != nil { return convertToErrorEnvelop(err) } - res, err := srv.SendAnchoredDocument(ctx, m) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeSendAnchoredDocRep, res) if err != nil { return convertToErrorEnvelop(err) } - resp, err := proto.Marshal(res) - if err != nil { - return convertToErrorEnvelop(err) - } - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP, Body: resp}, nil + return p2pEnv, nil } // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB -func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { - err := srv.handshakeValidator.Validate(docReq.Header) - if err != nil { - return nil, err - } - +func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest, senderID []byte) (*p2ppb.AnchorDocumentResponse, error) { svc, model, err := getServiceAndModel(srv.registry, docReq.Document) if err != nil { return nil, centerrors.New(code.DocumentInvalid, err.Error()) } - err = svc.ReceiveAnchoredDocument(ctx, model, docReq.Header) + err = svc.ReceiveAnchoredDocument(ctx, model, senderID) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } - return &p2ppb.AnchorDocumentResponse{ - CentNodeVersion: version.GetVersion().String(), - Accepted: true, - }, nil + return &p2ppb.AnchorDocumentResponse{Accepted: true}, nil } func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { @@ -184,6 +192,19 @@ func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { if err != nil { return nil, err } + + envelope := &p2ppb.Envelope{ + Header: &p2ppb.Header{ + Type: p2pcommon.MessageTypeError.String(), + }, + Body: errBytes, + } + + marshalledOut, err := proto.Marshal(envelope) + if err != nil { + return nil, err + } + // an error for the client - return &pb.P2PEnvelope{Type: pb.MessageType_MESSAGE_TYPE_ERROR, Body: errBytes}, nil + return &pb.P2PEnvelope{Body: marshalledOut}, nil } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 195b5029c..1a758d256 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -32,7 +32,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/go-centrifuge/version" "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" @@ -158,7 +157,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") anchorReq := getAnchoredRequest(doc) - anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq) + anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq, idConfig.ID[:]) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) assert.Nil(t, anchorResp) @@ -169,7 +168,8 @@ func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) req := getAnchoredRequest(doc) req.Document = nil - resp, err := handler.SendAnchoredDocument(ctxh, req) + id, _ := cfg.GetIdentityID() + resp, err := handler.SendAnchoredDocument(ctxh, req, id) assert.NotNil(t, err) assert.Nil(t, resp, "must be nil") } @@ -202,11 +202,10 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") anchorReq := getAnchoredRequest(doc) - anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq) + anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") assert.True(t, anchorResp.Accepted) - assert.Equal(t, anchorResp.CentNodeVersion, anchorReq.Header.CentNodeVersion) } func createIdentity(t *testing.T) identity.CentID { @@ -268,16 +267,9 @@ func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) } func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentRequest { - return &p2ppb.AnchorDocumentRequest{ - Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: cfg.GetNetworkID(), - }, Document: doc, - } + return &p2ppb.AnchorDocumentRequest{Document: doc} } func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureRequest { - return &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID(), - }, Document: doc} + return &p2ppb.SignatureRequest{Document: doc} } diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 89d1b7e34..c680e3059 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -5,17 +5,22 @@ package receiver import ( "context" "os" - "strconv" "testing" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/version" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/proto" + "github.com/libp2p/go-libp2p-protocol" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -24,17 +29,17 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/version" "github.com/golang/protobuf/ptypes/any" + libp2pPeer "github.com/libp2p/go-libp2p-peer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) var ( - grpcHandler p2ppb.P2PServiceServer - registry *documents.ServiceRegistry - coreDoc = testingcoredocument.GenerateCoreDocument() - cfg config.Configuration + handler *Handler + registry *documents.ServiceRegistry + coreDoc = testingcoredocument.GenerateCoreDocument() + cfg config.Configuration ) func TestMain(m *testing.M) { @@ -52,100 +57,143 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - grpcHandler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) + handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) } func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { - req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID(), - }} + req := &p2ppb.SignatureRequest{} + + resp, err := handler.RequestDocumentSignature(context.Background(), req) + assert.Error(t, err, "must return error") + assert.Nil(t, resp, "must be nil") +} + +func TestHandler_HandleInterceptor_nilPayload(t *testing.T) { + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("protocolX"), nil) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "nil payload provided") + assert.Nil(t, resp, "must be nil") +} + +func TestHandler_HandleInterceptor_HeaderEmpty(t *testing.T) { + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("protocolX"), &protocolpb.P2PEnvelope{}) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "Header field is empty") + assert.Nil(t, resp, "must be nil") +} - resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) +func TestHandler_HandleInterceptor_CentIDNotHex(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("protocolX"), p2pEnv) assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "hex string without 0x prefix") assert.Nil(t, resp, "must be nil") } -func TestHandler_RequestDocumentSignature_version_fail(t *testing.T) { - req := &p2ppb.SignatureRequest{Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: "1000.0.1-invalid", NetworkIdentifier: cfg.GetNetworkID(), - }} +func TestHandler_HandleInterceptor_TenantNotFound(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("0x001100110011"), p2pEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "model not found in db") + assert.Nil(t, resp, "must be nil") +} + +func TestHandler_HandleInterceptor_HandshakeValidationFail(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) + + // Manipulate version in Header + dataEnv, _ := p2pcommon.ResolveDataEnvelope(p2pEnv) + dataEnv.Header.NodeVersion = "incompatible" + marshalledRequest, err := proto.Marshal(dataEnv) + assert.NoError(t, err) + p2pEnv = &protocolpb.P2PEnvelope{Body: marshalledRequest} - resp, err := grpcHandler.RequestDocumentSignature(context.Background(), req) + id, _ := cfg.GetIdentityID() + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "Incompatible version") assert.Nil(t, resp, "must be nil") + + // Manipulate network in Header + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(ctx, uint32(999), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) + + resp, err = handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "Incompatible network id") + assert.Nil(t, resp, "must be nil") } -func TestSendAnchoredDocument_IncompatibleRequest(t *testing.T) { - // Test invalid version - header := &p2ppb.CentrifugeHeader{ - CentNodeVersion: "1000.0.0-invalid", - NetworkIdentifier: cfg.GetNetworkID(), - } - req := p2ppb.AnchorDocumentRequest{Document: coreDoc, Header: header} - res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) - assert.Error(t, err) - p2perr, _ := centerrors.FromError(err) - assert.Contains(t, p2perr.Message(), strconv.Itoa(int(code.VersionMismatch))) - assert.Nil(t, res) - - // Test invalid network - header.NetworkIdentifier = cfg.GetNetworkID() + 1 - header.CentNodeVersion = version.GetVersion().String() - res, err = grpcHandler.SendAnchoredDocument(context.Background(), &req) - assert.Error(t, err) - p2perr, _ = centerrors.FromError(err) - assert.Contains(t, p2perr.Message(), strconv.Itoa(int(code.NetworkMismatch))) - assert.Nil(t, res) +func TestHandler_HandleInterceptor_UnsupportedMessageType(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) + + // Manipulate message type in Header + dataEnv, _ := p2pcommon.ResolveDataEnvelope(p2pEnv) + dataEnv.Header.Type = "UnsupportedType" + marshalledRequest, err := proto.Marshal(dataEnv) + assert.NoError(t, err) + p2pEnv = &protocolpb.P2PEnvelope{Body: marshalledRequest} + + id, _ := cfg.GetIdentityID() + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "MessageType [UnsupportedType] not found") + assert.Nil(t, resp, "must be nil") } -func TestSendAnchoredDocument_NilDocument(t *testing.T) { - header := &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: cfg.GetNetworkID(), - } - req := p2ppb.AnchorDocumentRequest{Header: header} - res, err := grpcHandler.SendAnchoredDocument(context.Background(), &req) +func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) + assert.NoError(t, err) - assert.Error(t, err) - assert.Nil(t, res) + id, _ := cfg.GetIdentityID() + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + assert.Error(t, err, "must return error") + assert.Contains(t, err.Error(), "nil core document") + assert.Nil(t, resp, "must be nil") } -func TestHandler_SendAnchoredDocument_getServiceAndModel_fail(t *testing.T) { - req := &p2ppb.AnchorDocumentRequest{ - Header: &p2ppb.CentrifugeHeader{ - CentNodeVersion: version.GetVersion().String(), - NetworkIdentifier: cfg.GetNetworkID(), - }, - Document: coredocument.New(), - } +func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { + ctx := testingconfig.CreateTenantContext(t, cfg) + req := &p2ppb.AnchorDocumentRequest{Document: coredocument.New()} + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDoc, req) + assert.NoError(t, err) - res, err := grpcHandler.SendAnchoredDocument(context.Background(), req) - assert.Error(t, err) + id, _ := cfg.GetIdentityID() + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "failed to get type of the document") - assert.Nil(t, res) + assert.Nil(t, resp, "must be nil") } func TestP2PService_basicChecks(t *testing.T) { tests := []struct { - header *p2ppb.CentrifugeHeader + header *p2ppb.Header err error }{ { - header: &p2ppb.CentrifugeHeader{CentNodeVersion: "someversion", NetworkIdentifier: 12}, + header: &p2ppb.Header{NodeVersion: "someversion", NetworkIdentifier: 12}, err: errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), }, { - header: &p2ppb.CentrifugeHeader{CentNodeVersion: "0.0.1", NetworkIdentifier: 12}, + header: &p2ppb.Header{NodeVersion: "0.0.1", NetworkIdentifier: 12}, err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), }, { - header: &p2ppb.CentrifugeHeader{CentNodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}, + header: &p2ppb.Header{NodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}, }, } diff --git a/p2p/receiver/protocol.go b/p2p/receiver/protocol.go deleted file mode 100644 index 0cf8786e2..000000000 --- a/p2p/receiver/protocol.go +++ /dev/null @@ -1,24 +0,0 @@ -package receiver - -import ( - "fmt" - "strings" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/libp2p/go-libp2p-protocol" -) - -// CentrifugeProtocol is the centrifuge wire protocol -const CentrifugeProtocol protocol.ID = "/centrifuge/0.0.1" - -// ProtocolForCID creates the protocol string for the given CID -func ProtocolForCID(CID identity.CentID) protocol.ID { - return protocol.ID(fmt.Sprintf("%s/%s", CentrifugeProtocol, CID.String())) -} - -// ExtractCID extracts CID from a protocol string -func ExtractCID(id protocol.ID) (identity.CentID, error) { - parts := strings.Split(string(id), "/") - cidHexStr := parts[len(parts)-1] - return identity.CentIDFromString(cidHexStr) -} diff --git a/p2p/receiver/protocol_test.go b/p2p/receiver/protocol_test.go deleted file mode 100644 index 8a98bdf92..000000000 --- a/p2p/receiver/protocol_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package receiver - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/libp2p/go-libp2p-protocol" - "github.com/stretchr/testify/assert" -) - -func TestExtractCID(t *testing.T) { - p := protocol.ID("/centrifuge/0.0.1/0xd9f72e705074") - cid, err := ExtractCID(p) - assert.NoError(t, err) - assert.Equal(t, "0xd9f72e705074", cid.String()) -} - -func TestProtocolForCID(t *testing.T) { - cid := identity.RandomCentID() - p := ProtocolForCID(cid) - assert.Contains(t, p, cid.String()) - cidE, err := ExtractCID(p) - assert.NoError(t, err) - assert.Equal(t, cid.String(), cidE.String()) -} diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 0bfe03ca8..90e157848 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -13,14 +13,14 @@ import ( // Validator defines method that must be implemented by any validator type. type Validator interface { // Validate validates p2p requests - Validate(header *p2ppb.CentrifugeHeader) error + Validate(header *p2ppb.Header) error } // ValidatorGroup implements Validator for validating a set of validators. type ValidatorGroup []Validator // Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(header *p2ppb.CentrifugeHeader) (errs error) { +func (group ValidatorGroup) Validate(header *p2ppb.Header) (errs error) { for _, v := range group { if err := v.Validate(header); err != nil { errs = errors.AppendError(errs, err) @@ -31,28 +31,28 @@ func (group ValidatorGroup) Validate(header *p2ppb.CentrifugeHeader) (errs error // ValidatorFunc implements Validator and can be used as a adaptor for functions // with specific function signature -type ValidatorFunc func(header *p2ppb.CentrifugeHeader) error +type ValidatorFunc func(header *p2ppb.Header) error // Validate passes the arguments to the underlying validator // function and returns the results -func (vf ValidatorFunc) Validate(header *p2ppb.CentrifugeHeader) error { +func (vf ValidatorFunc) Validate(header *p2ppb.Header) error { return vf(header) } func versionValidator() Validator { - return ValidatorFunc(func(header *p2ppb.CentrifugeHeader) error { + return ValidatorFunc(func(header *p2ppb.Header) error { if header == nil { return errors.New("nil header") } - if !version.CheckVersion(header.CentNodeVersion) { - return version.IncompatibleVersionError(header.CentNodeVersion) + if !version.CheckVersion(header.NodeVersion) { + return version.IncompatibleVersionError(header.NodeVersion) } return nil }) } func networkValidator(networkID uint32) Validator { - return ValidatorFunc(func(header *p2ppb.CentrifugeHeader) error { + return ValidatorFunc(func(header *p2ppb.Header) error { if header == nil { return errors.New("nil header") } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 5d8ac9329..6be5b3f31 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -18,22 +18,22 @@ func TestValidate_versionValidator(t *testing.T) { assert.NotNil(t, err) // Empty header - header := &p2ppb.CentrifugeHeader{} + header := &p2ppb.Header{} err = vv.Validate(header) assert.NotNil(t, err) // Incompatible Major - header.CentNodeVersion = "1.1.1" + header.NodeVersion = "1.1.1" err = vv.Validate(header) assert.NotNil(t, err) // Compatible Minor - header.CentNodeVersion = "0.1.1" + header.NodeVersion = "0.1.1" err = vv.Validate(header) assert.Nil(t, err) //Same version - header.CentNodeVersion = version.GetVersion().String() + header.NodeVersion = version.GetVersion().String() err = vv.Validate(header) assert.Nil(t, err) } @@ -45,7 +45,7 @@ func TestValidate_networkValidator(t *testing.T) { err := nv.Validate(nil) assert.NotNil(t, err) - header := &p2ppb.CentrifugeHeader{} + header := &p2ppb.Header{} err = nv.Validate(header) assert.NotNil(t, err) @@ -64,8 +64,8 @@ func TestValidate_handshakeValidator(t *testing.T) { hv := HandshakeValidator(cfg.GetNetworkID()) // Incompatible version and network - header := &p2ppb.CentrifugeHeader{ - CentNodeVersion: "version", + header := &p2ppb.Header{ + NodeVersion: "version", NetworkIdentifier: 52, } err := hv.Validate(header) @@ -78,7 +78,7 @@ func TestValidate_handshakeValidator(t *testing.T) { // Compatible version, incorrect network header.NetworkIdentifier = 52 - header.CentNodeVersion = version.GetVersion().String() + header.NodeVersion = version.GetVersion().String() err = hv.Validate(header) assert.NotNil(t, err) diff --git a/p2p/server.go b/p2p/server.go index 7184a3e71..cadf5e1a0 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -10,9 +10,10 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/p2p/receiver" - pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/libp2p/go-libp2p-protocol" "github.com/centrifuge/go-centrifuge/errors" @@ -36,8 +37,6 @@ var log = logging.Logger("p2p-server") // messenger is an interface to wrap p2p messaging implementation type messenger interface { - addHandler(mType pb.MessageType, handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) - init(protocols ...protocol.ID) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) @@ -85,11 +84,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- return } - s.mes = newP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout()) - handler := s.handlerCreator() - s.mes.addHandler(pb.MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC, handler.HandleSendAnchoredDocument) - s.mes.addHandler(pb.MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE, handler.HandleRequestDocumentSignature) - + s.mes = newP2PMessenger(ctx, s.host, nc.P2PConnectionTimeout, s.handlerCreator().HandleInterceptor) tcs, err := s.config.GetAllTenants() if err != nil { startupErr <- err @@ -102,7 +97,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- startupErr <- err return } - protocols = append(protocols, receiver.ProtocolForCID(CID)) + protocols = append(protocols, p2pcommon.ProtocolForCID(CID)) } s.mes.init(protocols...) diff --git a/protobufs/gen/go/protocol/protocol.pb.go b/protobufs/gen/go/protocol/protocol.pb.go index 0cf85fcd6..b1e4d5335 100644 --- a/protobufs/gen/go/protocol/protocol.pb.go +++ b/protobufs/gen/go/protocol/protocol.pb.go @@ -18,44 +18,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package -type MessageType int32 - -const ( - MessageType_MESSAGE_TYPE_INVALID MessageType = 0 - MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE MessageType = 1 - MessageType_MESSAGE_TYPE_REQUEST_SIGNATURE_REP MessageType = 2 - MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC MessageType = 3 - MessageType_MESSAGE_TYPE_SEND_ANCHORED_DOC_REP MessageType = 4 - MessageType_MESSAGE_TYPE_ERROR MessageType = 5 -) - -var MessageType_name = map[int32]string{ - 0: "MESSAGE_TYPE_INVALID", - 1: "MESSAGE_TYPE_REQUEST_SIGNATURE", - 2: "MESSAGE_TYPE_REQUEST_SIGNATURE_REP", - 3: "MESSAGE_TYPE_SEND_ANCHORED_DOC", - 4: "MESSAGE_TYPE_SEND_ANCHORED_DOC_REP", - 5: "MESSAGE_TYPE_ERROR", -} -var MessageType_value = map[string]int32{ - "MESSAGE_TYPE_INVALID": 0, - "MESSAGE_TYPE_REQUEST_SIGNATURE": 1, - "MESSAGE_TYPE_REQUEST_SIGNATURE_REP": 2, - "MESSAGE_TYPE_SEND_ANCHORED_DOC": 3, - "MESSAGE_TYPE_SEND_ANCHORED_DOC_REP": 4, - "MESSAGE_TYPE_ERROR": 5, -} - -func (x MessageType) String() string { - return proto.EnumName(MessageType_name, int32(x)) -} -func (MessageType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_protocol_79283badde166d66, []int{0} -} - type P2PEnvelope struct { - // defines what type of message it is. (if we modify centrifuge-protobufs we can use type any with typeURL here) - Type MessageType `protobuf:"varint,1,opt,name=type,proto3,enum=protocol.MessageType" json:"type,omitempty"` // serialized protobuf for the actual message Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -67,7 +30,7 @@ func (m *P2PEnvelope) Reset() { *m = P2PEnvelope{} } func (m *P2PEnvelope) String() string { return proto.CompactTextString(m) } func (*P2PEnvelope) ProtoMessage() {} func (*P2PEnvelope) Descriptor() ([]byte, []int) { - return fileDescriptor_protocol_79283badde166d66, []int{0} + return fileDescriptor_protocol_989700cde17ecb56, []int{0} } func (m *P2PEnvelope) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_P2PEnvelope.Unmarshal(m, b) @@ -87,13 +50,6 @@ func (m *P2PEnvelope) XXX_DiscardUnknown() { var xxx_messageInfo_P2PEnvelope proto.InternalMessageInfo -func (m *P2PEnvelope) GetType() MessageType { - if m != nil { - return m.Type - } - return MessageType_MESSAGE_TYPE_INVALID -} - func (m *P2PEnvelope) GetBody() []byte { if m != nil { return m.Body @@ -103,27 +59,17 @@ func (m *P2PEnvelope) GetBody() []byte { func init() { proto.RegisterType((*P2PEnvelope)(nil), "protocol.P2PEnvelope") - proto.RegisterEnum("protocol.MessageType", MessageType_name, MessageType_value) } -func init() { proto.RegisterFile("protocol/protocol.proto", fileDescriptor_protocol_79283badde166d66) } +func init() { proto.RegisterFile("protocol/protocol.proto", fileDescriptor_protocol_989700cde17ecb56) } -var fileDescriptor_protocol_79283badde166d66 = []byte{ - // 249 bytes of a gzipped FileDescriptorProto +var fileDescriptor_protocol_989700cde17ecb56 = []byte{ + // 104 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2f, 0x28, 0xca, 0x2f, - 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x87, 0x31, 0xf4, 0xc0, 0x0c, 0x21, 0x0e, 0x18, 0x5f, 0xc9, 0x87, - 0x8b, 0x3b, 0xc0, 0x28, 0xc0, 0x35, 0xaf, 0x2c, 0x35, 0x27, 0xbf, 0x20, 0x55, 0x48, 0x93, 0x8b, - 0xa5, 0xa4, 0xb2, 0x20, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0xcf, 0x48, 0x54, 0x0f, 0xae, 0xcf, - 0x37, 0xb5, 0xb8, 0x38, 0x31, 0x3d, 0x35, 0xa4, 0xb2, 0x20, 0x35, 0x08, 0xac, 0x44, 0x48, 0x88, - 0x8b, 0x25, 0x29, 0x3f, 0xa5, 0x52, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xcc, 0xd6, 0xba, - 0xce, 0xc8, 0xc5, 0x8d, 0xa4, 0x52, 0x48, 0x82, 0x4b, 0xc4, 0xd7, 0x35, 0x38, 0xd8, 0xd1, 0xdd, - 0x35, 0x3e, 0x24, 0x32, 0xc0, 0x35, 0xde, 0xd3, 0x2f, 0xcc, 0xd1, 0xc7, 0xd3, 0x45, 0x80, 0x41, - 0x48, 0x89, 0x4b, 0x0e, 0x45, 0x26, 0xc8, 0x35, 0x30, 0xd4, 0x35, 0x38, 0x24, 0x3e, 0xd8, 0xd3, - 0xdd, 0xcf, 0x31, 0x24, 0x34, 0xc8, 0x55, 0x80, 0x51, 0x48, 0x8d, 0x4b, 0x09, 0xbf, 0x9a, 0xf8, - 0x20, 0xd7, 0x00, 0x01, 0x26, 0x0c, 0xb3, 0x82, 0x5d, 0xfd, 0x5c, 0xe2, 0x1d, 0xfd, 0x9c, 0x3d, - 0xfc, 0x83, 0x5c, 0x5d, 0xe2, 0x5d, 0xfc, 0x9d, 0x05, 0x98, 0x31, 0xcc, 0xc2, 0x50, 0x03, 0x36, - 0x8b, 0x45, 0x48, 0x8c, 0x4b, 0x08, 0x45, 0x9d, 0x6b, 0x50, 0x90, 0x7f, 0x90, 0x00, 0xab, 0x93, - 0x36, 0x17, 0x4f, 0x72, 0x7e, 0x2e, 0x3c, 0x3c, 0x9c, 0x78, 0x03, 0xa0, 0x2c, 0x30, 0x1d, 0xc0, - 0x18, 0xc5, 0x05, 0x93, 0x2a, 0x48, 0x4a, 0x62, 0x03, 0xb3, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, - 0xff, 0x0e, 0x36, 0x74, 0x34, 0x80, 0x01, 0x00, 0x00, + 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 0x87, 0x31, 0xf4, 0xc0, 0x0c, 0x21, 0x0e, 0x18, 0x5f, 0x49, 0x91, + 0x8b, 0x3b, 0xc0, 0x28, 0xc0, 0x35, 0xaf, 0x2c, 0x35, 0x27, 0xbf, 0x20, 0x55, 0x48, 0x88, 0x8b, + 0x25, 0x29, 0x3f, 0xa5, 0x52, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xcc, 0x76, 0xd2, 0xe6, + 0xe2, 0x49, 0xce, 0xcf, 0xd5, 0x83, 0x69, 0x71, 0xe2, 0x0d, 0x80, 0xb2, 0xc0, 0x74, 0x00, 0x63, + 0x14, 0x17, 0x4c, 0xaa, 0x20, 0x29, 0x89, 0x0d, 0xcc, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, + 0xc7, 0xdc, 0x5f, 0x90, 0x7b, 0x00, 0x00, 0x00, } diff --git a/protobufs/protocol/protocol.proto b/protobufs/protocol/protocol.proto index 0deea7a8b..884a6aee8 100644 --- a/protobufs/protocol/protocol.proto +++ b/protobufs/protocol/protocol.proto @@ -7,18 +7,7 @@ option java_multiple_files = true; option java_outer_classname = "ProtocolProto"; option java_package = "com.protocol"; -enum MessageType { - MESSAGE_TYPE_INVALID = 0; - MESSAGE_TYPE_REQUEST_SIGNATURE = 1; - MESSAGE_TYPE_REQUEST_SIGNATURE_REP = 2; - MESSAGE_TYPE_SEND_ANCHORED_DOC = 3; - MESSAGE_TYPE_SEND_ANCHORED_DOC_REP = 4; - MESSAGE_TYPE_ERROR = 5; -} - message P2PEnvelope { - // defines what type of message it is. (if we modify centrifuge-protobufs we can use type any with typeURL here) - MessageType type = 1; // serialized protobuf for the actual message bytes body = 2; } diff --git a/testingutils/commons/mock_p2p.go b/testingutils/commons/mock_p2p.go index 4bd509e58..67948f605 100644 --- a/testingutils/commons/mock_p2p.go +++ b/testingutils/commons/mock_p2p.go @@ -5,7 +5,6 @@ package testingcommons import ( "context" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/stretchr/testify/mock" "google.golang.org/grpc" @@ -27,18 +26,3 @@ func (p2p *P2PMockClient) SendAnchoredDocument(ctx context.Context, in *p2ppb.An resp, _ := args.Get(0).(*p2ppb.AnchorDocumentResponse) return resp, args.Error(1) } - -type MockP2PWrapperClient struct { - mock.Mock - P2PMockClient *P2PMockClient -} - -func (m *MockP2PWrapperClient) OpenClient(target string) (p2ppb.P2PServiceClient, error) { - m.P2PMockClient = &P2PMockClient{} - return m.P2PMockClient, nil -} - -func (m *MockP2PWrapperClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { - m.Called(ctx, doc) - return nil -} diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 72a1be6d7..937c149db 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -161,9 +161,14 @@ func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { } func CreateTenantContext(t *testing.T, cfg config.Configuration) context.Context { + return CreateTenantContextWithContext(t, context.Background(), cfg) +} + +func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg config.Configuration) context.Context { tc, err := configstore.NewTenantConfig("", cfg) assert.Nil(t, err) - contextHeader, err := contextutil.NewCentrifugeContext(context.Background(), tc) + + contextHeader, err := contextutil.NewCentrifugeContext(ctx, tc) assert.Nil(t, err) return contextHeader } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 99e846ee6..09fd0c666 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -6,7 +6,6 @@ import ( "context" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/documents" "github.com/stretchr/testify/mock" ) @@ -45,7 +44,7 @@ func (m *MockService) RequestDocumentSignature(ctx context.Context, model docume return args.Get(0).(*coredocumentpb.Signature), args.Error(1) } -func (m *MockService) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, headers *p2ppb.CentrifugeHeader) error { +func (m *MockService) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error { args := m.Called() return args.Error(0) } From 058e9eadbbc05c9c895d0397714a6196500dac5a Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Sun, 13 Jan 2019 21:51:56 +0100 Subject: [PATCH 129/220] Fix storage <--> config cycles (#633) * Fix storage <--> config cycles * Fix test * Fix lint * merge issues * merge issues --- api/bootstrapper.go | 3 +- api/server_test.go | 5 +- api/service.go | 3 +- bootstrap/bootstrappers/bootstrapper.go | 6 +- .../testingbootstrap/testing_bootstrap.go | 4 +- config/configstore/bootstrapper.go | 8 ++- config/configstore/bootstrapper_test.go | 6 +- config/configstore/handler.go | 30 +++++---- config/configstore/handler_test.go | 67 +++++++++++-------- config/configstore/mock_service.go | 21 +++--- config/configstore/model.go | 22 ++++-- config/configstore/model_test.go | 44 +++++++++--- config/configstore/repository.go | 49 +++++++------- config/configstore/repository_test.go | 27 +++++--- config/configstore/service.go | 45 ++++++------- config/configstore/service_test.go | 41 ++++++++---- config/configuration.go | 55 +++++++++++++++ contextutil/context.go | 14 ++-- documents/anchor_task.go | 6 +- documents/bootstrapper.go | 3 +- documents/bootstrapper_test.go | 11 +-- documents/genericdoc/service_test.go | 7 +- documents/handler.go | 6 +- documents/invoice/handler.go | 6 +- documents/invoice/model_test.go | 8 +-- documents/invoice/service_test.go | 7 +- documents/model.go | 13 +--- documents/model_test.go | 9 +-- documents/purchaseorder/handler.go | 6 +- documents/purchaseorder/model_test.go | 8 +-- documents/purchaseorder/service_test.go | 6 +- documents/test_bootstrapper.go | 1 - nft/bootstrapper_test.go | 5 +- nft/ethereum_payment_obligation.go | 9 ++- nft/handler.go | 8 +-- nft/handler_test.go | 4 +- notification/notification.go | 2 +- p2p/bootstrapper.go | 3 +- p2p/client.go | 4 +- p2p/client_integration_test.go | 15 +++-- p2p/client_test.go | 6 +- p2p/receiver/handler.go | 10 +-- p2p/receiver/handler_integration_test.go | 2 +- p2p/receiver/handler_test.go | 7 +- p2p/server.go | 15 +++-- p2p/server_test.go | 37 +++++----- storage/{ => leveldb}/bootstrapper.go | 14 ++-- storage/{ => leveldb}/bootstrapper_test.go | 2 +- storage/{ => leveldb}/leveldb.go | 44 ++++++------ storage/{ => leveldb}/leveldb_test.go | 20 +++--- storage/{ => leveldb}/test_bootstrapper.go | 7 +- storage/{ => leveldb}/util.go | 2 +- storage/repository.go | 7 ++ transactions/bootstrapper_test.go | 11 +-- transactions/handler.go | 13 ++-- transactions/handler_test.go | 7 +- transactions/repository_test.go | 4 +- 57 files changed, 488 insertions(+), 317 deletions(-) rename storage/{ => leveldb}/bootstrapper.go (72%) rename storage/{ => leveldb}/bootstrapper_test.go (94%) rename storage/{ => leveldb}/leveldb.go (67%) rename storage/{ => leveldb}/leveldb_test.go (86%) rename storage/{ => leveldb}/test_bootstrapper.go (87%) rename storage/{ => leveldb}/util.go (95%) diff --git a/api/bootstrapper.go b/api/bootstrapper.go index a18f773ad..1334cfdad 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -2,6 +2,7 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -17,7 +18,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - _, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + _, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("config store not initialised") } diff --git a/api/server_test.go b/api/server_test.go index fec971c5c..32e25b6e8 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/identity/ethid" @@ -28,7 +30,6 @@ import ( "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" @@ -48,7 +49,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, diff --git a/api/service.go b/api/service.go index 54e6d7c76..b758eeb2b 100644 --- a/api/service.go +++ b/api/service.go @@ -2,6 +2,7 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -36,7 +37,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, return errors.New("failed to get %s", documents.BootstrappedRegistry) } - configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(configstore.Service) + configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("failed to get %s", configstore.BootstrappedConfigStorage) } diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 33f6c07d8..18d9463ad 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -17,7 +17,7 @@ import ( "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/version" log2 "github.com/ipfs/go-log" @@ -35,7 +35,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { m.Bootstrappers = []bootstrap.Bootstrapper{ &version.Bootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, transactions.Bootstrapper{}, ethereum.Bootstrapper{}, @@ -59,7 +59,7 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { m.Bootstrappers = []bootstrap.Bootstrapper{ &version.Bootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index d3dd86476..08f000b7e 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -18,7 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/transactions" logging "github.com/ipfs/go-log" @@ -29,7 +29,7 @@ var log = logging.Logger("context") var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, &configstore.Bootstrapper{}, ethereum.Bootstrapper{}, diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 7c0c12e5d..7ef0b4774 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -38,12 +38,16 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) } } - tc, err := NewTenantConfig(nc.MainIdentity.EthereumDefaultAccountName, cfg) + tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), cfg) if err != nil { return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) } configdb.Register(tc) - _, err = service.GetTenant(nc.MainIdentity.ID()) + i, err := nc.GetIdentityID() + if err != nil { + return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + } + _, err = service.GetTenant(i) // if main tenant config doesn't exist in the db, add it // Another additional check we can do is check if there are more than 0 tenant configs in the db but main tenant is not, then it might indicate a problem if err != nil { diff --git a/config/configstore/bootstrapper_test.go b/config/configstore/bootstrapper_test.go index b403d3dd4..abdb93c5e 100644 --- a/config/configstore/bootstrapper_test.go +++ b/config/configstore/bootstrapper_test.go @@ -15,12 +15,14 @@ func TestBootstrapper_BootstrapHappy(t *testing.T) { b := Bootstrapper{} err := b.Bootstrap(ctx) assert.NoError(t, err) - configService, ok := ctx[BootstrappedConfigStorage].(Service) + configService, ok := ctx[BootstrappedConfigStorage].(config.Service) assert.True(t, ok) _, err = configService.GetConfig() assert.NoError(t, err) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) nc := NewNodeConfig(cfg) - _, err = configService.GetTenant(nc.MainIdentity.IdentityID) + i, err := nc.GetIdentityID() + assert.NoError(t, err) + _, err = configService.GetTenant(i) assert.NoError(t, err) } diff --git a/config/configstore/handler.go b/config/configstore/handler.go index b5e207b42..31127d26f 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -3,6 +3,8 @@ package configstore import ( "context" + "github.com/centrifuge/go-centrifuge/config" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" @@ -13,18 +15,18 @@ import ( var apiLog = logging.Logger("config-api") type grpcHandler struct { - service Service + service config.Service } // GRPCHandler returns an implementation of configpb.ConfigServiceServer -func GRPCHandler(svc Service) configpb.ConfigServiceServer { +func GRPCHandler(svc config.Service) configpb.ConfigServiceServer { return &grpcHandler{service: svc} } -func (h grpcHandler) deriveAllTenantResponse(cfgs []*TenantConfig) (*configpb.GetAllTenantResponse, error) { +func (h grpcHandler) deriveAllTenantResponse(cfgs []config.TenantConfiguration) (*configpb.GetAllTenantResponse, error) { response := new(configpb.GetAllTenantResponse) for _, t := range cfgs { - response.Data = append(response.Data, t.createProtobuf()) + response.Data = append(response.Data, t.CreateProtobuf()) } return response, nil } @@ -34,7 +36,7 @@ func (h grpcHandler) GetConfig(ctx context.Context, _ *empty.Empty) (*configpb.C if err != nil { return nil, err } - return nodeConfig.createProtobuf(), nil + return nodeConfig.CreateProtobuf(), nil } func (h grpcHandler) GetTenant(ctx context.Context, req *configpb.GetTenantRequest) (*configpb.TenantData, error) { @@ -46,7 +48,7 @@ func (h grpcHandler) GetTenant(ctx context.Context, req *configpb.GetTenantReque if err != nil { return nil, err } - return tenantConfig.createProtobuf(), nil + return tenantConfig.CreateProtobuf(), nil } func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*configpb.GetAllTenantResponse, error) { @@ -64,22 +66,22 @@ func (h grpcHandler) CreateConfig(ctx context.Context, data *configpb.ConfigData if err != nil { return nil, err } - nodeConfig, err = h.service.CreateConfig(nodeConfig) + nc, err := h.service.CreateConfig(nodeConfig) if err != nil { return nil, err } - return nodeConfig.createProtobuf(), nil + return nc.CreateProtobuf(), nil } func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData) (*configpb.TenantData, error) { apiLog.Infof("Creating tenant config: %v", data) tenantConfig := new(TenantConfig) tenantConfig.loadFromProtobuf(data) - tenantConfig, err := h.service.CreateTenant(tenantConfig) + tc, err := h.service.CreateTenant(tenantConfig) if err != nil { return nil, err } - return tenantConfig.createProtobuf(), nil + return tc.CreateProtobuf(), nil } func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { @@ -89,22 +91,22 @@ func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData if err != nil { return nil, err } - nodeConfig, err = h.service.UpdateConfig(nodeConfig) + nc, err := h.service.UpdateConfig(nodeConfig) if err != nil { return nil, err } - return nodeConfig.createProtobuf(), nil + return nc.CreateProtobuf(), nil } func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenantRequest) (*configpb.TenantData, error) { apiLog.Infof("Updating tenant config: %v", req) tenantConfig := new(TenantConfig) tenantConfig.loadFromProtobuf(req.Data) - tenantConfig, err := h.service.UpdateTenant(tenantConfig) + tc, err := h.service.UpdateTenant(tenantConfig) if err != nil { return nil, err } - return tenantConfig.createProtobuf(), nil + return tc.CreateProtobuf(), nil } func (h grpcHandler) DeleteConfig(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) { diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index da2aa4988..807b1cfa2 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -29,7 +29,7 @@ func TestGrpcHandler_GetConfig(t *testing.T) { svc := DefaultService(repo) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) readCfg, err := h.GetConfig(context.Background(), nil) assert.Nil(t, err) @@ -53,11 +53,13 @@ func TestGrpcHandler_GetTenant(t *testing.T) { repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo) h := GRPCHandler(svc) - nodeCfg, err := NewTenantConfig("main", cfg) + tenantCfg, err := NewTenantConfig("main", cfg) + assert.Nil(t, err) + _, err = h.CreateTenant(context.Background(), tenantCfg.CreateProtobuf()) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + tid, err := tenantCfg.GetIdentityID() assert.Nil(t, err) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) assert.NotNil(t, readCfg) } @@ -68,12 +70,13 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo) h := GRPCHandler(svc) - nodeCfg1, err := NewTenantConfig("main", cfg) - nodeCfg2, err := NewTenantConfig("main", cfg) - nodeCfg2.IdentityID = []byte("0x123456789") - _, err = h.CreateTenant(context.Background(), nodeCfg1.createProtobuf()) + tenantCfg1, err := NewTenantConfig("main", cfg) + tenantCfg2, err := NewTenantConfig("main", cfg) + tc := tenantCfg2.(*TenantConfig) + tc.IdentityID = []byte("0x123456789") + _, err = h.CreateTenant(context.Background(), tenantCfg1.CreateProtobuf()) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg2.createProtobuf()) + _, err = h.CreateTenant(context.Background(), tc.CreateProtobuf()) assert.Nil(t, err) resp, err := h.GetAllTenants(context.Background(), nil) @@ -88,11 +91,11 @@ func TestGrpcHandler_CreateConfig(t *testing.T) { svc := DefaultService(repo) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) // Already exists - _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.NotNil(t, err) } @@ -104,11 +107,11 @@ func TestGrpcHandler_CreateTenant(t *testing.T) { h := GRPCHandler(svc) nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) // Already exists - _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) assert.NotNil(t, err) } @@ -121,18 +124,19 @@ func TestGrpcHandler_UpdateConfig(t *testing.T) { nodeCfg := NewNodeConfig(cfg) // Config doesn't exist - _, err = h.UpdateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.UpdateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.NotNil(t, err) - _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) - nodeCfg.NetworkString = "other" - _, err = h.UpdateConfig(context.Background(), nodeCfg.createProtobuf()) + n := nodeCfg.(*NodeConfig) + n.NetworkString = "other" + _, err = h.UpdateConfig(context.Background(), n.CreateProtobuf()) assert.Nil(t, err) readCfg, err := h.GetConfig(context.Background(), nil) assert.Nil(t, err) - assert.Equal(t, nodeCfg.NetworkString, readCfg.Network) + assert.Equal(t, n.GetNetworkString(), readCfg.Network) } func TestGrpcHandler_UpdateTenant(t *testing.T) { @@ -144,19 +148,24 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) + tid, err := nodeCfg.GetIdentityID() + assert.Nil(t, err) + + tc := nodeCfg.(*TenantConfig) + // Config doesn't exist - _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID), Data: nodeCfg.createProtobuf()}) + _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(tid), Data: nodeCfg.CreateProtobuf()}) assert.NotNil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) - nodeCfg.EthereumDefaultAccountName = "other" - _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID), Data: nodeCfg.createProtobuf()}) + tc.EthereumDefaultAccountName = "other" + _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(tid), Data: tc.CreateProtobuf()}) assert.Nil(t, err) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) - assert.Equal(t, nodeCfg.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) + assert.Equal(t, tc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) } func TestGrpcHandler_DeleteConfig(t *testing.T) { @@ -171,7 +180,7 @@ func TestGrpcHandler_DeleteConfig(t *testing.T) { assert.Nil(t, err) nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) _, err = h.DeleteConfig(context.Background(), nil) assert.Nil(t, err) @@ -194,12 +203,14 @@ func TestGrpcHandler_DeleteTenant(t *testing.T) { nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.createProtobuf()) + _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) + assert.Nil(t, err) + tid, err := nodeCfg.GetIdentityID() assert.Nil(t, err) - _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(nodeCfg.IdentityID)}) + readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) assert.NotNil(t, err) assert.Nil(t, readCfg) } diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 191a10f54..c249b7a7e 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -2,44 +2,47 @@ package configstore -import "github.com/stretchr/testify/mock" +import ( + "github.com/centrifuge/go-centrifuge/config" + "github.com/stretchr/testify/mock" +) type MockService struct { mock.Mock } -func (m MockService) GetConfig() (*NodeConfig, error) { +func (m MockService) GetConfig() (config.Configuration, error) { args := m.Called() return args.Get(0).(*NodeConfig), args.Error(1) } -func (m MockService) GetTenant(identifier []byte) (*TenantConfig, error) { +func (m MockService) GetTenant(identifier []byte) (config.TenantConfiguration, error) { args := m.Called(identifier) return args.Get(0).(*TenantConfig), args.Error(0) } -func (m MockService) GetAllTenants() ([]*TenantConfig, error) { +func (m MockService) GetAllTenants() ([]config.TenantConfiguration, error) { args := m.Called() - v, _ := args.Get(0).([]*TenantConfig) + v, _ := args.Get(0).([]config.TenantConfiguration) return v, nil } -func (m MockService) CreateConfig(data *NodeConfig) (*NodeConfig, error) { +func (m MockService) CreateConfig(data config.Configuration) (config.Configuration, error) { args := m.Called(data) return args.Get(0).(*NodeConfig), args.Error(0) } -func (m MockService) CreateTenant(data *TenantConfig) (*TenantConfig, error) { +func (m MockService) CreateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { args := m.Called(data) return args.Get(0).(*TenantConfig), args.Error(0) } -func (m MockService) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { +func (m MockService) UpdateConfig(data config.Configuration) (config.Configuration, error) { args := m.Called() return args.Get(0).(*NodeConfig), args.Error(0) } -func (m MockService) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { +func (m MockService) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { args := m.Called(data) return args.Get(0).(*TenantConfig), args.Error(0) } diff --git a/config/configstore/model.go b/config/configstore/model.go index f9cac1faf..7a02be738 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -269,7 +269,8 @@ func (nc *NodeConfig) FromJSON(data []byte) error { return json.Unmarshal(data, nc) } -func (nc *NodeConfig) createProtobuf() *configpb.ConfigData { +// CreateProtobuf creates protobuf for config +func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { return &configpb.ConfigData{ MainIdentity: &configpb.TenantData{ EthAccount: &configpb.EthereumAccount{ @@ -380,7 +381,7 @@ func convertStringMapToSmartContractAddresses(addrs map[string]string) (map[conf } // NewNodeConfig creates a new NodeConfig instance with configs -func NewNodeConfig(c config.Configuration) *NodeConfig { +func NewNodeConfig(c config.Configuration) config.Configuration { mainAccount, _ := c.GetEthereumAccount(c.GetEthereumDefaultAccountName()) mainIdentity, _ := c.GetIdentityID() signPub, signPriv := c.GetSigningKeyPair() @@ -448,11 +449,21 @@ type TenantConfig struct { EthAuthKeyPair KeyPair } +// GetEthereumAccount gets EthereumAccount +func (tc *TenantConfig) GetEthereumAccount() *config.AccountConfig { + return tc.EthereumAccount +} + // GetEthereumDefaultAccountName gets EthereumDefaultAccountName func (tc *TenantConfig) GetEthereumDefaultAccountName() string { return tc.EthereumDefaultAccountName } +// GetReceiveEventNotificationEndpoint gets ReceiveEventNotificationEndpoint +func (tc *TenantConfig) GetReceiveEventNotificationEndpoint() string { + return tc.ReceiveEventNotificationEndpoint +} + // GetIdentityID gets IdentityID func (tc *TenantConfig) GetIdentityID() ([]byte, error) { return tc.IdentityID, nil @@ -493,7 +504,8 @@ func (tc *TenantConfig) FromJSON(data []byte) error { return json.Unmarshal(data, tc) } -func (tc *TenantConfig) createProtobuf() *configpb.TenantData { +// CreateProtobuf creates protobuf for config +func (tc *TenantConfig) CreateProtobuf() *configpb.TenantData { return &configpb.TenantData{ EthAccount: &configpb.EthereumAccount{ Address: tc.EthereumAccount.Address, @@ -534,7 +546,7 @@ func (tc *TenantConfig) loadFromProtobuf(data *configpb.TenantData) { } // NewTenantConfig creates a new TenantConfig instance with configs -func NewTenantConfig(ethAccountName string, c config.Configuration) (*TenantConfig, error) { +func NewTenantConfig(ethAccountName string, c config.Configuration) (config.TenantConfiguration, error) { id, err := c.GetIdentityID() if err != nil { return nil, err @@ -554,7 +566,7 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (*TenantConf } // TempTenantConfig creates a new TenantConfig without id validation, Must only be used for tenant creation. -func TempTenantConfig(ethAccountName string, c config.Configuration) (*TenantConfig, error) { +func TempTenantConfig(ethAccountName string, c config.Configuration) (config.TenantConfiguration, error) { acc, err := c.GetEthereumAccount(ethAccountName) if err != nil && ethAccountName != "" { return nil, err diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index ae08415f0..3a6e53cb8 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -3,8 +3,11 @@ package configstore import ( + "reflect" "testing" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/centrifuge/go-centrifuge/config" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,6 +25,26 @@ type mockConfig struct { mock.Mock } +func (m *mockConfig) Type() reflect.Type { + args := m.Called() + return args.Get(0).(reflect.Type) +} + +func (m *mockConfig) JSON() ([]byte, error) { + args := m.Called() + return args.Get(0).([]byte), args.Error(0) +} + +func (m *mockConfig) FromJSON(json []byte) error { + args := m.Called(json) + return args.Error(0) +} + +func (m *mockConfig) CreateProtobuf() *configpb.ConfigData { + args := m.Called() + return args.Get(0).(*configpb.ConfigData) +} + func (m *mockConfig) IsSet(key string) bool { args := m.Called(key) return args.Get(0).(bool) @@ -238,10 +261,12 @@ func TestNodeConfigProtobuf(t *testing.T) { nc := NewNodeConfig(c) c.AssertExpectations(t) - ncpb := nc.createProtobuf() - assert.Equal(t, nc.StoragePath, ncpb.StoragePath) - assert.Equal(t, nc.ServerPort, int(ncpb.ServerPort)) - assert.Equal(t, hexutil.Encode(nc.MainIdentity.IdentityID), ncpb.MainIdentity.IdentityId) + ncpb := nc.CreateProtobuf() + assert.Equal(t, nc.GetStoragePath(), ncpb.StoragePath) + assert.Equal(t, nc.GetServerPort(), int(ncpb.ServerPort)) + i, err := nc.GetIdentityID() + assert.Nil(t, err) + assert.Equal(t, hexutil.Encode(i), ncpb.MainIdentity.IdentityId) ncCopy := new(NodeConfig) ncCopy.loadFromProtobuf(ncpb) @@ -262,10 +287,13 @@ func TestTenantConfigProtobuf(t *testing.T) { assert.Nil(t, err) c.AssertExpectations(t) - tcpb := tc.createProtobuf() - assert.Equal(t, tc.ReceiveEventNotificationEndpoint, tcpb.ReceiveEventNotificationEndpoint) - assert.Equal(t, hexutil.Encode(tc.IdentityID), tcpb.IdentityId) - assert.Equal(t, tc.SigningKeyPair.Priv, tcpb.SigningKeyPair.Pvt) + tcpb := tc.CreateProtobuf() + assert.Equal(t, tc.GetReceiveEventNotificationEndpoint(), tcpb.ReceiveEventNotificationEndpoint) + i, err := tc.GetIdentityID() + assert.Nil(t, err) + assert.Equal(t, hexutil.Encode(i), tcpb.IdentityId) + _, priv := tc.GetSigningKeyPair() + assert.Equal(t, priv, tcpb.SigningKeyPair.Pvt) tcCopy := new(TenantConfig) tcCopy.loadFromProtobuf(tcpb) diff --git a/config/configstore/repository.go b/config/configstore/repository.go index 79071f046..23b81e41e 100644 --- a/config/configstore/repository.go +++ b/config/configstore/repository.go @@ -1,6 +1,7 @@ package configstore import ( + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/storage" ) @@ -9,38 +10,38 @@ const ( tenantPrefix string = "tenant-" ) -// Repository defines the required methods for the config repository. -type Repository interface { +// repository defines the required methods for the config repository. +type repository interface { // RegisterTenant registers tenant config in DB - RegisterTenant(config *TenantConfig) + RegisterTenant(config config.TenantConfiguration) // RegisterConfig registers node config in DB - RegisterConfig(config *NodeConfig) + RegisterConfig(config config.Configuration) // GetTenant returns the tenant config Model associated with tenant ID - GetTenant(id []byte) (*TenantConfig, error) + GetTenant(id []byte) (config.TenantConfiguration, error) // GetConfig returns the node config model - GetConfig() (*NodeConfig, error) + GetConfig() (config.Configuration, error) // GetAllTenants returns a list of all tenant models in the config DB - GetAllTenants() ([]*TenantConfig, error) + GetAllTenants() ([]config.TenantConfiguration, error) // Create creates the tenant config model if not present in the DB. // should error out if the config exists. - CreateTenant(id []byte, tenant *TenantConfig) error + CreateTenant(id []byte, tenant config.TenantConfiguration) error // Create creates the node config model if not present in the DB. // should error out if the config exists. - CreateConfig(nodeConfig *NodeConfig) error + CreateConfig(config config.Configuration) error // Update strictly updates the tenant config model. // Will error out when the config model doesn't exist in the DB. - UpdateTenant(id []byte, tenant *TenantConfig) error + UpdateTenant(id []byte, tenant config.TenantConfiguration) error // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. - UpdateConfig(nodeConfig *NodeConfig) error + UpdateConfig(nodeConfig config.Configuration) error // Delete deletes tenant config // Will not error out when config model doesn't exists in DB @@ -63,23 +64,23 @@ func getConfigKey() []byte { return []byte(configPrefix) } -// NewDBRepository creates instance of Config Repository -func NewDBRepository(db storage.Repository) Repository { +// newDBRepository creates instance of Config repository +func newDBRepository(db storage.Repository) repository { return &repo{db: db} } // RegisterTenant registers tenant config in DB -func (r *repo) RegisterTenant(config *TenantConfig) { +func (r *repo) RegisterTenant(config config.TenantConfiguration) { r.db.Register(config) } // RegisterConfig registers node config in DB -func (r *repo) RegisterConfig(config *NodeConfig) { +func (r *repo) RegisterConfig(config config.Configuration) { r.db.Register(config) } // GetTenant returns the tenant config Model associated with tenant ID -func (r *repo) GetTenant(id []byte) (*TenantConfig, error) { +func (r *repo) GetTenant(id []byte) (config.TenantConfiguration, error) { key := getTenantKey(id) model, err := r.db.Get(key) if err != nil { @@ -89,7 +90,7 @@ func (r *repo) GetTenant(id []byte) (*TenantConfig, error) { } // GetConfig returns the node config model -func (r *repo) GetConfig() (*NodeConfig, error) { +func (r *repo) GetConfig() (config.Configuration, error) { key := getConfigKey() model, err := r.db.Get(key) if err != nil { @@ -100,8 +101,8 @@ func (r *repo) GetConfig() (*NodeConfig, error) { // GetAllTenants iterates over all tenant entries in DB and returns a list of Models // If an error occur reading a tenant, throws a warning and continue -func (r *repo) GetAllTenants() ([]*TenantConfig, error) { - var tenantConfigs []*TenantConfig +func (r *repo) GetAllTenants() ([]config.TenantConfiguration, error) { + var tenantConfigs []config.TenantConfiguration models, err := r.db.GetAllByPrefix(tenantPrefix) if err != nil { return nil, err @@ -114,28 +115,28 @@ func (r *repo) GetAllTenants() ([]*TenantConfig, error) { // Create creates the tenant config model if not present in the DB. // should error out if the config exists. -func (r *repo) CreateTenant(id []byte, tenant *TenantConfig) error { +func (r *repo) CreateTenant(id []byte, tenant config.TenantConfiguration) error { key := getTenantKey(id) return r.db.Create(key, tenant) } // Create creates the node config model if not present in the DB. // should error out if the config exists. -func (r *repo) CreateConfig(nodeConfig *NodeConfig) error { +func (r *repo) CreateConfig(config config.Configuration) error { key := getConfigKey() - return r.db.Create(key, nodeConfig) + return r.db.Create(key, config) } // Update strictly updates the tenant config model. // Will error out when the config model doesn't exist in the DB. -func (r *repo) UpdateTenant(id []byte, tenant *TenantConfig) error { +func (r *repo) UpdateTenant(id []byte, tenant config.TenantConfiguration) error { key := getTenantKey(id) return r.db.Update(key, tenant) } // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. -func (r *repo) UpdateConfig(nodeConfig *NodeConfig) error { +func (r *repo) UpdateConfig(nodeConfig config.Configuration) error { key := getConfigKey() return r.db.Update(key, nodeConfig) } diff --git a/config/configstore/repository_test.go b/config/configstore/repository_test.go index a957b13a6..0e0f1a0dc 100644 --- a/config/configstore/repository_test.go +++ b/config/configstore/repository_test.go @@ -7,6 +7,8 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -25,7 +27,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) configdb := ctx[storage.BootstrappedConfigDB].(storage.Repository) @@ -33,7 +35,8 @@ func TestMain(m *testing.M) { nc := NewNodeConfig(cfg) // clean db _ = configdb.Delete(getConfigKey()) - _ = configdb.Delete(getTenantKey(nc.MainIdentity.IdentityID)) + i, _ := nc.GetIdentityID() + _ = configdb.Delete(getTenantKey(i)) result := m.Run() cleanupDBFiles() os.Exit(result) @@ -84,7 +87,9 @@ func TestTenantOperations(t *testing.T) { readTenant, err := repo.GetTenant(id) assert.Nil(t, err) assert.Equal(t, reflect.TypeOf(newTenant), readTenant.Type()) - assert.Equal(t, newTenant.IdentityID, readTenant.IdentityID) + i, err := readTenant.GetIdentityID() + assert.Nil(t, err) + assert.Equal(t, newTenant.IdentityID, i) // Update tenant newTenant.EthereumDefaultAccountName = "secondary" @@ -120,7 +125,7 @@ func TestConfigOperations(t *testing.T) { readDoc, err := repo.GetConfig() assert.Nil(t, err) assert.Equal(t, reflect.TypeOf(newConfig), readDoc.Type()) - assert.Equal(t, newConfig.NetworkID, readDoc.NetworkID) + assert.Equal(t, newConfig.NetworkID, readDoc.GetNetworkID()) // Update config newConfig.NetworkID = 42 @@ -166,9 +171,9 @@ func TestLevelDBRepo_GetAllTenants(t *testing.T) { tenants, err := repo.GetAllTenants() assert.Nil(t, err) assert.Equal(t, 3, len(tenants)) - t0Id := tenants[0].ID() - t1Id := tenants[1].ID() - t2Id := tenants[2].ID() + t0Id, _ := tenants[0].GetIdentityID() + t1Id, _ := tenants[1].GetIdentityID() + t2Id, _ := tenants[2].GetIdentityID() assert.Contains(t, ids, t0Id) assert.Contains(t, ids, t1Id) assert.Contains(t, ids, t2Id) @@ -183,12 +188,12 @@ func cleanupDBFiles() { } } -func getRandomStorage() (Repository, string, error) { - randomPath := storage.GetRandomTestStoragePath() - db, err := storage.NewLevelDBStorage(randomPath) +func getRandomStorage() (repository, string, error) { + randomPath := leveldb.GetRandomTestStoragePath() + db, err := leveldb.NewLevelDBStorage(randomPath) if err != nil { return nil, "", err } dbFiles = append(dbFiles, randomPath) - return NewDBRepository(storage.NewLevelDBRepository(db)), randomPath, nil + return newDBRepository(leveldb.NewLevelDBRepository(db)), randomPath, nil } diff --git a/config/configstore/service.go b/config/configstore/service.go index 77080fbf9..3ccc9fbc4 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -6,54 +6,49 @@ import ( "github.com/centrifuge/go-centrifuge/errors" ) -// Service exposes functions over the config objects -type Service interface { - GetConfig() (*NodeConfig, error) - GetTenant(identifier []byte) (*TenantConfig, error) - GetAllTenants() ([]*TenantConfig, error) - CreateConfig(data *NodeConfig) (*NodeConfig, error) - CreateTenant(data *TenantConfig) (*TenantConfig, error) - UpdateConfig(data *NodeConfig) (*NodeConfig, error) - UpdateTenant(data *TenantConfig) (*TenantConfig, error) - DeleteConfig() error - DeleteTenant(identifier []byte) error -} - type service struct { - repo Repository + repo repository } // DefaultService returns an implementation of the config.Service -func DefaultService(repository Repository) Service { +func DefaultService(repository repository) config.Service { return &service{repo: repository} } -func (s service) GetConfig() (*NodeConfig, error) { +func (s service) GetConfig() (config.Configuration, error) { return s.repo.GetConfig() } -func (s service) GetTenant(identifier []byte) (*TenantConfig, error) { +func (s service) GetTenant(identifier []byte) (config.TenantConfiguration, error) { return s.repo.GetTenant(identifier) } -func (s service) GetAllTenants() ([]*TenantConfig, error) { +func (s service) GetAllTenants() ([]config.TenantConfiguration, error) { return s.repo.GetAllTenants() } -func (s service) CreateConfig(data *NodeConfig) (*NodeConfig, error) { +func (s service) CreateConfig(data config.Configuration) (config.Configuration, error) { return data, s.repo.CreateConfig(data) } -func (s service) CreateTenant(data *TenantConfig) (*TenantConfig, error) { - return data, s.repo.CreateTenant(data.IdentityID, data) +func (s service) CreateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { + id, err := data.GetIdentityID() + if err != nil { + return nil, err + } + return data, s.repo.CreateTenant(id, data) } -func (s service) UpdateConfig(data *NodeConfig) (*NodeConfig, error) { +func (s service) UpdateConfig(data config.Configuration) (config.Configuration, error) { return data, s.repo.UpdateConfig(data) } -func (s service) UpdateTenant(data *TenantConfig) (*TenantConfig, error) { - return data, s.repo.UpdateTenant(data.IdentityID, data) +func (s service) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { + id, err := data.GetIdentityID() + if err != nil { + return nil, err + } + return data, s.repo.UpdateTenant(id, data) } func (s service) DeleteConfig() error { @@ -68,7 +63,7 @@ func (s service) DeleteTenant(identifier []byte) error { func RetrieveConfig(dbOnly bool, ctx map[string]interface{}) (config.Configuration, error) { var cfg config.Configuration var err error - if cfgService, ok := ctx[BootstrappedConfigStorage].(Service); ok { + if cfgService, ok := ctx[BootstrappedConfigStorage].(config.Service); ok { // may be we need a way to detect a corrupted db here cfg, err = cfgService.GetConfig() if err != nil { diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index 4f5283e39..c581a6819 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -48,9 +48,10 @@ func TestService_GetTenant(t *testing.T) { svc := DefaultService(repo) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - err = repo.CreateTenant(tenantCfg.IdentityID, tenantCfg) + tid, _ := tenantCfg.GetIdentityID() + err = repo.CreateTenant(tid, tenantCfg) assert.Nil(t, err) - cfg, err := svc.GetTenant(tenantCfg.IdentityID) + cfg, err := svc.GetTenant(tid) assert.Nil(t, err) assert.NotNil(t, cfg) } @@ -63,7 +64,7 @@ func TestService_CreateConfig(t *testing.T) { nodeCfg := NewNodeConfig(cfg) cfgpb, err := svc.CreateConfig(nodeCfg) assert.Nil(t, err) - assert.Equal(t, nodeCfg.StoragePath, cfgpb.StoragePath) + assert.Equal(t, nodeCfg.GetStoragePath(), cfgpb.GetStoragePath()) //Config already exists _, err = svc.CreateConfig(nodeCfg) @@ -79,7 +80,11 @@ func TestService_CreateTenant(t *testing.T) { assert.Nil(t, err) newCfg, err := svc.CreateTenant(tenantCfg) assert.Nil(t, err) - assert.Equal(t, tenantCfg.IdentityID, newCfg.IdentityID) + i, err := newCfg.GetIdentityID() + assert.Nil(t, err) + tid, err := tenantCfg.GetIdentityID() + assert.Nil(t, err) + assert.Equal(t, tid, i) //Tenant already exists _, err = svc.CreateTenant(tenantCfg) @@ -99,12 +104,13 @@ func TestService_UpdateConfig(t *testing.T) { newCfg, err := svc.CreateConfig(nodeCfg) assert.Nil(t, err) - assert.Equal(t, nodeCfg.StoragePath, newCfg.StoragePath) + assert.Equal(t, nodeCfg.GetStoragePath(), newCfg.GetStoragePath()) - nodeCfg.NetworkString = "something" - newCfg, err = svc.UpdateConfig(nodeCfg) + n := nodeCfg.(*NodeConfig) + n.NetworkString = "something" + newCfg, err = svc.UpdateConfig(n) assert.Nil(t, err) - assert.Equal(t, nodeCfg.NetworkString, newCfg.NetworkString) + assert.Equal(t, n.GetNetworkString(), newCfg.GetNetworkString()) } func TestService_UpdateTenant(t *testing.T) { @@ -120,12 +126,17 @@ func TestService_UpdateTenant(t *testing.T) { newCfg, err = svc.CreateTenant(tenantCfg) assert.Nil(t, err) - assert.Equal(t, tenantCfg.IdentityID, newCfg.IdentityID) + i, err := newCfg.GetIdentityID() + assert.Nil(t, err) + tid, err := tenantCfg.GetIdentityID() + assert.Nil(t, err) + assert.Equal(t, tid, i) - tenantCfg.EthereumDefaultAccountName = "other" + tc := tenantCfg.(*TenantConfig) + tc.EthereumDefaultAccountName = "other" newCfg, err = svc.UpdateTenant(tenantCfg) assert.Nil(t, err) - assert.Equal(t, tenantCfg.EthereumDefaultAccountName, newCfg.EthereumDefaultAccountName) + assert.Equal(t, tc.EthereumDefaultAccountName, newCfg.GetEthereumDefaultAccountName()) } func TestService_DeleteConfig(t *testing.T) { @@ -156,17 +167,19 @@ func TestService_DeleteTenant(t *testing.T) { svc := DefaultService(repo) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) + tid, err := tenantCfg.GetIdentityID() + assert.Nil(t, err) //No config, no error - err = svc.DeleteTenant(tenantCfg.IdentityID) + err = svc.DeleteTenant(tid) assert.Nil(t, err) _, err = svc.CreateTenant(tenantCfg) assert.Nil(t, err) - err = svc.DeleteTenant(tenantCfg.IdentityID) + err = svc.DeleteTenant(tid) assert.Nil(t, err) - _, err = svc.GetTenant(tenantCfg.IdentityID) + _, err = svc.GetTenant(tid) assert.NotNil(t, err) } diff --git a/config/configuration.go b/config/configuration.go index 91650465d..29527fba0 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -11,10 +11,15 @@ import ( "io/ioutil" "math/big" "os" + "reflect" "strings" "sync" "time" + "github.com/centrifuge/go-centrifuge/storage" + + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/centerrors" @@ -55,6 +60,8 @@ func ContractNames() [4]ContractName { // Configuration defines the methods that a config type should implement. type Configuration interface { + storage.Model + // generic methods IsSet(key string) bool Set(key string, value interface{}) @@ -100,6 +107,38 @@ type Configuration interface { // debug specific methods IsPProfEnabled() bool + + // CreateProtobuf creates protobuf + CreateProtobuf() *configpb.ConfigData +} + +// TenantConfiguration exposes tenant specific config options +type TenantConfiguration interface { + storage.Model + + GetEthereumAccount() *AccountConfig + GetEthereumDefaultAccountName() string + GetReceiveEventNotificationEndpoint() string + GetIdentityID() ([]byte, error) + GetSigningKeyPair() (pub, priv string) + GetEthAuthKeyPair() (pub, priv string) + GetEthereumContextWaitTimeout() time.Duration + + // CreateProtobuf creates protobuf + CreateProtobuf() *configpb.TenantData +} + +// Service exposes functions over the config objects +type Service interface { + GetConfig() (Configuration, error) + GetTenant(identifier []byte) (TenantConfiguration, error) + GetAllTenants() ([]TenantConfiguration, error) + CreateConfig(data Configuration) (Configuration, error) + CreateTenant(data TenantConfiguration) (TenantConfiguration, error) + UpdateConfig(data Configuration) (Configuration, error) + UpdateTenant(data TenantConfiguration) (TenantConfiguration, error) + DeleteConfig() error + DeleteTenant(identifier []byte) error } // configuration holds the configuration details for the node. @@ -109,6 +148,22 @@ type configuration struct { v *viper.Viper } +func (c *configuration) Type() reflect.Type { + panic("irrelevant, configuration#Type must not be used") +} + +func (c *configuration) JSON() ([]byte, error) { + panic("irrelevant, configuration#JSON must not be used") +} + +func (c *configuration) FromJSON(json []byte) error { + panic("irrelevant, configuration#FromJSON must not be used") +} + +func (c *configuration) CreateProtobuf() *configpb.ConfigData { + panic("irrelevant, configuration#CreateProtobuf must not be used") +} + // AccountConfig holds the account details. type AccountConfig struct { Address string diff --git a/contextutil/context.go b/contextutil/context.go index 55b44f58e..83f932d91 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -4,13 +4,13 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" ) @@ -24,13 +24,13 @@ const ( ) // NewCentrifugeContext creates new instance of the request headers. -func NewCentrifugeContext(ctx context.Context, cfg *configstore.TenantConfig) (context.Context, error) { +func NewCentrifugeContext(ctx context.Context, cfg config.TenantConfiguration) (context.Context, error) { return context.WithValue(ctx, self, cfg), nil } // Self returns Self CentID. func Self(ctx context.Context) (*identity.IDConfig, error) { - tc, ok := ctx.Value(self).(*configstore.TenantConfig) + tc, ok := ctx.Value(self).(config.TenantConfiguration) if !ok { return nil, ErrSelfNotFound } @@ -38,8 +38,8 @@ func Self(ctx context.Context) (*identity.IDConfig, error) { } // Tenant extracts the TenanConfig from the given context value -func Tenant(ctx context.Context) (*configstore.TenantConfig, error) { - tc, ok := ctx.Value(self).(*configstore.TenantConfig) +func Tenant(ctx context.Context) (config.TenantConfiguration, error) { + tc, ok := ctx.Value(self).(config.TenantConfiguration) if !ok { return nil, ErrSelfNotFound } @@ -47,7 +47,7 @@ func Tenant(ctx context.Context) (*configstore.TenantConfig, error) { } // CentContext updates a context with tenant info using the configstore, must only be used for api handlers -func CentContext(ctx context.Context, config configstore.Service) (context.Context, error) { +func CentContext(ctx context.Context, config config.Service) (context.Context, error) { // TODO [multi-tenancy] remove following and read the tenantID from the context tc, err := config.GetAllTenants() if err != nil { diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 254d9ebf1..0bfe52802 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -4,12 +4,12 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" @@ -35,7 +35,7 @@ type documentAnchorTask struct { tenantID identity.CentID // state - config configstore.Service + config config.Service processor anchorProcessor modelGetFunc func(tenantID, id []byte) (Model, error) modelSaveFunc func(tenantID, id []byte, model Model) error diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index ad285af87..f4c43d42c 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -2,6 +2,7 @@ package documents import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" @@ -36,7 +37,7 @@ type PostBootstrapper struct{} // Bootstrap register task to the queue. func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("config service not initialised") } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 296b9d151..822a9f1f2 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -5,9 +5,12 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/storage" + + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" @@ -15,10 +18,10 @@ import ( func TestBootstrapper_Bootstrap(t *testing.T) { ctx := make(map[string]interface{}) - randomPath := storage.GetRandomTestStoragePath() - db, err := storage.NewLevelDBStorage(randomPath) + randomPath := leveldb.GetRandomTestStoragePath() + db, err := leveldb.NewLevelDBStorage(randomPath) assert.Nil(t, err) - repo := storage.NewLevelDBRepository(db) + repo := leveldb.NewLevelDBRepository(db) ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo ctx[bootstrap.BootstrappedQueueServer] = new(queue.Server) diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index ca1e6057e..7b410a4fb 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/genericdoc" @@ -25,7 +27,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -414,11 +415,11 @@ func TestService_GetVersion_error(t *testing.T) { func testRepo() documents.Repository { if testRepoGlobal == nil { - ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + ldb, err := leveldb.NewLevelDBStorage(leveldb.GetRandomTestStoragePath()) if err != nil { panic(err) } - testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) + testRepoGlobal = documents.NewDBRepository(leveldb.NewLevelDBRepository(ldb)) testRepoGlobal.Register(&invoice.Invoice{}) } return testRepoGlobal diff --git a/documents/handler.go b/documents/handler.go index eb75f9aeb..f64941501 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -3,7 +3,7 @@ package documents import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -17,12 +17,12 @@ var apiLog = logging.Logger("document-api") // grpcHandler handles all the common document related actions: proof generation type grpcHandler struct { - config configstore.Service + config config.Service registry *ServiceRegistry } // GRPCHandler returns an implementation of documentpb.DocumentServiceServer -func GRPCHandler(config configstore.Service, registry *ServiceRegistry) documentpb.DocumentServiceServer { +func GRPCHandler(config config.Service, registry *ServiceRegistry) documentpb.DocumentServiceServer { return grpcHandler{config: config, registry: registry} } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index e32ddb612..850c74284 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -1,7 +1,7 @@ package invoice import ( - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -19,11 +19,11 @@ var apiLog = logging.Logger("invoice-api") // anchoring, sending, finding stored invoice document type grpcHandler struct { service Service - config configstore.Service + config config.Service } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(config configstore.Service, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { +func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) if err != nil { return nil, err diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 3c8472202..d5e346ef3 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -31,7 +32,6 @@ import ( "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -43,7 +43,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration -var configService configstore.Service +var configService config.Service func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -53,7 +53,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, @@ -69,7 +69,7 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) - configService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + configService = ctx[configstore.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 4ccb219e7..d65189fe8 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -5,6 +5,8 @@ package invoice import ( "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/documents/genericdoc" @@ -20,7 +22,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -489,11 +490,11 @@ var testRepoGlobal documents.Repository func testRepo() documents.Repository { if testRepoGlobal == nil { - ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + ldb, err := leveldb.NewLevelDBStorage(leveldb.GetRandomTestStoragePath()) if err != nil { panic(err) } - testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) + testRepoGlobal = documents.NewDBRepository(leveldb.NewLevelDBRepository(ldb)) testRepoGlobal.Register(&Invoice{}) } return testRepoGlobal diff --git a/documents/model.go b/documents/model.go index 0dd50bf28..baa37f92e 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,8 +1,7 @@ package documents import ( - "reflect" - + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -11,6 +10,7 @@ import ( // Model is an interface to abstract away model specificness like invoice or purchaseOrder // The interface can cast into the type specified by the model if required type Model interface { + storage.Model // Get the ID of the document represented by this model ID() ([]byte, error) @@ -23,15 +23,6 @@ type Model interface { // assumes that core document has valid identifiers set UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error - //Returns the underlying type of the Model - Type() reflect.Type - - // JSON return the json representation of the model - JSON() ([]byte, error) - - // FromJSON initialize the model with a json - FromJSON(json []byte) error - // CreateProofs creates precise-proofs for given fields CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) } diff --git a/documents/model_test.go b/documents/model_test.go index 369db0bed..61e324e95 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -6,31 +6,32 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" ) var ctx = map[string]interface{}{} -var ConfigService configstore.Service +var ConfigService config.Service func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, &Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) - ConfigService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + ConfigService = ctx[configstore.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 95b7c321c..c6004beef 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -1,7 +1,7 @@ package purchaseorder import ( - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -20,11 +20,11 @@ var apiLog = logging.Logger("purchaseorder-api") // anchoring, sending, finding stored purchase order document type grpcHandler struct { service Service - config configstore.Service + config config.Service } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler(config configstore.Service, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { +func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) if err != nil { return nil, errors.New("failed to fetch purchase order service") diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index e0dc0a036..d42b725b1 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -31,7 +32,6 @@ import ( "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -43,7 +43,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration -var configService configstore.Service +var configService config.Service func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -53,7 +53,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, @@ -68,7 +68,7 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) - configService = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + configService = ctx[configstore.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index f1bd4de20..b32f3ac16 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -5,6 +5,8 @@ package purchaseorder import ( "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" @@ -531,11 +533,11 @@ var testRepoGlobal documents.Repository func testRepo() documents.Repository { if testRepoGlobal == nil { - ldb, err := storage.NewLevelDBStorage(storage.GetRandomTestStoragePath()) + ldb, err := leveldb.NewLevelDBStorage(leveldb.GetRandomTestStoragePath()) if err != nil { panic(err) } - testRepoGlobal = documents.NewDBRepository(storage.NewLevelDBRepository(ldb)) + testRepoGlobal = documents.NewDBRepository(leveldb.NewLevelDBRepository(ldb)) testRepoGlobal.Register(&PurchaseOrder{}) } return testRepoGlobal diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 0be76299d..78a113f9f 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -4,7 +4,6 @@ package documents import ( "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/storage" ) diff --git a/nft/bootstrapper_test.go b/nft/bootstrapper_test.go index 0c0e3f84e..28b2e9b34 100644 --- a/nft/bootstrapper_test.go +++ b/nft/bootstrapper_test.go @@ -6,10 +6,11 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -20,7 +21,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 25699f7af..f1da11d15 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -116,7 +116,7 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, errors.New("failed to prepare mint request: %v", err) } - opts, err := s.ethClient.GetTxOpts(tc.EthereumDefaultAccountName) + opts, err := s.ethClient.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { return nil, err } @@ -126,7 +126,12 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, err } - cid, err := identity.ToCentID(tc.IdentityID) + cidBytes, err := tc.GetIdentityID() + if err != nil { + return nil, err + } + + cid, err := identity.ToCentID(cidBytes) if err != nil { return nil, err } diff --git a/nft/handler.go b/nft/handler.go index 26585612f..cbf2569c9 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -3,9 +3,9 @@ package nft import ( "context" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" @@ -18,12 +18,12 @@ import ( var apiLog = logging.Logger("nft-api") type grpcHandler struct { - config configstore.Service + config config.Service service PaymentObligation } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(config configstore.Service, payOb PaymentObligation) nftpb.NFTServiceServer { +func GRPCHandler(config config.Service, payOb PaymentObligation) nftpb.NFTServiceServer { return &grpcHandler{config: config, service: payOb} } diff --git a/nft/handler_test.go b/nft/handler_test.go index 4b2afcb49..1cf4dd97e 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -7,6 +7,8 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" @@ -47,7 +49,7 @@ func TestNFTMint_success(t *testing.T) { func mockConfigService() *configstore.MockService { mockConfigStore := &configstore.MockService{} - mockConfigStore.On("GetAllTenants").Return([]*configstore.TenantConfig{&configstore.TenantConfig{}}, nil) + mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{}}, nil) return mockConfigStore } diff --git a/notification/notification.go b/notification/notification.go index 9a44c7a72..087d53b30 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -49,7 +49,7 @@ func (wh webhookSender) Send(ctx context.Context, notification *notificationpb.N if err != nil { return Failure, err } - url := tc.ReceiveEventNotificationEndpoint + url := tc.GetReceiveEventNotificationEndpoint() if url == "" { log.Warningf("Webhook URL not defined, manually fetch received document") return Success, nil diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 2b3318399..8a063b023 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -2,6 +2,7 @@ package p2p import ( "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -18,7 +19,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("configstore not initialised") } diff --git a/p2p/client.go b/p2p/client.go index 6ec4a9cbe..7c8975722 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -60,7 +60,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i return nil, err } - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeSendAnchoredDoc, in) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDoc, in) if err != nil { return nil, err } @@ -168,7 +168,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden if err != nil { return nil, err } - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &doc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &doc}) if err != nil { return nil, err } diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 7bb442999..eec1b6dac 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -30,14 +30,14 @@ var ( client p2p.Client cfg config.Configuration idService identity.Service - cfgStore configstore.Service + cfgStore config.Service ) func TestMain(m *testing.M) { flag.Parse() ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgStore = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfgStore = ctx[configstore.BootstrappedConfigStorage].(config.Service) idService = ctx[ethid.BootstrappedIDService].(identity.Service) client = ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) testingidentity.CreateIdentityWithKeys(cfg, idService) @@ -80,14 +80,15 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.TenantC tcID := identity.RandomCentID() tc, err := configstore.TempTenantConfig("", cfg) assert.NoError(t, err) - tc.IdentityID = tcID[:] - id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tc, idService) + tcr := tc.(*configstore.TenantConfig) + tcr.IdentityID = tcID[:] + id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService) if corruptID { - tc.IdentityID = utils.RandomSlice(identity.CentIDLength) + tcr.IdentityID = utils.RandomSlice(identity.CentIDLength) } - tc, err = cfgStore.CreateTenant(tc) + tc, err = cfgStore.CreateTenant(tcr) assert.NoError(t, err) - return tc, id, err + return tcr, id, err } func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *coredocumentpb.CoreDocument { diff --git a/p2p/client_test.go b/p2p/client_test.go index 6e2f4344e..7ee027ee9 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -56,7 +56,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) @@ -78,7 +78,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) @@ -101,7 +101,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.NetworkID, p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") randomBytes := utils.RandomSlice(identity.CentIDLength) diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 4e9b6a768..d3c65a329 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -3,9 +3,9 @@ package receiver import ( "context" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/golang/protobuf/proto" @@ -48,12 +48,12 @@ func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb. // Handler implements protocol message handlers type Handler struct { registry *documents.ServiceRegistry - config configstore.Service + config config.Service handshakeValidator ValidatorGroup } // New returns an implementation of P2PServiceServer -func New(config configstore.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup) *Handler { +func New(config config.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup) *Handler { return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator} } @@ -116,7 +116,7 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee return convertToErrorEnvelop(err) } - p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeRequestSignatureRep, res) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignatureRep, res) if err != nil { return convertToErrorEnvelop(err) } @@ -160,7 +160,7 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID return convertToErrorEnvelop(err) } - p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.NetworkID, p2pcommon.MessageTypeSendAnchoredDocRep, res) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDocRep, res) if err != nil { return convertToErrorEnvelop(err) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 1a758d256..747bdbc69 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -49,7 +49,7 @@ func TestMain(m *testing.M) { flag.Parse() ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfgService := ctx[configstore.BootstrappedConfigStorage].(config.Service) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[ethid.BootstrappedIDService].(identity.Service) diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index c680e3059..003428488 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -15,6 +15,8 @@ import ( "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-protocol" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -26,7 +28,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/transactions" "github.com/golang/protobuf/ptypes/any" @@ -46,7 +47,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, @@ -55,7 +56,7 @@ func TestMain(m *testing.M) { ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfgService := ctx[configstore.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) result := m.Run() diff --git a/p2p/server.go b/p2p/server.go index cadf5e1a0..9bf70a910 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -6,9 +6,9 @@ import ( "sync" "time" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -45,7 +45,7 @@ type messenger interface { // peer implements node.Server type peer struct { disablePeerStore bool - config configstore.Service + config config.Service host host.Host handlerCreator func() *receiver.Handler mes messenger @@ -84,7 +84,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- return } - s.mes = newP2PMessenger(ctx, s.host, nc.P2PConnectionTimeout, s.handlerCreator().HandleInterceptor) + s.mes = newP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout(), s.handlerCreator().HandleInterceptor) tcs, err := s.config.GetAllTenants() if err != nil { startupErr <- err @@ -92,7 +92,12 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- } var protocols []protocol.ID for _, t := range tcs { - CID, err := identity.ToCentID(t.IdentityID) + tid, err := t.GetIdentityID() + if err != nil { + startupErr <- err + return + } + CID, err := identity.ToCentID(tid) if err != nil { startupErr <- err return diff --git a/p2p/server_test.go b/p2p/server_test.go index b4f021902..5be5846c7 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -18,21 +20,20 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/p2p/receiver" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" ) var ( - cfg configstore.Service + cfg config.Service ) func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, @@ -40,12 +41,13 @@ func TestMain(m *testing.M) { } ctx := make(map[string]interface{}) bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cfg = ctx[configstore.BootstrappedConfigStorage].(config.Service) c, _ := cfg.GetConfig() - c.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" - c.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" - c.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" - c.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" + n := c.(*configstore.NodeConfig) + n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" + n.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" + n.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" + n.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" cfg.UpdateConfig(c) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -55,11 +57,12 @@ func TestMain(m *testing.M) { func TestCentP2PServer_StartContextCancel(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) - c.P2PPort = 38203 + n := c.(*configstore.NodeConfig) + n.P2PPort = 38203 _, err = cfg.UpdateConfig(c) assert.NoError(t, err) cp2p := &peer{config: cfg, handlerCreator: func() *receiver.Handler { - return receiver.New(cfg, nil, receiver.HandshakeValidator(c.NetworkID)) + return receiver.New(cfg, nil, receiver.HandshakeValidator(n.NetworkID)) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) @@ -77,8 +80,9 @@ func TestCentP2PServer_StartListenError(t *testing.T) { // cause an error by using an invalid port c, err := cfg.GetConfig() assert.NoError(t, err) - c.P2PPort = 100000000 - _, err = cfg.UpdateConfig(c) + n := c.(*configstore.NodeConfig) + n.P2PPort = 100000000 + _, err = cfg.UpdateConfig(n) assert.NoError(t, err) cp2p := &peer{config: cfg} ctx, _ := context.WithCancel(context.Background()) @@ -97,7 +101,8 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { assert.NoError(t, err) listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) + pu, pr := c.GetSigningKeyPair() + priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, "", listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -109,7 +114,8 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) + pu, pr := c.GetSigningKeyPair() + priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.Nil(t, err) assert.NotNil(t, h) @@ -125,7 +131,8 @@ func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 cp2p := &peer{config: cfg} - priv, pub, err := cp2p.createSigningKey(c.MainIdentity.SigningKeyPair.Pub, c.MainIdentity.SigningKeyPair.Priv) + pu, pr := c.GetSigningKeyPair() + priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.NotNil(t, err) assert.Nil(t, h) diff --git a/storage/bootstrapper.go b/storage/leveldb/bootstrapper.go similarity index 72% rename from storage/bootstrapper.go rename to storage/leveldb/bootstrapper.go index 082dbb300..e22fc0cbb 100644 --- a/storage/bootstrapper.go +++ b/storage/leveldb/bootstrapper.go @@ -1,15 +1,9 @@ -package storage +package leveldb import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/errors" -) - -const ( - // BootstrappedDB is a key mapped to DB at boot - BootstrappedDB string = "BootstrappedDB" - // BootstrappedConfigDB is a key mapped to DB for configs at boot - BootstrappedConfigDB string = "BootstrappedConfigDB" + "github.com/centrifuge/go-centrifuge/storage" ) // Config holds configuration data for storage package @@ -33,12 +27,12 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return errors.New("failed to init config level db: %v", err) } - context[BootstrappedConfigDB] = NewLevelDBRepository(configLevelDB) + context[storage.BootstrappedConfigDB] = NewLevelDBRepository(configLevelDB) levelDB, err := NewLevelDBStorage(cfg.GetStoragePath()) if err != nil { return errors.New("failed to init level db: %v", err) } - context[BootstrappedDB] = NewLevelDBRepository(levelDB) + context[storage.BootstrappedDB] = NewLevelDBRepository(levelDB) return nil } diff --git a/storage/bootstrapper_test.go b/storage/leveldb/bootstrapper_test.go similarity index 94% rename from storage/bootstrapper_test.go rename to storage/leveldb/bootstrapper_test.go index 66fd011c0..1ba30e987 100644 --- a/storage/bootstrapper_test.go +++ b/storage/leveldb/bootstrapper_test.go @@ -1,6 +1,6 @@ // +build unit -package storage +package leveldb import ( "testing" diff --git a/storage/leveldb.go b/storage/leveldb/leveldb.go similarity index 67% rename from storage/leveldb.go rename to storage/leveldb/leveldb.go index e54b80c1f..e5c36a728 100644 --- a/storage/leveldb.go +++ b/storage/leveldb/leveldb.go @@ -1,10 +1,12 @@ -package storage +package leveldb import ( "encoding/json" "reflect" "sync" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/errors" logging "github.com/ipfs/go-log" "github.com/syndtr/goleveldb/leveldb" @@ -36,7 +38,7 @@ type value struct { } // NewLevelDBRepository returns levelDb implementation of Repository -func NewLevelDBRepository(db *leveldb.DB) Repository { +func NewLevelDBRepository(db *leveldb.DB) storage.Repository { return &levelDBRepo{ db: db, models: make(map[string]reflect.Type), @@ -44,7 +46,7 @@ func NewLevelDBRepository(db *leveldb.DB) Repository { } // Register registers the model so that the DB can return the model without knowing the type -func (l *levelDBRepo) Register(model Model) { +func (l *levelDBRepo) Register(model storage.Model) { l.mu.Lock() defer l.mu.Unlock() tp := getTypeIndirect(model.Type()) @@ -61,20 +63,20 @@ func (l *levelDBRepo) Exists(key []byte) bool { } // getModel returns a new instance of the type mt. -func (l *levelDBRepo) getModel(mt string) (Model, error) { +func (l *levelDBRepo) getModel(mt string) (storage.Model, error) { tp, ok := l.models[mt] if !ok { - return nil, errors.NewTypedError(ErrModelTypeNotRegistered, errors.New("%s", mt)) + return nil, errors.NewTypedError(storage.ErrModelTypeNotRegistered, errors.New("%s", mt)) } - return reflect.New(tp).Interface().(Model), nil + return reflect.New(tp).Interface().(storage.Model), nil } -func (l *levelDBRepo) parseModel(data []byte) (Model, error) { +func (l *levelDBRepo) parseModel(data []byte) (storage.Model, error) { v := new(value) err := json.Unmarshal(data, v) if err != nil { - return nil, errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to unmarshal to value: %v", err)) + return nil, errors.NewTypedError(storage.ErrModelRepositorySerialisation, errors.New("failed to unmarshal to value: %v", err)) } nm, err := l.getModel(v.Type) @@ -84,19 +86,19 @@ func (l *levelDBRepo) parseModel(data []byte) (Model, error) { err = nm.FromJSON([]byte(v.Data)) if err != nil { - return nil, errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to unmarshal to model: %v", err)) + return nil, errors.NewTypedError(storage.ErrModelRepositorySerialisation, errors.New("failed to unmarshal to model: %v", err)) } return nm, nil } // Get retrieves model by key, otherwise returns error -func (l *levelDBRepo) Get(key []byte) (Model, error) { +func (l *levelDBRepo) Get(key []byte) (storage.Model, error) { l.mu.RLock() defer l.mu.RUnlock() data, err := l.db.Get(key, nil) if err != nil { - return nil, errors.NewTypedError(ErrModelRepositoryNotFound, err) + return nil, errors.NewTypedError(storage.ErrModelRepositoryNotFound, err) } return l.parseModel(data) @@ -104,8 +106,8 @@ func (l *levelDBRepo) Get(key []byte) (Model, error) { // GetAllByPrefix returns all models which keys match the provided prefix // If an error is found parsing one of the matched models, logs warning and continues -func (l *levelDBRepo) GetAllByPrefix(prefix string) ([]Model, error) { - var models []Model +func (l *levelDBRepo) GetAllByPrefix(prefix string) ([]storage.Model, error) { + var models []storage.Model l.mu.RLock() defer l.mu.RUnlock() iter := l.db.NewIterator(util.BytesPrefix([]byte(prefix)), nil) @@ -122,10 +124,10 @@ func (l *levelDBRepo) GetAllByPrefix(prefix string) ([]Model, error) { return models, iter.Error() } -func (l *levelDBRepo) save(key []byte, model Model) error { +func (l *levelDBRepo) save(key []byte, model storage.Model) error { data, err := model.JSON() if err != nil { - return errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to marshall model: %v", err)) + return errors.NewTypedError(storage.ErrModelRepositorySerialisation, errors.New("failed to marshall model: %v", err)) } tp := getTypeIndirect(model.Type()) @@ -136,12 +138,12 @@ func (l *levelDBRepo) save(key []byte, model Model) error { data, err = json.Marshal(v) if err != nil { - return errors.NewTypedError(ErrModelRepositorySerialisation, errors.New("failed to marshall value: %v", err)) + return errors.NewTypedError(storage.ErrModelRepositorySerialisation, errors.New("failed to marshall value: %v", err)) } err = l.db.Put(key, data, nil) if err != nil { - return errors.NewTypedError(ErrRepositoryModelSave, errors.New("%v", err)) + return errors.NewTypedError(storage.ErrRepositoryModelSave, errors.New("%v", err)) } return nil @@ -149,18 +151,18 @@ func (l *levelDBRepo) save(key []byte, model Model) error { // Create creates a model indexed by the key provided // errors out if key already exists -func (l *levelDBRepo) Create(key []byte, model Model) error { +func (l *levelDBRepo) Create(key []byte, model storage.Model) error { if l.Exists(key) { - return ErrRepositoryModelCreateKeyExists + return storage.ErrRepositoryModelCreateKeyExists } return l.save(key, model) } // Update updates a model indexed by the key provided // errors out if key doesn't exists -func (l *levelDBRepo) Update(key []byte, model Model) error { +func (l *levelDBRepo) Update(key []byte, model storage.Model) error { if !l.Exists(key) { - return ErrRepositoryModelUpdateKeyNotFound + return storage.ErrRepositoryModelUpdateKeyNotFound } return l.save(key, model) } diff --git a/storage/leveldb_test.go b/storage/leveldb/leveldb_test.go similarity index 86% rename from storage/leveldb_test.go rename to storage/leveldb/leveldb_test.go index 22a0a7786..e5b401970 100644 --- a/storage/leveldb_test.go +++ b/storage/leveldb/leveldb_test.go @@ -1,16 +1,16 @@ // +build unit -package storage +package leveldb import ( "encoding/json" "reflect" "testing" - "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" ) @@ -35,7 +35,7 @@ func (m *doc) Type() reflect.Type { return reflect.TypeOf(m) } -func getRandomRepository() (Repository, string, error) { +func getRandomRepository() (storage.Repository, string, error) { randomPath := GetRandomTestStoragePath() db, err := NewLevelDBStorage(randomPath) if err != nil { @@ -61,7 +61,7 @@ func TestLevelDBRepo_Register(t *testing.T) { d := &doc{SomeString: "Hello, Repo!"} repo.Register(d) assert.Len(t, repo.(*levelDBRepo).models, 1, "should be not empty") - assert.Contains(t, repo.(*levelDBRepo).models, "storage.doc") + assert.Contains(t, repo.(*levelDBRepo).models, "leveldb.doc") } func TestLevelDBRepo_Exists(t *testing.T) { @@ -87,7 +87,7 @@ func TestLevelDBRepo_Get(t *testing.T) { // Key doesnt exist _, err = repo.Get(id) - assert.True(t, errors.IsOfType(ErrModelRepositoryNotFound, err)) + assert.True(t, errors.IsOfType(storage.ErrModelRepositoryNotFound, err)) d := &doc{SomeString: "Hello, Repo!"} err = repo.Create(id, d) @@ -95,7 +95,7 @@ func TestLevelDBRepo_Get(t *testing.T) { // Model not registered _, err = repo.Get(id) - assert.True(t, errors.IsOfType(ErrModelTypeNotRegistered, err)) + assert.True(t, errors.IsOfType(storage.ErrModelTypeNotRegistered, err)) // Success repo.Register(&doc{}) @@ -140,7 +140,7 @@ func TestLevelDBRepo_Create(t *testing.T) { //Already exists err = repo.Create(id, d) - assert.True(t, errors.IsOfType(ErrRepositoryModelCreateKeyExists, err)) + assert.True(t, errors.IsOfType(storage.ErrRepositoryModelCreateKeyExists, err)) } func TestLevelDBRepo_Update(t *testing.T) { @@ -152,7 +152,7 @@ func TestLevelDBRepo_Update(t *testing.T) { // Doesn't exist err = repo.Update(id, d) - assert.True(t, errors.IsOfType(ErrRepositoryModelUpdateKeyNotFound, err)) + assert.True(t, errors.IsOfType(storage.ErrRepositoryModelUpdateKeyNotFound, err)) err = repo.Create(id, d) assert.Nil(t, err) @@ -187,5 +187,5 @@ func TestLevelDBRepo_Delete(t *testing.T) { // Entry doesnt exist _, err = repo.Get(id) - assert.True(t, errors.IsOfType(ErrModelRepositoryNotFound, err)) + assert.True(t, errors.IsOfType(storage.ErrModelRepositoryNotFound, err)) } diff --git a/storage/test_bootstrapper.go b/storage/leveldb/test_bootstrapper.go similarity index 87% rename from storage/test_bootstrapper.go rename to storage/leveldb/test_bootstrapper.go index 8f7f88a1c..85c5934b0 100644 --- a/storage/test_bootstrapper.go +++ b/storage/leveldb/test_bootstrapper.go @@ -1,11 +1,12 @@ // +build integration unit -package storage +package leveldb import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/storage" "github.com/syndtr/goleveldb/leveldb" ) @@ -22,7 +23,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { if err != nil { return errors.New("failed to init config level db: %v", err) } - context[BootstrappedConfigDB] = NewLevelDBRepository(configdb) + context[storage.BootstrappedConfigDB] = NewLevelDBRepository(configdb) rs := GetRandomTestStoragePath() cfg.Set("storage.Path", rs) @@ -32,7 +33,7 @@ func (*Bootstrapper) TestBootstrap(context map[string]interface{}) (err error) { return errors.New("failed to init level db: %v", err) } log.Infof("Setting levelDb at: %s", cfg.GetStoragePath()) - context[BootstrappedDB] = NewLevelDBRepository(db) + context[storage.BootstrappedDB] = NewLevelDBRepository(db) return nil } diff --git a/storage/util.go b/storage/leveldb/util.go similarity index 95% rename from storage/util.go rename to storage/leveldb/util.go index 369cbc350..673642cc2 100644 --- a/storage/util.go +++ b/storage/leveldb/util.go @@ -1,4 +1,4 @@ -package storage +package leveldb import ( "fmt" diff --git a/storage/repository.go b/storage/repository.go index 159bef7c9..4a2bd5182 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -4,6 +4,13 @@ import ( "reflect" ) +const ( + // BootstrappedDB is a key mapped to DB at boot + BootstrappedDB string = "BootstrappedDB" + // BootstrappedConfigDB is a key mapped to DB for configs at boot + BootstrappedConfigDB string = "BootstrappedConfigDB" +) + // Model is an interface to abstract away storage model specificness type Model interface { //Returns the underlying type of the Model diff --git a/transactions/bootstrapper_test.go b/transactions/bootstrapper_test.go index 493210043..57fa0d622 100644 --- a/transactions/bootstrapper_test.go +++ b/transactions/bootstrapper_test.go @@ -5,8 +5,11 @@ package transactions import ( "testing" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" + + "github.com/centrifuge/go-centrifuge/storage/leveldb" + + "github.com/centrifuge/go-centrifuge/errors" "github.com/stretchr/testify/assert" ) @@ -16,10 +19,10 @@ func TestBootstrapper_Bootstrap(t *testing.T) { err := b.Bootstrap(ctx) assert.True(t, errors.IsOfType(ErrTransactionBootstrap, err)) - randomPath := storage.GetRandomTestStoragePath() - db, err := storage.NewLevelDBStorage(randomPath) + randomPath := leveldb.GetRandomTestStoragePath() + db, err := leveldb.NewLevelDBStorage(randomPath) assert.Nil(t, err) - ctx[storage.BootstrappedDB] = storage.NewLevelDBRepository(db) + ctx[storage.BootstrappedDB] = leveldb.NewLevelDBRepository(db) err = b.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRepo]) diff --git a/transactions/handler.go b/transactions/handler.go index 3d2d85287..2ac312938 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -3,7 +3,8 @@ package transactions import ( "context" - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/errors" @@ -18,14 +19,14 @@ const ErrInvalidTransactionID = errors.Error("Invalid Transaction ID") const ErrInvalidTenantID = errors.Error("Invalid Tenant ID") // GRPCHandler returns an implementation of the TransactionServiceServer -func GRPCHandler(srv Service, configService configstore.Service) transactionspb.TransactionServiceServer { +func GRPCHandler(srv Service, configService config.Service) transactionspb.TransactionServiceServer { return grpcHandler{srv: srv, configService: configService} } // grpcHandler implements transactionspb.TransactionServiceServer type grpcHandler struct { srv Service - configService configstore.Service + configService config.Service } // GetTransactionStatus returns transaction status of the given transaction id. @@ -40,7 +41,11 @@ func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactions return nil, ErrInvalidTransactionID } - cid, err := identity.ToCentID(tcs[0].IdentityID) + tid, err := tcs[0].GetIdentityID() + if err != nil { + return nil, ErrInvalidTenantID + } + cid, err := identity.ToCentID(tid) if err != nil || len(tcs) == 0 { return nil, ErrInvalidTenantID } diff --git a/transactions/handler_test.go b/transactions/handler_test.go index 7fea0fd42..fbbffc910 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -16,7 +18,7 @@ import ( ) func TestGRPCHandler_GetTransactionStatus(t *testing.T) { - cService := ctx[configstore.BootstrappedConfigStorage].(configstore.Service) + cService := ctx[configstore.BootstrappedConfigStorage].(config.Service) h := GRPCHandler(ctx[BootstrappedService].(Service), cService) req := new(transactionspb.TransactionStatusRequest) ctxl := context.Background() @@ -36,7 +38,8 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { // missing err tcs, _ := cService.GetAllTenants() - cid, err := identity.ToCentID(tcs[0].IdentityID) + tid, _ := tcs[0].GetIdentityID() + cid, err := identity.ToCentID(tid) tx := NewTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) diff --git a/transactions/repository_test.go b/transactions/repository_test.go index 2fb5415ac..ae1e6e0fe 100644 --- a/transactions/repository_test.go +++ b/transactions/repository_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/identity" @@ -14,7 +15,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" @@ -26,7 +26,7 @@ func TestMain(m *testing.M) { ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, - &storage.Bootstrapper{}, + &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, Bootstrapper{}, } From 1d3e83ada8a7b9565a8fd321542b249242e8f0e0 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Mon, 14 Jan 2019 16:07:24 +0100 Subject: [PATCH 130/220] add peer validator for Read ACL (#639) * add peer validator * refactor to bool --- coredocument/read_acls.go | 64 ++++++++++++++++++++++++++++++++-- coredocument/read_acls_test.go | 18 ++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index facf541ea..b20e0ca7b 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -1,13 +1,17 @@ package coredocument import ( + "bytes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" ) -// ErrZeroCollaborators error when no collaborators are passed -const ErrZeroCollaborators = errors.Error("require at least one collaborator") +const ( + // ErrZeroCollaborators error when no collaborators are passed + ErrZeroCollaborators = errors.Error("require at least one collaborator") +) // initReadRules initiates the read rules for a given coredocument. // Collaborators are given Read_Sign action. @@ -54,3 +58,59 @@ func appendRole(roles []*coredocumentpb.RoleEntry, role *coredocumentpb.Role) [] Role: role, }) } + +// ReadAccessValidator defines validator functions for peer. +type ReadAccessValidator interface { + PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool +} + +// readAccessValidator implements ReadAccessValidator. +type readAccessValidator struct{} + +// PeerCanRead validate if the core document can be read by the peer. +// Returns an error if not. +func (r readAccessValidator) PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool { + // lets loop though read rules + for _, rule := range cd.ReadRules { + for _, rk := range rule.Roles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + + if isPeerInRole(role, peer) { + return true + } + } + } + + return false +} + +func getRole(key uint32, roles []*coredocumentpb.RoleEntry) (*coredocumentpb.Role, error) { + for _, roleEntry := range roles { + if roleEntry.RoleKey == key { + return roleEntry.Role, nil + } + } + + return nil, errors.New("role %d not found", key) +} + +// isPeerInRole returns true if peer is in the given role as collaborators. +func isPeerInRole(role *coredocumentpb.Role, peer identity.CentID) bool { + for _, id := range role.Collaborators { + if bytes.Equal(id, peer[:]) { + return true + } + } + + return false +} + +// peerValidator return the +func peerValidator() ReadAccessValidator { + return readAccessValidator{} +} diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index 55607fe97..ce9544a49 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -27,3 +27,21 @@ func TestReadACLs_initReadRules(t *testing.T) { assert.Len(t, cd.ReadRules, 1) assert.Len(t, cd.Roles, 1) } + +func TestReadAccessValidator_PeerCanRead(t *testing.T) { + pv := peerValidator() + peer, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + cd, err := NewWithCollaborators([]string{peer.String()}) + assert.NoError(t, err) + assert.NotNil(t, cd.ReadRules) + assert.NotNil(t, cd.Roles) + + // peer who cant access + rcid := identity.RandomCentID() + assert.False(t, pv.PeerCanRead(cd, rcid)) + + // peer can access + assert.True(t, pv.PeerCanRead(cd, peer)) +} From bbb08c2c2edd5826133e46568183fc220316a03d Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 14 Jan 2019 16:42:08 +0100 Subject: [PATCH 131/220] API /config/tenants/generate endpoint (#637) * API /config/tenants/generate endpoint * Fix problems * Fix test issues * Fix test issues --- anchors/anchor_repository_integration_test.go | 4 +- api/bootstrapper.go | 2 +- api/bootstrapper_test.go | 4 +- api/server_test.go | 11 +- api/service.go | 4 +- bootstrap/bootstrappers/bootstrapper.go | 4 +- .../testingbootstrap/testing_bootstrap.go | 4 +- build/configs/default_config.yaml | 4 + build/configs/testing_config.yaml | 4 + cmd/centrifuge/manage_identities.go | 6 +- cmd/common.go | 5 +- config/bootstrapper.go | 4 + config/configstore/bootstrapper.go | 27 ++- config/configstore/bootstrapper_test.go | 2 +- config/configstore/error.go | 11 - config/configstore/handler.go | 9 + config/configstore/handler_test.go | 45 +++- config/configstore/mock_service.go | 5 + config/configstore/model.go | 19 +- config/configstore/model_test.go | 8 + config/configstore/repository_test.go | 4 + config/configstore/service.go | 127 +++++++++- .../configstore/service_integration_test.go | 59 +++++ config/configstore/service_test.go | 50 +++- config/configuration.go | 17 +- config/error.go | 3 + coredocument/bootstrapper.go | 3 +- crypto/ed25519/ed25519.go | 8 +- crypto/generate.go | 23 +- crypto/secp256k1/secp256k1.go | 6 +- crypto/secp256k1/secp256k1_test.go | 10 +- documents/bootstrapper.go | 3 +- documents/genericdoc/bootstrapper.go | 3 +- documents/invoice/bootstrapper.go | 8 +- documents/invoice/model_test.go | 4 +- documents/model_test.go | 6 +- documents/purchaseorder/bootstrapper.go | 8 +- documents/purchaseorder/model_test.go | 4 +- identity/ethid/bootstrapper.go | 6 +- .../ethereum_identity_integration_test.go | 13 +- identity/identity.go | 4 + nft/bootstrapper.go | 3 +- nft/ethereum_payment_obligation_test.go | 2 + nft/payment_obligation_integration_test.go | 3 +- p2p/bootstrapper.go | 2 +- p2p/bootstrapper_test.go | 4 +- p2p/client_integration_test.go | 5 +- p2p/receiver/handler_integration_test.go | 8 +- p2p/receiver/handler_test.go | 6 +- p2p/server_test.go | 6 +- protobufs/config/service.proto | 8 + protobufs/gen/go/config/service.pb.go | 225 ++++++++++-------- protobufs/gen/go/config/service.pb.gw.go | 42 ++++ protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 17 ++ resources/data.go | 8 +- testworld/config_test.go | 5 + testworld/document_consensus_test.go | 4 + testworld/httputils.go | 8 + testworld/nft_test.go | 6 +- testworld/park.go | 4 +- transactions/handler_test.go | 4 +- transactions/repository_test.go | 3 + 63 files changed, 662 insertions(+), 264 deletions(-) delete mode 100644 config/configstore/error.go create mode 100644 config/configstore/service_integration_test.go diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 195eac7aa..9ab9710b2 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -11,8 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/anchors" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" @@ -32,7 +30,7 @@ var ( func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - identityService = ctx[ethid.BootstrappedIDService].(identity.Service) + identityService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 1334cfdad..783a9698a 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -18,7 +18,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - _, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) + _, ok := ctx[config.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("config store not initialised") } diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index bb74d20da..88cb762ca 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -5,6 +5,8 @@ package api import ( "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" @@ -24,7 +26,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) cs := new(configstore.MockService) - m[configstore.BootstrappedConfigStorage] = cs + m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) diff --git a/api/server_test.go b/api/server_test.go index 32e25b6e8..bba671c66 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,14 +9,13 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/identity/ethid" - - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -50,11 +49,11 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, - anchors.Bootstrapper{}, ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &genericdoc.Bootstrapper{}, diff --git a/api/service.go b/api/service.go index b758eeb2b..ae90dbcea 100644 --- a/api/service.go +++ b/api/service.go @@ -37,9 +37,9 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, return errors.New("failed to get %s", documents.BootstrappedRegistry) } - configService, ok := nodeObjReg[configstore.BootstrappedConfigStorage].(config.Service) + configService, ok := nodeObjReg[config.BootstrappedConfigStorage].(config.Service) if !ok { - return errors.New("failed to get %s", configstore.BootstrappedConfigStorage) + return errors.New("failed to get %s", config.BootstrappedConfigStorage) } payObService, ok := nodeObjReg[nft.BootstrappedPayObService].(nft.PaymentObligation) diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 18d9463ad..87c6a355e 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -36,12 +36,12 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - &configstore.Bootstrapper{}, transactions.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, - &anchors.Bootstrapper{}, ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + &anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 08f000b7e..6f6db8c6f 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -31,11 +31,11 @@ var bootstappers = []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, - &configstore.Bootstrapper{}, ethereum.Bootstrapper{}, &queue.Bootstrapper{}, - anchors.Bootstrapper{}, ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, &genericdoc.Bootstrapper{}, diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 6694bb58c..676a7e758 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -65,6 +65,10 @@ configStorage: # Path for levelDB file path: /tmp/centrifuge_config_data.leveldb +# Tenant key storage +tenants: + keystore: /tmp/tenants + # Interface where the API and P2P Server listens to nodeHostname: 0.0.0.0 # Port where API Server listens to diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index e051442e7..20676d4dc 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -8,6 +8,10 @@ ethereum: identityId: "0x010101010101" +# Tenant key storage +tenants: + keystore: /tmp/tenants + queue: numWorkers: 2 workerWaitTimeMS: 1 diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index 3fa714e85..d0c4785e7 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -10,8 +10,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/identity" "github.com/spf13/cobra" @@ -49,7 +47,7 @@ var createIdentityCmd = &cobra.Command{ panic(err) } - idService := ctx[ethid.BootstrappedIDService].(identity.Service) + idService := ctx[identity.BootstrappedIDService].(identity.Service) _, confirmations, err := idService.CreateIdentity(tctx, centID) if err != nil { panic(err) @@ -91,7 +89,7 @@ var addKeyCmd = &cobra.Command{ } cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - idService := ctx[ethid.BootstrappedIDService].(identity.Service) + idService := ctx[identity.BootstrappedIDService].(identity.Service) err := idService.AddKeyFromConfig(cfg, purposeInt) if err != nil { panic(err) diff --git a/cmd/common.go b/cmd/common.go index 103e5b4fc..7ba8f9c0b 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -6,8 +6,6 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/storage" @@ -39,7 +37,6 @@ func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetSigningKeyPair() ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } @@ -102,7 +99,7 @@ func CreateConfig( return err } - idService := ctx[ethid.BootstrappedIDService].(identity.Service) + idService := ctx[identity.BootstrappedIDService].(identity.Service) id, err := createIdentity(tctx, idService) if err != nil { return err diff --git a/config/bootstrapper.go b/config/bootstrapper.go index 934556882..df0a9b399 100644 --- a/config/bootstrapper.go +++ b/config/bootstrapper.go @@ -4,7 +4,11 @@ import "github.com/centrifuge/go-centrifuge/bootstrap" // Bootstrap constants are keys to the value mappings in context bootstrap. const ( + // BootstrappedConfigFile points to the config file the node is bootstrapped with BootstrappedConfigFile string = "BootstrappedConfigFile" + + // BootstrappedConfigStorage indicates that config storage has been bootstrapped and its the key for config storage service in the bootstrap context + BootstrappedConfigStorage string = "BootstrappedConfigStorage" ) // Bootstrapper implements bootstrap.Bootstrapper to initialise config package. diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 7ef0b4774..ffd1f4b9f 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -4,14 +4,10 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" ) -const ( - // BootstrappedConfigStorage indicates that config storage has been bootstrapped and its the key for config storage service in the bootstrap context - BootstrappedConfigStorage string = "BootstrappedConfigStorage" -) - // Bootstrapper implements bootstrap.Bootstrapper to initialise configstore package. type Bootstrapper struct{} @@ -19,14 +15,19 @@ type Bootstrapper struct{} func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { cfg, ok := context[bootstrap.BootstrappedConfig].(config.Configuration) if !ok { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("could not find the bootstrapped config")) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("could not find the bootstrapped config")) } configdb, ok := context[storage.BootstrappedConfigDB].(storage.Repository) if !ok { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("could not find the storage repository")) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("could not find the storage repository")) } + idService, ok := context[identity.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + repo := &repo{configdb} - service := &service{repo} + service := &service{repo, idService} nc := NewNodeConfig(cfg) configdb.Register(nc) @@ -35,17 +36,17 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { nc, err = service.CreateConfig(NewNodeConfig(cfg)) if err != nil { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } } tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), cfg) if err != nil { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } configdb.Register(tc) i, err := nc.GetIdentityID() if err != nil { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } _, err = service.GetTenant(i) // if main tenant config doesn't exist in the db, add it @@ -53,9 +54,9 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { _, err = service.CreateTenant(tc) if err != nil { - return errors.NewTypedError(ErrConfigStorageBootstrap, errors.New("%v", err)) + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } } - context[BootstrappedConfigStorage] = service + context[config.BootstrappedConfigStorage] = service return nil } diff --git a/config/configstore/bootstrapper_test.go b/config/configstore/bootstrapper_test.go index abdb93c5e..3492546bd 100644 --- a/config/configstore/bootstrapper_test.go +++ b/config/configstore/bootstrapper_test.go @@ -15,7 +15,7 @@ func TestBootstrapper_BootstrapHappy(t *testing.T) { b := Bootstrapper{} err := b.Bootstrap(ctx) assert.NoError(t, err) - configService, ok := ctx[BootstrappedConfigStorage].(config.Service) + configService, ok := ctx[config.BootstrappedConfigStorage].(config.Service) assert.True(t, ok) _, err = configService.GetConfig() assert.NoError(t, err) diff --git a/config/configstore/error.go b/config/configstore/error.go deleted file mode 100644 index e1152c8a8..000000000 --- a/config/configstore/error.go +++ /dev/null @@ -1,11 +0,0 @@ -package configstore - -import "github.com/centrifuge/go-centrifuge/errors" - -const ( - // ErrConfigStorageBootstrap must be returned when there is an error while bootstrapping the config storage - ErrConfigStorageBootstrap = errors.Error("error when bootstrapping config storage") - - // ErrConfigRetrieve must be returned when there is an error while retrieving config - ErrConfigRetrieve = errors.Error("error when retrieving config") -) diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 31127d26f..93d87570a 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -84,6 +84,15 @@ func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData return tc.CreateProtobuf(), nil } +func (h grpcHandler) GenerateTenant(context.Context, *empty.Empty) (*configpb.TenantData, error) { + apiLog.Infof("Generating tenant config") + tc, err := h.service.GenerateTenant() + if err != nil { + return nil, err + } + return tc.CreateProtobuf(), nil +} + func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { apiLog.Infof("Updating node config: %v", data) nodeConfig := new(NodeConfig) diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 807b1cfa2..6c9634d0f 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -6,16 +6,19 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) func TestGrpcHandler_GetConfigNoConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) readCfg, err := h.GetConfig(context.Background(), nil) assert.NotNil(t, err) @@ -23,10 +26,11 @@ func TestGrpcHandler_GetConfigNoConfig(t *testing.T) { } func TestGrpcHandler_GetConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) @@ -37,10 +41,11 @@ func TestGrpcHandler_GetConfig(t *testing.T) { } func TestGrpcHandler_GetTenantNoConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: "0x123456789"}) assert.NotNil(t, err) @@ -48,10 +53,11 @@ func TestGrpcHandler_GetTenantNoConfig(t *testing.T) { } func TestGrpcHandler_GetTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) @@ -65,10 +71,11 @@ func TestGrpcHandler_GetTenant(t *testing.T) { } func TestGrpcHandler_GetAllTenants(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) tenantCfg1, err := NewTenantConfig("main", cfg) tenantCfg2, err := NewTenantConfig("main", cfg) @@ -85,10 +92,11 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { } func TestGrpcHandler_CreateConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) @@ -100,10 +108,11 @@ func TestGrpcHandler_CreateConfig(t *testing.T) { } func TestGrpcHandler_CreateTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) @@ -115,11 +124,22 @@ func TestGrpcHandler_CreateTenant(t *testing.T) { assert.NotNil(t, err) } +func TestGrpcHandler_GenerateTenant(t *testing.T) { + s := MockService{} + t1, _ := NewTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) + s.On("GenerateTenant").Return(t1, nil) + h := GRPCHandler(s) + tc, err := h.GenerateTenant(context.Background(), nil) + assert.NoError(t, err) + assert.NotNil(t, tc) +} + func TestGrpcHandler_UpdateConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) @@ -140,10 +160,11 @@ func TestGrpcHandler_UpdateConfig(t *testing.T) { } func TestGrpcHandler_UpdateTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) @@ -169,10 +190,11 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { } func TestGrpcHandler_DeleteConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) //No error when no config @@ -191,10 +213,11 @@ func TestGrpcHandler_DeleteConfig(t *testing.T) { } func TestGrpcHandler_DeleteTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) h := GRPCHandler(svc) //No error when no config diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index c249b7a7e..8a9710478 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -11,6 +11,11 @@ type MockService struct { mock.Mock } +func (m MockService) GenerateTenant() (config.TenantConfiguration, error) { + args := m.Called() + return args.Get(0).(config.TenantConfiguration), args.Error(1) +} + func (m MockService) GetConfig() (config.Configuration, error) { args := m.Called() return args.Get(0).(*NodeConfig), args.Error(1) diff --git a/config/configstore/model.go b/config/configstore/model.go index 7a02be738..18a5eed5b 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -6,15 +6,11 @@ import ( "reflect" "time" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" - + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/ethereum/go-ethereum/common" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/ethereum/go-ethereum/common/hexutil" - - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/golang/protobuf/ptypes/duration" ) @@ -32,6 +28,7 @@ func NewKeyPair(pub, priv string) KeyPair { type NodeConfig struct { MainIdentity TenantConfig StoragePath string + TenantsKeystore string P2PPort int P2PExternalIP string P2PConnectionTimeout time.Duration @@ -109,6 +106,11 @@ func (nc *NodeConfig) GetConfigStoragePath() string { panic("irrelevant, NodeConfig#GetConfigStoragePath must not be used") } +// GetTenantsKeystore returns the tenant keystore path. +func (nc *NodeConfig) GetTenantsKeystore() string { + return nc.TenantsKeystore +} + // GetP2PPort refer the interface func (nc *NodeConfig) GetP2PPort() int { return nc.P2PPort @@ -407,6 +409,7 @@ func NewNodeConfig(c config.Configuration) config.Configuration { }, }, StoragePath: c.GetStoragePath(), + TenantsKeystore: c.GetTenantsKeystore(), P2PPort: c.GetP2PPort(), P2PExternalIP: c.GetP2PExternalIP(), P2PConnectionTimeout: c.GetP2PConnectionTimeout(), @@ -443,6 +446,7 @@ func extractSmartContractAddresses(c config.Configuration) map[config.ContractNa type TenantConfig struct { EthereumAccount *config.AccountConfig EthereumDefaultAccountName string + EthereumContextWaitTimeout time.Duration ReceiveEventNotificationEndpoint string IdentityID []byte SigningKeyPair KeyPair @@ -481,7 +485,7 @@ func (tc *TenantConfig) GetEthAuthKeyPair() (pub, priv string) { // GetEthereumContextWaitTimeout gets EthereumContextWaitTimeout func (tc *TenantConfig) GetEthereumContextWaitTimeout() time.Duration { - panic("irrelevant, TenantConfig#GetEthereumContextWaitTimeout must not be used") + return tc.EthereumContextWaitTimeout } // ID Get the ID of the document represented by this model @@ -558,6 +562,7 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (config.Tena return &TenantConfig{ EthereumAccount: acc, EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), + EthereumContextWaitTimeout: c.GetEthereumContextWaitTimeout(), IdentityID: id, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 3a6e53cb8..21a567aaa 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -102,6 +102,11 @@ func (m *mockConfig) GetConfigStoragePath() string { return args.Get(0).(string) } +func (m *mockConfig) GetTenantsKeystore() string { + args := m.Called() + return args.Get(0).(string) +} + func (m *mockConfig) GetP2PPort() int { args := m.Called() return args.Get(0).(int) @@ -252,6 +257,7 @@ func TestNewTenantConfig(t *testing.T) { c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() NewTenantConfig("name", c) c.AssertExpectations(t) } @@ -283,6 +289,7 @@ func TestTenantConfigProtobuf(t *testing.T) { c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() + c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() tc, err := NewTenantConfig("name", c) assert.Nil(t, err) c.AssertExpectations(t) @@ -305,6 +312,7 @@ func TestTenantConfigProtobuf(t *testing.T) { func createMockConfig() *mockConfig { c := &mockConfig{} c.On("GetStoragePath").Return("dummyStorage").Once() + c.On("GetTenantsKeystore").Return("dummyKeyStorage").Once() c.On("GetP2PPort").Return(30000).Once() c.On("GetP2PExternalIP").Return("ip").Once() c.On("GetP2PConnectionTimeout").Return(time.Second).Once() diff --git a/config/configstore/repository_test.go b/config/configstore/repository_test.go index 0e0f1a0dc..5bdd5834e 100644 --- a/config/configstore/repository_test.go +++ b/config/configstore/repository_test.go @@ -7,6 +7,9 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/config" @@ -29,6 +32,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, } + ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) configdb := ctx[storage.BootstrappedConfigDB].(storage.Repository) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) diff --git a/config/configstore/service.go b/config/configstore/service.go index 3ccc9fbc4..8086724dd 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -1,18 +1,34 @@ package configstore import ( + "context" + "fmt" + "os" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" +) + +const ( + signingPubKeyName = "signingKey.pub.pem" + signingPrivKeyName = "signingKey.key.pem" + ethAuthPubKeyName = "ethauth.pub.pem" + ethAuthPrivKeyName = "ethauth.key.pem" ) type service struct { - repo repository + repo repository + idService identity.Service } // DefaultService returns an implementation of the config.Service -func DefaultService(repository repository) config.Service { - return &service{repo: repository} +func DefaultService(repository repository, idService identity.Service) config.Service { + return &service{repo: repository, idService: idService} } func (s service) GetConfig() (config.Configuration, error) { @@ -39,6 +55,107 @@ func (s service) CreateTenant(data config.TenantConfiguration) (config.TenantCon return data, s.repo.CreateTenant(id, data) } +func (s service) GenerateTenant() (config.TenantConfiguration, error) { + nc, err := s.GetConfig() + if err != nil { + return nil, err + } + + // copy the main tenant for basic settings + mtc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), nc) + if nil != err { + return nil, err + } + ctx, err := contextutil.NewCentrifugeContext(context.Background(), mtc) + if err != nil { + return nil, err + } + + id, confirmations, err := s.idService.CreateIdentity(ctx, identity.RandomCentID()) + if err != nil { + return nil, err + } + <-confirmations + + // copy the main tenant again to create the new tenant + tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), nc) + if err != nil { + return nil, err + } + + CID := id.CentID() + tc, err = generateTenantKeys(nc.GetTenantsKeystore(), tc.(*TenantConfig), CID) + if err != nil { + return nil, err + } + + err = s.idService.AddKeyFromConfig(tc, identity.KeyPurposeSigning) + if err != nil { + return nil, err + } + + err = s.idService.AddKeyFromConfig(tc, identity.KeyPurposeEthMsgAuth) + if err != nil { + return nil, err + } + + err = s.repo.CreateTenant(CID[:], tc) + if err != nil { + return nil, err + } + + return tc, nil +} + +func generateTenantKeys(keystore string, tc *TenantConfig, CID identity.CentID) (*TenantConfig, error) { + tc.IdentityID = CID[:] + Pub, err := createKeyPath(keystore, CID, signingPubKeyName) + if err != nil { + return nil, err + } + Priv, err := createKeyPath(keystore, CID, signingPrivKeyName) + if err != nil { + return nil, err + } + tc.SigningKeyPair = KeyPair{ + Pub: Pub, + Priv: Priv, + } + ePub, err := createKeyPath(keystore, CID, ethAuthPubKeyName) + if err != nil { + return nil, err + } + ePriv, err := createKeyPath(keystore, CID, ethAuthPrivKeyName) + if err != nil { + return nil, err + } + tc.EthAuthKeyPair = KeyPair{ + Pub: ePub, + Priv: ePriv, + } + err = crypto.GenerateSigningKeyPair(tc.SigningKeyPair.Pub, tc.SigningKeyPair.Priv, "ed25519") + if err != nil { + return nil, err + } + err = crypto.GenerateSigningKeyPair(tc.EthAuthKeyPair.Pub, tc.EthAuthKeyPair.Priv, "secp256k1") + if err != nil { + return nil, err + } + return tc, nil +} + +func createKeyPath(keyStorepath string, CID identity.CentID, keyName string) (string, error) { + tdir := fmt.Sprintf("%s/%s", keyStorepath, CID.String()) + // create tenant specific key dir + if _, err := os.Stat(tdir); os.IsNotExist(err) { + err := os.MkdirAll(tdir, os.ModePerm) + if err != nil { + return "", err + } + } + return fmt.Sprintf("%s/%s", tdir, keyName), nil +} + func (s service) UpdateConfig(data config.Configuration) (config.Configuration, error) { return data, s.repo.UpdateConfig(data) } @@ -63,7 +180,7 @@ func (s service) DeleteTenant(identifier []byte) error { func RetrieveConfig(dbOnly bool, ctx map[string]interface{}) (config.Configuration, error) { var cfg config.Configuration var err error - if cfgService, ok := ctx[BootstrappedConfigStorage].(config.Service); ok { + if cfgService, ok := ctx[config.BootstrappedConfigStorage].(config.Service); ok { // may be we need a way to detect a corrupted db here cfg, err = cfgService.GetConfig() if err != nil { @@ -76,7 +193,7 @@ func RetrieveConfig(dbOnly bool, ctx map[string]interface{}) (config.Configurati if _, ok := ctx[bootstrap.BootstrappedConfig]; ok && cfg == nil && !dbOnly { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) } else { - return nil, errors.NewTypedError(ErrConfigRetrieve, err) + return nil, errors.NewTypedError(config.ErrConfigRetrieve, err) } return cfg, nil } diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go new file mode 100644 index 000000000..612926466 --- /dev/null +++ b/config/configstore/service_integration_test.go @@ -0,0 +1,59 @@ +// +build integration + +package configstore_test + +import ( + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" +) + +var identityService identity.Service +var cfg config.Service + +func TestMain(m *testing.M) { + // Adding delay to startup (concurrency hack) + time.Sleep(time.Second + 2) + ctx := testingbootstrap.TestFunctionalEthereumBootstrap() + cfg = ctx[config.BootstrappedConfigStorage].(config.Service) + identityService = ctx[identity.BootstrappedIDService].(identity.Service) + result := m.Run() + testingbootstrap.TestFunctionalEthereumTearDown() + os.Exit(result) +} + +func TestService_GenerateTenantHappy(t *testing.T) { + tct, err := cfg.GenerateTenant() + assert.NoError(t, err) + i, _ := tct.GetIdentityID() + tc, err := cfg.GetTenant(i) + assert.NoError(t, err) + assert.NotNil(t, tc) + i, _ = tc.GetIdentityID() + cid, err := identity.ToCentID(i) + assert.NoError(t, err) + assert.True(t, tc.GetEthereumDefaultAccountName() != "") + pb, pv := tc.GetSigningKeyPair() + err = checkKeyPair(t, pb, pv) + pb, pv = tc.GetEthAuthKeyPair() + err = checkKeyPair(t, pb, pv) + exists, err := identityService.CheckIdentityExists(cid) + assert.NoError(t, err) + assert.True(t, exists) +} + +func checkKeyPair(t *testing.T, pb string, pv string) error { + assert.True(t, pb != "") + assert.True(t, pv != "") + _, err := os.Stat(pb) + assert.False(t, os.IsNotExist(err)) + _, err = os.Stat(pv) + assert.False(t, os.IsNotExist(err)) + return err +} diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index c581a6819..71f2a23c7 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -3,26 +3,33 @@ package configstore import ( + "os" "testing" + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/stretchr/testify/assert" ) func TestService_GetConfig_NoConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) cfg, err := svc.GetConfig() assert.NotNil(t, err) assert.Nil(t, cfg) } func TestService_GetConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) nodeCfg := NewNodeConfig(cfg) err = repo.CreateConfig(nodeCfg) assert.Nil(t, err) @@ -32,20 +39,22 @@ func TestService_GetConfig(t *testing.T) { } func TestService_GetTenant_NoTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) cfg, err := svc.GetTenant([]byte("0x123456789")) assert.NotNil(t, err) assert.Nil(t, cfg) } func TestService_GetTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) tid, _ := tenantCfg.GetIdentityID() @@ -57,10 +66,11 @@ func TestService_GetTenant(t *testing.T) { } func TestService_CreateConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) nodeCfg := NewNodeConfig(cfg) cfgpb, err := svc.CreateConfig(nodeCfg) assert.Nil(t, err) @@ -72,10 +82,11 @@ func TestService_CreateConfig(t *testing.T) { } func TestService_CreateTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) newCfg, err := svc.CreateTenant(tenantCfg) @@ -92,10 +103,11 @@ func TestService_CreateTenant(t *testing.T) { } func TestService_UpdateConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) nodeCfg := NewNodeConfig(cfg) //Config doesn't exists @@ -114,10 +126,11 @@ func TestService_UpdateConfig(t *testing.T) { } func TestService_UpdateTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) tenantCfg, err := NewTenantConfig("main", cfg) // Tenant doesn't exist @@ -140,10 +153,11 @@ func TestService_UpdateTenant(t *testing.T) { } func TestService_DeleteConfig(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) //No config, no error err = svc.DeleteConfig() @@ -161,10 +175,11 @@ func TestService_DeleteConfig(t *testing.T) { } func TestService_DeleteTenant(t *testing.T) { + idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo) + svc := DefaultService(repo, idService) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) tid, err := tenantCfg.GetIdentityID() @@ -183,3 +198,18 @@ func TestService_DeleteTenant(t *testing.T) { _, err = svc.GetTenant(tid) assert.NotNil(t, err) } + +func TestGenerateTenantKeys(t *testing.T) { + tc, err := generateTenantKeys("/tmp/tenants/", &TenantConfig{}, identity.RandomCentID()) + assert.Nil(t, err) + assert.NotNil(t, tc.SigningKeyPair) + assert.NotNil(t, tc.EthAuthKeyPair) + _, err = os.Stat(tc.SigningKeyPair.Pub) + assert.False(t, os.IsNotExist(err)) + _, err = os.Stat(tc.SigningKeyPair.Priv) + assert.False(t, os.IsNotExist(err)) + _, err = os.Stat(tc.EthAuthKeyPair.Pub) + assert.False(t, os.IsNotExist(err)) + _, err = os.Stat(tc.EthAuthKeyPair.Priv) + assert.False(t, os.IsNotExist(err)) +} diff --git a/config/configuration.go b/config/configuration.go index 29527fba0..ab612d8fe 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -16,14 +16,11 @@ import ( "sync" "time" - "github.com/centrifuge/go-centrifuge/storage" - - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/resources" + "github.com/centrifuge/go-centrifuge/storage" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" @@ -75,6 +72,7 @@ type Configuration interface { GetStoragePath() string GetConfigStoragePath() string + GetTenantsKeystore() string GetP2PPort() int GetP2PExternalIP() string GetP2PConnectionTimeout() time.Duration @@ -135,6 +133,7 @@ type Service interface { GetAllTenants() ([]TenantConfiguration, error) CreateConfig(data Configuration) (Configuration, error) CreateTenant(data TenantConfiguration) (TenantConfiguration, error) + GenerateTenant() (TenantConfiguration, error) UpdateConfig(data Configuration) (Configuration, error) UpdateTenant(data TenantConfiguration) (TenantConfiguration, error) DeleteConfig() error @@ -233,6 +232,11 @@ func (c *configuration) GetConfigStoragePath() string { return c.GetString("configStorage.path") } +// GetTenantsKeystore returns the tenants keystore location. +func (c *configuration) GetTenantsKeystore() string { + return c.GetString("tenants.keystore") +} + // GetP2PPort returns P2P Port. func (c *configuration) GetP2PPort() int { return c.GetInt("p2p.port") @@ -486,6 +490,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.SetConfigType("yaml") v.Set("storage.path", targetDataDir+"/db/centrifuge_data.leveldb") v.Set("configStorage.path", targetDataDir+"/db/centrifuge_config_data.leveldb") + v.Set("tenants.keystore", targetDataDir+"/tenants") v.Set("identityId", "") v.Set("centrifugeNetwork", network) v.Set("nodeHostname", "0.0.0.0") diff --git a/config/error.go b/config/error.go index 51140d84f..ec3d87f17 100644 --- a/config/error.go +++ b/config/error.go @@ -8,4 +8,7 @@ const ( // ErrConfigFileBootstrapNotFound used when config file is not found ErrConfigFileBootstrapNotFound = errors.Error("config file hasn't been provided") + + // ErrConfigRetrieve must be returned when there is an error while retrieving config + ErrConfigRetrieve = errors.Error("error when retrieving config") ) diff --git a/coredocument/bootstrapper.go b/coredocument/bootstrapper.go index ee28d6a69..e74964a2f 100644 --- a/coredocument/bootstrapper.go +++ b/coredocument/bootstrapper.go @@ -6,7 +6,6 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/ethid" ) // Bootstrapper to initialise processor @@ -24,7 +23,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 0f8dbe003..fb085749c 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -47,12 +47,12 @@ func GetSigningKeyPair(pub, priv string) (publicKey ed25519.PublicKey, privateKe } // GenerateSigningKeyPair generates ed25519 key pair -func GenerateSigningKeyPair() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey) { - publicKey, privateKey, err := ed25519.GenerateKey(nil) +func GenerateSigningKeyPair() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateKey, err error) { + publicKey, privateKey, err = ed25519.GenerateKey(nil) if err != nil { - log.Fatal(err) + return []byte{}, []byte{}, err } - return publicKey, privateKey + return publicKey, privateKey, nil } // PublicKeyToP2PKey returns p2pId from the public key diff --git a/crypto/generate.go b/crypto/generate.go index b6566da1c..247d6f449 100644 --- a/crypto/generate.go +++ b/crypto/generate.go @@ -9,17 +9,28 @@ import ( ) // GenerateSigningKeyPair generates based on the curveType and writes keys to file paths given. -func GenerateSigningKeyPair(publicFileName, privateFileName, curveType string) { +func GenerateSigningKeyPair(publicFileName, privateFileName, curveType string) (err error) { var publicKey, privateKey []byte switch strings.ToLower(curveType) { case CurveSecp256K1: - publicKey, privateKey = secp256k1.GenerateSigningKeyPair() + publicKey, privateKey, err = secp256k1.GenerateSigningKeyPair() case CurveEd25519: - publicKey, privateKey = ed25519.GenerateSigningKeyPair() + publicKey, privateKey, err = ed25519.GenerateSigningKeyPair() default: - publicKey, privateKey = ed25519.GenerateSigningKeyPair() + publicKey, privateKey, err = ed25519.GenerateSigningKeyPair() + } + if err != nil { + return err + } + + err = utils.WriteKeyToPemFile(privateFileName, utils.PrivateKey, privateKey) + if err != nil { + return err } - utils.WriteKeyToPemFile(privateFileName, utils.PrivateKey, privateKey) - utils.WriteKeyToPemFile(publicFileName, utils.PublicKey, publicKey) + err = utils.WriteKeyToPemFile(publicFileName, utils.PublicKey, publicKey) + if err != nil { + return err + } + return nil } diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index fdb540a2e..63c7ea4ab 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -25,11 +25,11 @@ const ( ) // GenerateSigningKeyPair generates secp2562k1 based keys. -func GenerateSigningKeyPair() (publicKey, privateKey []byte) { +func GenerateSigningKeyPair() (publicKey, privateKey []byte, err error) { log.Debug("generate secp256k1 keys") key, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) if err != nil { - log.Fatal(err) + return []byte{}, []byte{}, nil } publicKey = elliptic.Marshal(secp256k1.S256(), key.X, key.Y) @@ -37,7 +37,7 @@ func GenerateSigningKeyPair() (publicKey, privateKey []byte) { blob := key.D.Bytes() copy(privateKey[privateKeyLen-len(blob):], blob) - return publicKey, privateKey + return publicKey, privateKey, nil } // Sign signs the message using private key diff --git a/crypto/secp256k1/secp256k1_test.go b/crypto/secp256k1/secp256k1_test.go index bda1c7032..da8e75a63 100644 --- a/crypto/secp256k1/secp256k1_test.go +++ b/crypto/secp256k1/secp256k1_test.go @@ -34,7 +34,7 @@ func TestGenerateSigningKeyPair(t *testing.T) { const PublicKeyLen = 65 const PrivateKeyLen = 32 - publicKey, privateKey := GenerateSigningKeyPair() + publicKey, privateKey, _ := GenerateSigningKeyPair() assert.Equal(t, len(publicKey), PublicKeyLen, "secp256k1 public key not correct") assert.Equal(t, len(privateKey), PrivateKeyLen, "secp256k1 private key not correct") @@ -45,7 +45,7 @@ func TestSigningMsg(t *testing.T) { testMsg := make([]byte, MaxMsgLen) copy(testMsg, "test123") - publicKey, privateKey := GenerateSigningKeyPair() + publicKey, privateKey, _ := GenerateSigningKeyPair() signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) @@ -63,7 +63,7 @@ func TestVerifyFalseMsg(t *testing.T) { falseMsg := make([]byte, MaxMsgLen) copy(falseMsg, "false") - publicKey, privateKey := GenerateSigningKeyPair() + publicKey, privateKey, _ := GenerateSigningKeyPair() signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) @@ -78,9 +78,9 @@ func TestVerifyFalsePublicKey(t *testing.T) { testMsg := make([]byte, MaxMsgLen) copy(testMsg, "test123") - _, privateKey := GenerateSigningKeyPair() + _, privateKey, _ := GenerateSigningKeyPair() - falsePublicKey, _ := GenerateSigningKeyPair() + falsePublicKey, _, _ := GenerateSigningKeyPair() signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index f4c43d42c..58a845966 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -3,7 +3,6 @@ package documents import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" @@ -37,7 +36,7 @@ type PostBootstrapper struct{} // Bootstrap register task to the queue. func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) + cfgService, ok := ctx[config.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("config service not initialised") } diff --git a/documents/genericdoc/bootstrapper.go b/documents/genericdoc/bootstrapper.go index d3fea1a34..0a235b0c2 100644 --- a/documents/genericdoc/bootstrapper.go +++ b/documents/genericdoc/bootstrapper.go @@ -2,7 +2,6 @@ package genericdoc import ( "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/documents" @@ -22,7 +21,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index d717be04f..b792a6192 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -1,14 +1,12 @@ package invoice import ( - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -29,7 +27,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index d5e346ef3..d8f2b970a 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -54,10 +54,10 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, &genericdoc.Bootstrapper{}, @@ -69,7 +69,7 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) - configService = ctx[configstore.BootstrappedConfigStorage].(config.Service) + configService = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/model_test.go b/documents/model_test.go index 61e324e95..a483b4df2 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -6,6 +6,9 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -30,8 +33,9 @@ func TestMain(m *testing.M) { &queue.Bootstrapper{}, &Bootstrapper{}, } + ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) - ConfigService = ctx[configstore.BootstrappedConfigStorage].(config.Service) + ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index 0e1fa3208..a06d9ba9a 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -1,14 +1,12 @@ package purchaseorder import ( - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -29,7 +27,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("anchor repository not initialised") } - idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index d42b725b1..7f9d5430e 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -54,10 +54,10 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, p2p.Bootstrapper{}, @@ -68,7 +68,7 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) - configService = ctx[configstore.BootstrappedConfigStorage].(config.Service) + configService = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/identity/ethid/bootstrapper.go b/identity/ethid/bootstrapper.go index 7c9f7c625..61aa69bbd 100644 --- a/identity/ethid/bootstrapper.go +++ b/identity/ethid/bootstrapper.go @@ -4,6 +4,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" @@ -12,9 +13,6 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// BootstrappedIDService is used as a key to map the configured ID Service through context. -const BootstrappedIDService string = "BootstrappedIDService" - // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} @@ -47,7 +45,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } queueSrv := context[bootstrap.BootstrappedQueueServer].(*queue.Server) - context[BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, queueSrv, ethereum.GetClient, + context[identity.BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, queueSrv, ethereum.GetClient, func(address common.Address, backend bind.ContractBackend) (contract, error) { return NewEthereumIdentityContract(address, backend) }) diff --git a/identity/ethid/ethereum_identity_integration_test.go b/identity/ethid/ethereum_identity_integration_test.go index 825927756..3b34ee05a 100644 --- a/identity/ethid/ethereum_identity_integration_test.go +++ b/identity/ethid/ethereum_identity_integration_test.go @@ -8,14 +8,11 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/bootstrap" - cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -27,11 +24,11 @@ var cfg config.Configuration func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) - ctx := cc.TestFunctionalEthereumBootstrap() + ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - identityService = ctx[ethid.BootstrappedIDService].(identity.Service) + identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() - cc.TestFunctionalEthereumTearDown() + testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) } diff --git a/identity/identity.go b/identity/identity.go index 5ccd23379..e5ab0ee13 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -21,6 +21,10 @@ import ( ) const ( + + // BootstrappedIDService is used as a key to map the configured ID Service through context. + BootstrappedIDService string = "BootstrappedIDService" + // CentIDLength is the length in bytes of the CentrifugeID CentIDLength = 6 diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index c3588c646..35ea735a1 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -7,7 +7,6 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -39,7 +38,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("service registry not initialised") } - idService, ok := ctx[ethid.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) if !ok { return errors.New("identity service not initialised") } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 882ed1fbb..d697c5aa0 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -5,6 +5,7 @@ package nft import ( "math/big" "testing" + "time" "github.com/centrifuge/go-centrifuge/config" @@ -169,6 +170,7 @@ func TestPaymentObligationService(t *testing.T) { cid := identity.RandomCentID() configMock.On("GetIdentityID").Return(cid[:], nil) configMock.On("GetEthereumAccount").Return(&config.AccountConfig{}, nil) + configMock.On("GetEthereumContextWaitTimeout").Return(time.Second) configMock.On("GetReceiveEventNotificationEndpoint").Return("") configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 619855ff3..9271a18e8 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -36,7 +35,7 @@ func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - idService = ctx[ethid.BootstrappedIDService].(identity.Service) + idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txService = ctx[transactions.BootstrappedService].(transactions.Service) diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 8a063b023..df37e2a36 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -19,7 +19,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - cfgService, ok := ctx[configstore.BootstrappedConfigStorage].(config.Service) + cfgService, ok := ctx[config.BootstrappedConfigStorage].(config.Service) if !ok { return errors.New("configstore not initialised") } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 9c37ee8ef..bead4a968 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,6 +5,8 @@ package p2p import ( "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -25,7 +27,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { // config cs := new(configstore.MockService) m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) - m[configstore.BootstrappedConfigStorage] = cs + m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index eec1b6dac..c17a2e469 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -16,7 +16,6 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" @@ -37,8 +36,8 @@ func TestMain(m *testing.M) { flag.Parse() ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgStore = ctx[configstore.BootstrappedConfigStorage].(config.Service) - idService = ctx[ethid.BootstrappedIDService].(identity.Service) + cfgStore = ctx[config.BootstrappedConfigStorage].(config.Service) + idService = ctx[identity.BootstrappedIDService].(identity.Service) client = ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 747bdbc69..d35c2ab86 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,12 +8,8 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -49,10 +45,10 @@ func TestMain(m *testing.M) { flag.Parse() ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgService := ctx[configstore.BootstrappedConfigStorage].(config.Service) + cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - idService = ctx[ethid.BootstrappedIDService].(identity.Service) + idService = ctx[identity.BootstrappedIDService].(identity.Service) handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 003428488..5408da492 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -7,6 +7,9 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -54,9 +57,10 @@ func TestMain(m *testing.M) { documents.Bootstrapper{}, } ctx := make(map[string]interface{}) + ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgService := ctx[configstore.BootstrappedConfigStorage].(config.Service) + cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) result := m.Run() diff --git a/p2p/server_test.go b/p2p/server_test.go index 5be5846c7..497bd16e7 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,6 +10,9 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -40,8 +43,9 @@ func TestMain(m *testing.M) { documents.Bootstrapper{}, } ctx := make(map[string]interface{}) + ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[configstore.BootstrappedConfigStorage].(config.Service) + cfg = ctx[config.BootstrappedConfigStorage].(config.Service) c, _ := cfg.GetConfig() n := c.(*configstore.NodeConfig) n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index 8325f82f5..f6b729b51 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -56,6 +56,14 @@ service ConfigService { description: "Creates tenant config data" }; } + rpc GenerateTenant(google.protobuf.Empty) returns (TenantData) { + option (google.api.http) = { + post: "/config/tenants/generate" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Generates tenant config data taking defaults based on the main tenant" + }; + } rpc UpdateConfig(ConfigData) returns (ConfigData) { option (google.api.http) = { put: "/config/node" diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 906a8ff2c..88b79de2f 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -38,7 +38,7 @@ func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } func (*GetTenantRequest) ProtoMessage() {} func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{0} + return fileDescriptor_service_f381bc5e00981892, []int{0} } func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } func (*GetAllTenantResponse) ProtoMessage() {} func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{1} + return fileDescriptor_service_f381bc5e00981892, []int{1} } func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) @@ -115,7 +115,7 @@ func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } func (*UpdateTenantRequest) ProtoMessage() {} func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{2} + return fileDescriptor_service_f381bc5e00981892, []int{2} } func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) @@ -162,7 +162,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{3} + return fileDescriptor_service_f381bc5e00981892, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -215,7 +215,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{4} + return fileDescriptor_service_f381bc5e00981892, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -265,7 +265,7 @@ func (m *TenantData) Reset() { *m = TenantData{} } func (m *TenantData) String() string { return proto.CompactTextString(m) } func (*TenantData) ProtoMessage() {} func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{5} + return fileDescriptor_service_f381bc5e00981892, []int{5} } func (m *TenantData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TenantData.Unmarshal(m, b) @@ -359,7 +359,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_869e0c690febd200, []int{6} + return fileDescriptor_service_f381bc5e00981892, []int{6} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -561,6 +561,7 @@ type ConfigServiceClient interface { GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) CreateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) + GenerateTenant(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*TenantData, error) UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) DeleteConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) @@ -620,6 +621,15 @@ func (c *configServiceClient) CreateTenant(ctx context.Context, in *TenantData, return out, nil } +func (c *configServiceClient) GenerateTenant(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*TenantData, error) { + out := new(TenantData) + err := c.cc.Invoke(ctx, "/config.ConfigService/GenerateTenant", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *configServiceClient) UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) { out := new(ConfigData) err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateConfig", in, out, opts...) @@ -663,6 +673,7 @@ type ConfigServiceServer interface { GetAllTenants(context.Context, *empty.Empty) (*GetAllTenantResponse, error) CreateConfig(context.Context, *ConfigData) (*ConfigData, error) CreateTenant(context.Context, *TenantData) (*TenantData, error) + GenerateTenant(context.Context, *empty.Empty) (*TenantData, error) UpdateConfig(context.Context, *ConfigData) (*ConfigData, error) UpdateTenant(context.Context, *UpdateTenantRequest) (*TenantData, error) DeleteConfig(context.Context, *empty.Empty) (*empty.Empty, error) @@ -763,6 +774,24 @@ func _ConfigService_CreateTenant_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _ConfigService_GenerateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConfigServiceServer).GenerateTenant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/config.ConfigService/GenerateTenant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConfigServiceServer).GenerateTenant(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _ConfigService_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ConfigData) if err := dec(in); err != nil { @@ -859,6 +888,10 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ MethodName: "CreateTenant", Handler: _ConfigService_CreateTenant_Handler, }, + { + MethodName: "GenerateTenant", + Handler: _ConfigService_GenerateTenant_Handler, + }, { MethodName: "UpdateConfig", Handler: _ConfigService_UpdateConfig_Handler, @@ -880,91 +913,95 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_869e0c690febd200) } - -var fileDescriptor_service_869e0c690febd200 = []byte{ - // 1326 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xe9, 0x6a, 0x1b, 0xc9, - 0x16, 0x46, 0x76, 0xbc, 0x95, 0x24, 0x2f, 0xe5, 0x25, 0x9d, 0x8e, 0xe3, 0x74, 0x14, 0x6e, 0xae, - 0x08, 0xb1, 0x04, 0xba, 0x17, 0xb2, 0xfc, 0x08, 0x28, 0xb6, 0x30, 0xe6, 0xde, 0x64, 0x44, 0x27, - 0x21, 0xcc, 0x0c, 0x43, 0x53, 0x56, 0x1f, 0x4b, 0x4d, 0x5a, 0x5d, 0x95, 0xea, 0xd3, 0xb2, 0xc5, - 0x30, 0x30, 0x84, 0x79, 0x02, 0xcd, 0x2b, 0xcc, 0x1b, 0xcd, 0x2b, 0xcc, 0xbc, 0xc7, 0x50, 0x4b, - 0x5b, 0xb2, 0x25, 0xdb, 0xe4, 0x97, 0xd4, 0x67, 0xf9, 0xbe, 0x73, 0xbe, 0x3a, 0xb5, 0x90, 0xad, - 0x0e, 0x4f, 0x4e, 0xa3, 0x6e, 0x3d, 0x05, 0x39, 0x88, 0x3a, 0x50, 0x13, 0x92, 0x23, 0xa7, 0x8b, - 0xc6, 0xea, 0xee, 0x76, 0x39, 0xef, 0xc6, 0x50, 0x67, 0x22, 0xaa, 0xb3, 0x24, 0xe1, 0xc8, 0x30, - 0xe2, 0x49, 0x6a, 0xa2, 0xdc, 0x3d, 0xeb, 0xd5, 0x5f, 0x27, 0xd9, 0x69, 0x3d, 0xcc, 0xa4, 0x0e, - 0xb0, 0xfe, 0xfb, 0x57, 0xfd, 0xd0, 0x17, 0x38, 0xb4, 0xce, 0x67, 0xfa, 0xa7, 0xb3, 0xdf, 0x85, - 0x64, 0x3f, 0x3d, 0x63, 0xdd, 0x2e, 0xc8, 0x3a, 0x17, 0x1a, 0x7e, 0x9a, 0xaa, 0xd2, 0x20, 0xeb, - 0x47, 0x80, 0x1f, 0x20, 0x61, 0x09, 0xfa, 0xf0, 0x25, 0x83, 0x14, 0xe9, 0x1e, 0x21, 0x51, 0x08, - 0x09, 0x46, 0xa7, 0x11, 0x48, 0xa7, 0xe0, 0x15, 0xaa, 0x2b, 0xfe, 0x84, 0xa5, 0xf2, 0x9a, 0x6c, - 0x1d, 0x01, 0x36, 0xe3, 0x38, 0x4f, 0x4b, 0x05, 0x4f, 0x52, 0xa0, 0x4f, 0xc8, 0x9d, 0x90, 0x21, - 0x73, 0x0a, 0xde, 0x7c, 0xb5, 0xd8, 0xa0, 0x35, 0xd3, 0x6b, 0xcd, 0x44, 0x1d, 0x32, 0x64, 0xbe, - 0xf6, 0x57, 0x7e, 0x22, 0x9b, 0x1f, 0x45, 0xc8, 0x10, 0xbe, 0x89, 0xf6, 0x02, 0x7e, 0xce, 0x2b, - 0xdc, 0x08, 0xff, 0x3d, 0x59, 0x6b, 0x61, 0x0f, 0x24, 0x64, 0xfd, 0x66, 0xa7, 0xc3, 0xb3, 0x04, - 0xa9, 0x43, 0x96, 0x58, 0x18, 0x4a, 0x48, 0x53, 0x8b, 0x9b, 0x7f, 0xd2, 0x75, 0x32, 0xff, 0x19, - 0x86, 0x1a, 0x73, 0xc5, 0x57, 0x7f, 0xa9, 0x4b, 0x96, 0x05, 0x4b, 0xd3, 0x33, 0x2e, 0x43, 0x67, - 0x5e, 0x9b, 0x2f, 0xbe, 0x2b, 0xfb, 0x64, 0xe9, 0x7f, 0x30, 0x6c, 0xb3, 0x48, 0xaa, 0x44, 0x91, - 0x9d, 0x58, 0x38, 0xf5, 0x57, 0x5b, 0x06, 0x98, 0x43, 0x89, 0x01, 0x56, 0xfe, 0x9e, 0x23, 0x64, - 0x5c, 0x1e, 0x7d, 0x41, 0x8a, 0x80, 0xbd, 0x80, 0x99, 0xa2, 0x74, 0x6a, 0xb1, 0x71, 0x37, 0xef, - 0xe3, 0x4a, 0xcd, 0x3e, 0x01, 0xec, 0xe5, 0xf5, 0x3f, 0x27, 0x8e, 0xca, 0x0c, 0xe1, 0x94, 0x65, - 0x31, 0xe6, 0x08, 0x41, 0xc2, 0xfa, 0x60, 0xf9, 0xb6, 0x01, 0x7b, 0x87, 0xc6, 0x6d, 0x93, 0xde, - 0xb1, 0x3e, 0xd0, 0xb7, 0xe4, 0xb1, 0x84, 0x0e, 0x44, 0x03, 0x08, 0x60, 0x00, 0x2a, 0x85, 0x2b, - 0x35, 0x3b, 0x7a, 0x06, 0x02, 0x48, 0x42, 0xc1, 0xa3, 0x04, 0x6d, 0x9f, 0x9e, 0x0d, 0x6d, 0xa9, - 0xc8, 0x77, 0x13, 0x81, 0x2d, 0x1b, 0x47, 0x1f, 0x92, 0xa2, 0x59, 0x10, 0x1c, 0x06, 0x51, 0xe8, - 0xdc, 0x99, 0x5c, 0x23, 0x1c, 0x1e, 0x87, 0xf4, 0x25, 0x59, 0x4f, 0xa3, 0x6e, 0x12, 0x25, 0xdd, - 0xe0, 0x33, 0x0c, 0x03, 0xc1, 0x22, 0xe9, 0x2c, 0xe8, 0x3e, 0xd7, 0xf2, 0x3e, 0xad, 0x80, 0xfe, - 0xaa, 0x0d, 0xcc, 0x05, 0x7d, 0x49, 0xd6, 0x01, 0x7b, 0x2c, 0xc3, 0xde, 0x38, 0x75, 0xf1, 0x9a, - 0x54, 0x1b, 0x68, 0xbf, 0x2b, 0xbf, 0xad, 0x10, 0x72, 0xa0, 0x43, 0xb4, 0xce, 0x8f, 0x48, 0x29, - 0x45, 0x2e, 0x59, 0x17, 0x02, 0xc1, 0xb0, 0x67, 0xd7, 0xa8, 0x68, 0x6d, 0x6d, 0x86, 0x3d, 0x7a, - 0x8f, 0x2c, 0x8b, 0x86, 0x08, 0x04, 0x97, 0x66, 0xc1, 0x16, 0xfc, 0x25, 0xd1, 0x10, 0x6d, 0x2e, - 0x91, 0x3e, 0x21, 0x6b, 0xca, 0x05, 0xe7, 0x08, 0x32, 0x61, 0x71, 0x10, 0x09, 0x2b, 0x4f, 0x59, - 0x34, 0x44, 0xcb, 0x5a, 0x8f, 0x05, 0xfd, 0x8e, 0xec, 0xa8, 0xb8, 0x0e, 0x4f, 0x12, 0xe8, 0x68, - 0x39, 0x31, 0xea, 0x03, 0xcf, 0x50, 0xcb, 0x52, 0x6c, 0xdc, 0xab, 0x99, 0x5d, 0x5a, 0xcb, 0x77, - 0x69, 0xed, 0xd0, 0xee, 0x62, 0x7f, 0x4b, 0x34, 0xc4, 0xc1, 0x45, 0xde, 0x07, 0x93, 0xa6, 0xc4, - 0x55, 0x87, 0x05, 0x48, 0x53, 0xd6, 0x82, 0x2e, 0x8b, 0x18, 0x93, 0xae, 0xec, 0x5f, 0x64, 0xd5, - 0x06, 0xe4, 0xc3, 0xbc, 0x68, 0x0a, 0x33, 0xd6, 0xa6, 0x1d, 0xe9, 0x87, 0xa4, 0x98, 0x64, 0xfd, - 0xe0, 0x8c, 0xcb, 0xcf, 0x20, 0x53, 0x67, 0xc9, 0xe0, 0x24, 0x59, 0xff, 0x93, 0xb1, 0xd0, 0x7d, - 0xb2, 0x69, 0x9c, 0xc1, 0x19, 0x8b, 0x50, 0x97, 0x1d, 0xf4, 0x53, 0x67, 0x59, 0x07, 0xae, 0x1b, - 0xd7, 0x27, 0x16, 0xa1, 0x2a, 0xec, 0x6d, 0x4a, 0x3d, 0x52, 0x52, 0xc3, 0x97, 0xf0, 0x10, 0x82, - 0x4c, 0xc6, 0xce, 0x8a, 0x59, 0x75, 0xc0, 0xde, 0x3b, 0x1e, 0xc2, 0x47, 0x19, 0xd3, 0x1f, 0xc9, - 0x03, 0x15, 0xd1, 0xe1, 0x09, 0xc2, 0x39, 0x06, 0x12, 0x58, 0x38, 0x86, 0x56, 0x8a, 0x90, 0xdb, - 0x14, 0xb9, 0x07, 0xd8, 0x3b, 0x30, 0xe9, 0x3e, 0xb0, 0x30, 0x67, 0x57, 0xb2, 0xf8, 0x66, 0xf6, - 0x73, 0xf0, 0x4b, 0xb8, 0xc5, 0xdb, 0x70, 0xb7, 0xc7, 0xb8, 0x93, 0x98, 0x47, 0x84, 0x2a, 0xcc, - 0x28, 0x41, 0x90, 0x03, 0x16, 0x07, 0x12, 0x50, 0x0e, 0x9d, 0xd2, 0x6d, 0x68, 0x6a, 0x40, 0x8f, - 0x6d, 0x8e, 0xaf, 0x52, 0xd4, 0xb0, 0x28, 0xa0, 0x3e, 0x3b, 0xd7, 0x18, 0x11, 0xa4, 0x4e, 0xd9, - 0x2b, 0x54, 0xcb, 0x7e, 0x19, 0xb0, 0xf7, 0x96, 0x9d, 0xfb, 0xc6, 0x48, 0x2b, 0x44, 0x19, 0x82, - 0x2e, 0x4b, 0x03, 0x21, 0xa3, 0x0e, 0x38, 0xab, 0x5e, 0xa1, 0x7a, 0xc7, 0x57, 0xe7, 0xc1, 0x11, - 0x4b, 0xdb, 0xca, 0x34, 0x19, 0x13, 0x47, 0xfd, 0x08, 0x9d, 0xb5, 0xc9, 0x98, 0xff, 0x2b, 0x93, - 0xe2, 0xc3, 0xf3, 0x40, 0x70, 0x1e, 0x07, 0x90, 0xb0, 0x93, 0x18, 0x42, 0x67, 0xdd, 0x2b, 0x54, - 0x97, 0xfd, 0x32, 0x9e, 0xb7, 0x39, 0x8f, 0x5b, 0xc6, 0xa8, 0x0e, 0xbc, 0x04, 0x50, 0x2d, 0xa5, - 0xb3, 0x61, 0x0e, 0x3c, 0xfb, 0x49, 0xff, 0x4d, 0xd6, 0x4e, 0x38, 0xc7, 0x14, 0x25, 0x13, 0x81, - 0x00, 0x35, 0x21, 0xd4, 0x9b, 0xaf, 0xae, 0xf8, 0xab, 0x17, 0xe6, 0xb6, 0xb2, 0xd2, 0x07, 0x84, - 0xd8, 0x1c, 0xb5, 0xd5, 0x37, 0x75, 0x57, 0x2b, 0xd6, 0x72, 0x1c, 0xd2, 0xe7, 0xa4, 0xdc, 0x67, - 0x51, 0x12, 0xe4, 0x9b, 0xdf, 0xd9, 0xba, 0xf6, 0x58, 0x2e, 0xa9, 0xc0, 0x63, 0x1b, 0x47, 0x7b, - 0xc4, 0x49, 0xfb, 0x4c, 0xa2, 0x5e, 0x51, 0xc9, 0x3a, 0x98, 0x4f, 0x33, 0xa4, 0xce, 0xb6, 0xbe, - 0x39, 0x6a, 0x39, 0xc6, 0x78, 0x4f, 0xd7, 0xde, 0xab, 0x94, 0x03, 0x9b, 0xd1, 0xcc, 0x13, 0x5a, - 0x09, 0xca, 0xa1, 0xbf, 0x93, 0xce, 0x74, 0xd2, 0xc7, 0xa4, 0x2c, 0x84, 0xe4, 0xa7, 0x17, 0x52, - 0xed, 0x68, 0xa9, 0x4a, 0xda, 0x68, 0x95, 0x72, 0x8f, 0xc9, 0xfd, 0x1b, 0xb0, 0xf3, 0xfb, 0xa1, - 0x30, 0xbe, 0x1f, 0xb6, 0xc8, 0xc2, 0x80, 0xc5, 0x59, 0x7e, 0xf0, 0x9a, 0x8f, 0x57, 0x73, 0x2f, - 0x0a, 0x8d, 0x3f, 0x96, 0x49, 0xd9, 0x94, 0xfc, 0xde, 0x5c, 0xfa, 0x94, 0x91, 0x95, 0x23, 0x40, - 0x63, 0xa3, 0x3b, 0x53, 0x83, 0xd5, 0x52, 0xd7, 0xb6, 0x4b, 0xa7, 0xdb, 0xad, 0x54, 0x47, 0xcd, - 0x0d, 0x77, 0xed, 0x08, 0xd0, 0x53, 0x7b, 0xcc, 0x33, 0x9e, 0xaf, 0x7f, 0xfe, 0xf5, 0xfb, 0xdc, - 0x2a, 0x2d, 0xd5, 0xed, 0xd3, 0x42, 0xed, 0x48, 0x9a, 0x69, 0x0a, 0xa3, 0x36, 0x75, 0x72, 0xa8, - 0xab, 0x77, 0xba, 0x3b, 0x63, 0x5d, 0x2a, 0xaf, 0x46, 0xcd, 0x4d, 0x77, 0x43, 0x91, 0x18, 0xe3, - 0x24, 0xcd, 0x1e, 0xdd, 0xcd, 0x69, 0x50, 0x3b, 0xd3, 0xfa, 0xcf, 0xe3, 0xbb, 0xf8, 0x17, 0x3a, - 0x24, 0xe5, 0xc9, 0x37, 0x40, 0x7a, 0x6d, 0x77, 0xbb, 0x13, 0x25, 0x4d, 0x3d, 0x19, 0x2a, 0x8d, - 0x51, 0xd3, 0x71, 0x77, 0x54, 0x09, 0xcd, 0x38, 0xbe, 0x5c, 0x46, 0xaa, 0xeb, 0xd8, 0xa0, 0x6b, - 0x57, 0xea, 0xa0, 0x31, 0x29, 0x1d, 0x48, 0x60, 0x08, 0x56, 0xd7, 0x19, 0xfa, 0xcd, 0xd4, 0xf4, - 0xbf, 0xa3, 0xa6, 0xeb, 0x3a, 0x26, 0x35, 0xf5, 0x94, 0x78, 0x9e, 0x09, 0xf2, 0xd4, 0xb3, 0xc1, - 0xb0, 0x55, 0x2e, 0x89, 0xfb, 0xaa, 0xf0, 0x94, 0x7e, 0xc9, 0xd9, 0xac, 0xc4, 0x33, 0x84, 0x9c, - 0x29, 0xee, 0xcb, 0x51, 0x73, 0xd7, 0x75, 0x73, 0x36, 0x53, 0xfb, 0x14, 0xdf, 0x56, 0xe5, 0x6a, - 0x77, 0x8a, 0xb2, 0x4b, 0x4a, 0xe6, 0x7d, 0xf4, 0x8d, 0x0d, 0xd6, 0x47, 0xcd, 0x6d, 0xd7, 0x3e, - 0xad, 0x2e, 0x35, 0x68, 0x7a, 0x73, 0xa7, 0x7a, 0xfb, 0x5a, 0xc8, 0x99, 0x6c, 0x73, 0xf7, 0x73, - 0xd4, 0x19, 0xef, 0xb3, 0x99, 0x5d, 0x36, 0x47, 0xcd, 0xbb, 0xee, 0x76, 0x4e, 0x79, 0xa9, 0x4b, - 0x4d, 0xfa, 0xc8, 0xbd, 0x71, 0x8c, 0x54, 0x11, 0x31, 0x29, 0x1d, 0x42, 0x0c, 0x17, 0xdd, 0x5e, - 0x37, 0x48, 0xd7, 0xd8, 0x2b, 0xcf, 0x74, 0xd7, 0x06, 0x62, 0xba, 0xeb, 0xd5, 0xa7, 0x97, 0xb7, - 0xcb, 0xaf, 0x85, 0x9c, 0xee, 0xd6, 0x2d, 0x73, 0x1d, 0xe1, 0x6b, 0xdd, 0x73, 0x4e, 0x38, 0xdd, - 0xf3, 0xde, 0xd3, 0x1b, 0x7b, 0x7e, 0xf3, 0x84, 0x90, 0x0e, 0xef, 0x5b, 0xda, 0x37, 0x25, 0x7b, - 0x56, 0xb4, 0x15, 0x49, 0xbb, 0xf0, 0xc3, 0xb2, 0xb1, 0x8b, 0x93, 0x93, 0x45, 0xcd, 0xfb, 0x9f, - 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9e, 0x81, 0x92, 0x4a, 0x0c, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_f381bc5e00981892) } + +var fileDescriptor_service_f381bc5e00981892 = []byte{ + // 1385 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xe9, 0x6e, 0x1b, 0x47, + 0x12, 0x06, 0x25, 0xeb, 0x60, 0x93, 0xd4, 0xd1, 0x3a, 0x3c, 0x1e, 0xcb, 0xf2, 0x98, 0xc6, 0x7a, + 0x05, 0xc3, 0x22, 0x01, 0xee, 0x02, 0x3e, 0x7e, 0x18, 0xa0, 0x25, 0x82, 0x10, 0x76, 0xed, 0x10, + 0x63, 0x1b, 0x46, 0x12, 0x04, 0x83, 0x16, 0xa7, 0x44, 0x4e, 0x34, 0xec, 0x6e, 0xf7, 0x34, 0x29, + 0x11, 0x41, 0x80, 0xc0, 0xc8, 0x13, 0x30, 0x2f, 0x91, 0xb7, 0xc9, 0x8f, 0xbc, 0x42, 0xf2, 0x1e, + 0x41, 0x5f, 0x22, 0x25, 0x52, 0x12, 0xfc, 0x8b, 0x9c, 0xea, 0xaa, 0xef, 0xab, 0xfa, 0xaa, 0xfa, + 0x40, 0x9b, 0x6d, 0x46, 0x4f, 0x92, 0x4e, 0x35, 0x03, 0x31, 0x48, 0xda, 0x50, 0xe1, 0x82, 0x49, + 0x86, 0x17, 0x8d, 0xd5, 0xdf, 0xe9, 0x30, 0xd6, 0x49, 0xa1, 0x4a, 0x78, 0x52, 0x25, 0x94, 0x32, + 0x49, 0x64, 0xc2, 0x68, 0x66, 0xbc, 0xfc, 0x5d, 0xbb, 0xaa, 0xbf, 0x8e, 0xfb, 0x27, 0xd5, 0xb8, + 0x2f, 0xb4, 0x83, 0x5d, 0xbf, 0x7f, 0x75, 0x1d, 0x7a, 0x5c, 0x0e, 0xed, 0xe2, 0x33, 0xfd, 0xd3, + 0xde, 0xef, 0x00, 0xdd, 0xcf, 0xce, 0x48, 0xa7, 0x03, 0xa2, 0xca, 0xb8, 0x86, 0x9f, 0xa6, 0x2a, + 0xd7, 0xd0, 0x5a, 0x13, 0xe4, 0x07, 0xa0, 0x84, 0xca, 0x10, 0x3e, 0xf7, 0x21, 0x93, 0x78, 0x17, + 0xa1, 0x24, 0x06, 0x2a, 0x93, 0x93, 0x04, 0x84, 0x97, 0x0b, 0x72, 0x7b, 0xf9, 0x70, 0xc2, 0x52, + 0x7e, 0x8d, 0x36, 0x9b, 0x20, 0xeb, 0x69, 0xea, 0xc2, 0x32, 0xce, 0x68, 0x06, 0xf8, 0x09, 0xba, + 0x13, 0x13, 0x49, 0xbc, 0x5c, 0x30, 0xbf, 0x57, 0xa8, 0xe1, 0x8a, 0xa9, 0xb5, 0x62, 0xbc, 0x0e, + 0x89, 0x24, 0xa1, 0x5e, 0x2f, 0xff, 0x80, 0x36, 0x3e, 0xf2, 0x98, 0x48, 0xf8, 0x2a, 0xda, 0x0b, + 0xf8, 0xb9, 0x20, 0x77, 0x23, 0xfc, 0xb7, 0x68, 0xb5, 0x21, 0xbb, 0x20, 0xa0, 0xdf, 0xab, 0xb7, + 0xdb, 0xac, 0x4f, 0x25, 0xf6, 0xd0, 0x12, 0x89, 0x63, 0x01, 0x59, 0x66, 0x71, 0xdd, 0x27, 0x5e, + 0x43, 0xf3, 0xa7, 0x30, 0xd4, 0x98, 0xf9, 0x50, 0xfd, 0xc5, 0x3e, 0x5a, 0xe6, 0x24, 0xcb, 0xce, + 0x98, 0x88, 0xbd, 0x79, 0x6d, 0xbe, 0xf8, 0x2e, 0xef, 0xa3, 0xa5, 0xff, 0xc1, 0xb0, 0x45, 0x12, + 0xa1, 0x02, 0x79, 0xff, 0xd8, 0xc2, 0xa9, 0xbf, 0xda, 0x32, 0x90, 0x0e, 0x8a, 0x0f, 0x64, 0xf9, + 0xef, 0x39, 0x84, 0xc6, 0xe9, 0xe1, 0x17, 0xa8, 0x00, 0xb2, 0x1b, 0x11, 0x93, 0x94, 0x0e, 0x2d, + 0xd4, 0xee, 0xba, 0x3a, 0xae, 0xe4, 0x1c, 0x22, 0x90, 0x5d, 0x97, 0xff, 0x73, 0xe4, 0xa9, 0xc8, + 0x18, 0x4e, 0x48, 0x3f, 0x95, 0x0e, 0x21, 0xa2, 0xa4, 0x07, 0x96, 0x6f, 0x0b, 0x64, 0xf7, 0xd0, + 0x2c, 0xdb, 0xa0, 0x77, 0xa4, 0x07, 0xf8, 0x2d, 0x7a, 0x2c, 0xa0, 0x0d, 0xc9, 0x00, 0x22, 0x18, + 0x80, 0x0a, 0x61, 0x4a, 0xcd, 0xb6, 0x9e, 0x81, 0x08, 0x68, 0xcc, 0x59, 0x42, 0xa5, 0xad, 0x33, + 0xb0, 0xae, 0x0d, 0xe5, 0xf9, 0x6e, 0xc2, 0xb1, 0x61, 0xfd, 0xf0, 0x43, 0x54, 0x30, 0x0d, 0x91, + 0xc3, 0x28, 0x89, 0xbd, 0x3b, 0x93, 0x3d, 0x92, 0xc3, 0xa3, 0x18, 0xbf, 0x44, 0x6b, 0x59, 0xd2, + 0xa1, 0x09, 0xed, 0x44, 0xa7, 0x30, 0x8c, 0x38, 0x49, 0x84, 0xb7, 0xa0, 0xeb, 0x5c, 0x75, 0x75, + 0x5a, 0x01, 0xc3, 0x15, 0xeb, 0xe8, 0x04, 0x7d, 0x89, 0xd6, 0x40, 0x76, 0x49, 0x5f, 0x76, 0xc7, + 0xa1, 0x8b, 0xd7, 0x84, 0x5a, 0x47, 0xfb, 0x5d, 0xfe, 0x35, 0x8f, 0xd0, 0x81, 0x76, 0xd1, 0x3a, + 0x3f, 0x42, 0xc5, 0x4c, 0x32, 0x41, 0x3a, 0x10, 0x71, 0x22, 0xbb, 0xb6, 0x47, 0x05, 0x6b, 0x6b, + 0x11, 0xd9, 0xc5, 0xf7, 0xd0, 0x32, 0xaf, 0xf1, 0x88, 0x33, 0x61, 0x1a, 0xb6, 0x10, 0x2e, 0xf1, + 0x1a, 0x6f, 0x31, 0x21, 0xf1, 0x13, 0xb4, 0xaa, 0x96, 0xe0, 0x5c, 0x82, 0xa0, 0x24, 0x8d, 0x12, + 0x6e, 0xe5, 0x29, 0xf1, 0x1a, 0x6f, 0x58, 0xeb, 0x11, 0xc7, 0xdf, 0xa0, 0x6d, 0xe5, 0xd7, 0x66, + 0x94, 0x42, 0x5b, 0xcb, 0x29, 0x93, 0x1e, 0xb0, 0xbe, 0xd4, 0xb2, 0x14, 0x6a, 0xf7, 0x2a, 0x66, + 0x97, 0x56, 0xdc, 0x2e, 0xad, 0x1c, 0xda, 0x5d, 0x1c, 0x6e, 0xf2, 0x1a, 0x3f, 0xb8, 0x88, 0xfb, + 0x60, 0xc2, 0x94, 0xb8, 0xea, 0xb0, 0x00, 0x61, 0xd2, 0x5a, 0xd0, 0x69, 0x21, 0x63, 0xd2, 0x99, + 0xfd, 0x0b, 0xad, 0x58, 0x07, 0x37, 0xcc, 0x8b, 0x26, 0x31, 0x63, 0xad, 0xdb, 0x91, 0x7e, 0x88, + 0x0a, 0xb4, 0xdf, 0x8b, 0xce, 0x98, 0x38, 0x05, 0x91, 0x79, 0x4b, 0x06, 0x87, 0xf6, 0x7b, 0x9f, + 0x8c, 0x05, 0xef, 0xa3, 0x0d, 0xb3, 0x18, 0x9d, 0x91, 0x44, 0xea, 0xb4, 0xa3, 0x5e, 0xe6, 0x2d, + 0x6b, 0xc7, 0x35, 0xb3, 0xf4, 0x89, 0x24, 0x52, 0x25, 0xf6, 0x36, 0xc3, 0x01, 0x2a, 0xaa, 0xe1, + 0xa3, 0x2c, 0x86, 0xa8, 0x2f, 0x52, 0x2f, 0x6f, 0xba, 0x0e, 0xb2, 0xfb, 0x8e, 0xc5, 0xf0, 0x51, + 0xa4, 0xf8, 0x7b, 0xf4, 0x40, 0x79, 0xb4, 0x19, 0x95, 0x70, 0x2e, 0x23, 0x01, 0x24, 0x1e, 0x43, + 0x2b, 0x45, 0xd0, 0x6d, 0x8a, 0xdc, 0x03, 0xd9, 0x3d, 0x30, 0xe1, 0x21, 0x90, 0xd8, 0xb1, 0x2b, + 0x59, 0x42, 0x33, 0xfb, 0x0e, 0xfc, 0x12, 0x6e, 0xe1, 0x36, 0xdc, 0xad, 0x31, 0xee, 0x24, 0x66, + 0x13, 0x61, 0x85, 0x99, 0x50, 0x09, 0x62, 0x40, 0xd2, 0x48, 0x80, 0x14, 0x43, 0xaf, 0x78, 0x1b, + 0x9a, 0x1a, 0xd0, 0x23, 0x1b, 0x13, 0xaa, 0x10, 0x35, 0x2c, 0x0a, 0xa8, 0x47, 0xce, 0x35, 0x46, + 0x02, 0x99, 0x57, 0x0a, 0x72, 0x7b, 0xa5, 0xb0, 0x04, 0xb2, 0xfb, 0x96, 0x9c, 0x87, 0xc6, 0x88, + 0xcb, 0x48, 0x19, 0xa2, 0x0e, 0xc9, 0x22, 0x2e, 0x92, 0x36, 0x78, 0x2b, 0x41, 0x6e, 0xef, 0x4e, + 0xa8, 0xce, 0x83, 0x26, 0xc9, 0x5a, 0xca, 0x34, 0xe9, 0x93, 0x26, 0xbd, 0x44, 0x7a, 0xab, 0x93, + 0x3e, 0xff, 0x57, 0x26, 0xc5, 0x27, 0xcf, 0x23, 0xce, 0x58, 0x1a, 0x01, 0x25, 0xc7, 0x29, 0xc4, + 0xde, 0x5a, 0x90, 0xdb, 0x5b, 0x0e, 0x4b, 0xf2, 0xbc, 0xc5, 0x58, 0xda, 0x30, 0x46, 0x75, 0xe0, + 0x51, 0x90, 0xaa, 0x95, 0xde, 0xba, 0x39, 0xf0, 0xec, 0x27, 0xfe, 0x37, 0x5a, 0x3d, 0x66, 0x4c, + 0x66, 0x52, 0x10, 0x1e, 0x71, 0x50, 0x13, 0x82, 0x83, 0xf9, 0xbd, 0x7c, 0xb8, 0x72, 0x61, 0x6e, + 0x29, 0x2b, 0x7e, 0x80, 0x90, 0x8d, 0x51, 0x5b, 0x7d, 0x43, 0x57, 0x95, 0xb7, 0x96, 0xa3, 0x18, + 0x3f, 0x47, 0xa5, 0x1e, 0x49, 0x68, 0xe4, 0x36, 0xbf, 0xb7, 0x79, 0xed, 0xb1, 0x5c, 0x54, 0x8e, + 0x47, 0xd6, 0x0f, 0x77, 0x91, 0x97, 0xf5, 0x88, 0x90, 0xba, 0xa3, 0x82, 0xb4, 0xa5, 0x9b, 0x66, + 0xc8, 0xbc, 0x2d, 0x7d, 0x73, 0x54, 0x1c, 0xc6, 0x78, 0x4f, 0x57, 0xde, 0xab, 0x90, 0x03, 0x1b, + 0x51, 0x77, 0x01, 0x0d, 0x2a, 0xc5, 0x30, 0xdc, 0xce, 0x66, 0x2e, 0xe2, 0xc7, 0xa8, 0xc4, 0xb9, + 0x60, 0x27, 0x17, 0x52, 0x6d, 0x6b, 0xa9, 0x8a, 0xda, 0x68, 0x95, 0xf2, 0x8f, 0xd0, 0xfd, 0x1b, + 0xb0, 0xdd, 0xfd, 0x90, 0x1b, 0xdf, 0x0f, 0x9b, 0x68, 0x61, 0x40, 0xd2, 0xbe, 0x3b, 0x78, 0xcd, + 0xc7, 0xab, 0xb9, 0x17, 0xb9, 0xda, 0x1f, 0x79, 0x54, 0x32, 0x29, 0xbf, 0x37, 0x97, 0x3e, 0x26, + 0x28, 0xdf, 0x04, 0x69, 0x6c, 0x78, 0x7b, 0x6a, 0xb0, 0x1a, 0xea, 0xda, 0xf6, 0xf1, 0x74, 0xb9, + 0xe5, 0xbd, 0x51, 0x7d, 0xdd, 0x5f, 0x6d, 0x82, 0x0c, 0xd4, 0x1e, 0x0b, 0xcc, 0xca, 0x97, 0x3f, + 0xff, 0xfa, 0x6d, 0x6e, 0x05, 0x17, 0xab, 0xf6, 0x69, 0xa1, 0x76, 0x24, 0xee, 0x6b, 0x0a, 0xa3, + 0x36, 0xf6, 0x1c, 0xd4, 0xd5, 0x3b, 0xdd, 0x9f, 0xd1, 0x97, 0xf2, 0xab, 0x51, 0x7d, 0xc3, 0x5f, + 0x57, 0x24, 0xc6, 0x38, 0x49, 0xb3, 0x8b, 0x77, 0x1c, 0x8d, 0xd4, 0x8b, 0x59, 0xf5, 0xa7, 0xf1, + 0x5d, 0xfc, 0x33, 0x1e, 0xa2, 0xd2, 0xe4, 0x1b, 0x20, 0xbb, 0xb6, 0xba, 0x9d, 0x89, 0x94, 0xa6, + 0x9e, 0x0c, 0xe5, 0xda, 0xa8, 0xee, 0xf9, 0xdb, 0x2a, 0x85, 0x7a, 0x9a, 0x5e, 0x4e, 0x23, 0xd3, + 0x79, 0xac, 0xe3, 0xd5, 0x2b, 0x79, 0xe0, 0x14, 0x15, 0x0f, 0x04, 0x10, 0x09, 0x56, 0xd7, 0x19, + 0xfa, 0xcd, 0xd4, 0xf4, 0xbf, 0xa3, 0xba, 0xef, 0x7b, 0x26, 0x34, 0x0b, 0x94, 0x78, 0x81, 0x71, + 0x0a, 0xd4, 0xb3, 0xc1, 0xb0, 0x95, 0x2f, 0x89, 0xfb, 0x2a, 0xf7, 0x14, 0x7f, 0x76, 0x6c, 0x56, + 0xe2, 0x19, 0x42, 0xce, 0x14, 0xf7, 0xe5, 0xa8, 0xbe, 0xe3, 0xfb, 0x8e, 0xcd, 0xe4, 0x3e, 0xc5, + 0xb7, 0x59, 0xbe, 0x5a, 0x9d, 0xa2, 0xfc, 0x3d, 0x87, 0x56, 0x9a, 0x40, 0x41, 0x8c, 0x59, 0x6f, + 0x9d, 0x9d, 0x09, 0xe6, 0x1f, 0x47, 0xf5, 0xa6, 0xdf, 0x70, 0x00, 0xb3, 0xb8, 0x03, 0x49, 0x4e, + 0x13, 0xda, 0x09, 0xec, 0x7b, 0x22, 0x0b, 0x8e, 0x49, 0x06, 0x71, 0xc0, 0x68, 0x20, 0xbb, 0x10, + 0xa8, 0xdd, 0x6a, 0x83, 0x74, 0x92, 0x7e, 0xd9, 0xbb, 0x3a, 0x0a, 0x1d, 0x0b, 0x8e, 0x3b, 0xa8, + 0x68, 0x9e, 0x72, 0x5f, 0xd9, 0x8b, 0xea, 0xa8, 0xbe, 0xe5, 0xdb, 0x57, 0xe0, 0xa5, 0x5e, 0x98, + 0x36, 0xf8, 0x53, 0x6d, 0xf8, 0x92, 0x73, 0x4c, 0x56, 0x91, 0xfb, 0x0e, 0x75, 0xc6, 0x53, 0x72, + 0xa6, 0x2c, 0xf5, 0x51, 0xfd, 0xae, 0xbf, 0xe5, 0x28, 0x2f, 0x89, 0xa2, 0x49, 0x1f, 0xf9, 0x37, + 0x4e, 0xbc, 0x4a, 0x22, 0x45, 0xc5, 0x43, 0x48, 0xe1, 0xa2, 0xda, 0xeb, 0xba, 0x72, 0x8d, 0xbd, + 0xfc, 0x4c, 0x57, 0x6d, 0x20, 0xa6, 0xab, 0x5e, 0x79, 0x7a, 0x79, 0x67, 0xff, 0x92, 0x73, 0x74, + 0xb7, 0xee, 0xee, 0xeb, 0x08, 0x5f, 0xeb, 0x9a, 0x1d, 0xe1, 0x74, 0xcd, 0xbb, 0x4f, 0x6f, 0xac, + 0xf9, 0xcd, 0x13, 0x84, 0xda, 0xac, 0x67, 0x69, 0xdf, 0x14, 0xed, 0xb1, 0xd6, 0x52, 0x24, 0xad, + 0xdc, 0x77, 0xcb, 0xc6, 0xce, 0x8f, 0x8f, 0x17, 0x35, 0xef, 0x7f, 0xfe, 0x09, 0x00, 0x00, 0xff, + 0xff, 0xab, 0xbc, 0x5e, 0x33, 0xf5, 0x0c, 0x00, 0x00, } diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go index 1f2c8d225..66f81783e 100644 --- a/protobufs/gen/go/config/service.pb.gw.go +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -100,6 +100,15 @@ func request_ConfigService_CreateTenant_0(ctx context.Context, marshaler runtime } +func request_ConfigService_GenerateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GenerateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + func request_ConfigService_UpdateConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ConfigData var metadata runtime.ServerMetadata @@ -363,6 +372,35 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) + mux.Handle("POST", pattern_ConfigService_GenerateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ConfigService_GenerateTenant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ConfigService_GenerateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("PUT", pattern_ConfigService_UpdateConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -493,6 +531,8 @@ var ( pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) + pattern_ConfigService_GenerateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"config", "tenants", "generate"}, "")) + pattern_ConfigService_UpdateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) @@ -513,6 +553,8 @@ var ( forward_ConfigService_CreateTenant_0 = runtime.ForwardResponseMessage + forward_ConfigService_GenerateTenant_0 = runtime.ForwardResponseMessage + forward_ConfigService_UpdateConfig_0 = runtime.ForwardResponseMessage forward_ConfigService_UpdateTenant_0 = runtime.ForwardResponseMessage diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 0da34343c..22c0ef890 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 6e9404f26..b3d4e504b 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -139,6 +139,23 @@ ] } }, + "/config/tenants/generate": { + "post": { + "description": "Generates tenant config data taking defaults based on the main tenant", + "operationId": "GenerateTenant", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/configTenantData" + } + } + }, + "tags": [ + "ConfigService" + ] + } + }, "/config/tenants/{identifier}": { "get": { "description": "Get Tenant Config", diff --git a/resources/data.go b/resources/data.go index ab66c7b4b..707878d59 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xb9\x71\x5c\xd9\x96\xe3\x1b\xbf\x34\x20\x70\x28\x22\xa6\x00\x06\x00\xb5\xe4\xd7\x77\x00\x52\x8e\x1d\x2f\xb7\xcb\x34\x2f\xa6\x00\x9c\xfd\x3b\x1f\x0e\x72\x00\x27\x58\x91\xae\x31\xc0\x70\x8d\x8d\x6c\x57\x28\x0c\x18\xd4\x46\xa0\x01\xb2\x24\x5c\x68\x03\x8a\x8b\x7b\x2c\x77\x23\x8a\xc2\x28\x5e\x75\x4b\xbc\x40\xb3\x91\xea\x7e\x0a\xaa\xd3\x9a\x13\x51\xf3\xa6\x19\x39\x65\x5c\x20\x98\x1a\x81\x0d\x7a\x45\x7f\x52\x83\xa9\x89\x81\xe3\x07\x0d\xb0\x22\x5c\x18\xab\x7f\xb4\x3f\x32\x1d\x01\x1c\xc0\xb9\xa4\xa4\x71\x2e\x70\xb1\x04\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x89\xa0\xd1\xc0\x86\x9b\x1a\x50\xac\x61\x4d\x14\x27\x65\x83\x7a\x32\x82\xbd\xbc\x55\x09\xc0\xd9\x14\xa2\x28\x72\xdf\x68\x6a\x54\xd8\xad\x86\x08\x3e\xb0\x29\xe4\x51\xde\xef\x95\x52\x1a\x6d\x14\x69\xe7\x88\x4a\xf7\xb2\x1e\x8c\x0f\x79\x1b\x1f\x06\x61\x36\xf1\x27\xfe\x24\x38\x34\xb4\x3d\x8c\xf2\xd0\x0f\x0f\x79\x5b\xe9\xc3\xcb\xd5\xe2\x72\x5b\x6e\xee\xbb\xbb\x2f\x5f\x4e\xaa\xee\xc7\xa2\xdc\x9e\xce\xae\x70\x71\x71\x7c\x2e\x7f\xec\x76\x49\x92\xaf\x2f\xc5\xf2\xf3\x7a\xfe\xe9\xdb\xf9\x97\xfb\xf1\x9f\x28\x8d\xf6\x4a\x3f\x57\xe9\xe9\x45\xba\xba\xff\x7e\x8b\xdf\x6e\x3f\xde\x86\xdf\xe7\x5d\x90\xfe\xd1\xb2\x77\xd1\xfd\xef\x32\x58\x44\xab\x9a\xd4\xf3\xa3\xe4\x1a\x13\x11\xf4\x4a\xf7\xa9\x9a\xed\x33\xd5\x07\x60\xc3\x47\x61\xb8\xd9\x9d\x11\x6a\xa4\xda\x4d\x61\x3c\xfe\x65\xe7\x0a\x97\x5c\x9b\x27\x5b\x44\xd0\x5a\xaa\x2b\x6c\xa5\xe6\xbf\x48\xb5\x64\x67\x61\xf2\x8f\xb2\xe1\x4b\x62\xb8\x14\x6e\xcf\x15\xef\x13\xe1\xe2\x45\x28\x0d\x35\x1e\xc1\x63\xc4\xf4\x0e\x1e\xc0\x45\xb7\x42\xc5\x29\x7c\x38\x01\x59\x39\xf4\x3c\xc2\xc9\x4f\xc9\xbe\x90\x49\x30\x48\x1d\xed\xab\x05\x0d\xd7\xc6\x4a\x0a\xc9\xf0\x39\xd0\x5a\x25\xd7\xdc\x6d\x48\xa7\xfb\x91\x03\x7b\xf7\xfe\xb4\xfa\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x45\x40\x10\x9e\x44\x1f\xa5\xbc\x3d\xe7\x9c\x5e\x7e\xde\x2c\xea\xc5\xd1\x97\x74\xfb\x91\xce\xe5\x79\x95\x5e\x5d\x7e\xf9\xfd\xac\xdd\x54\x81\xca\x92\xcd\xf9\x36\xbc\xbb\x8a\xda\x63\x16\x8c\x5f\x52\x9f\xa7\x93\x30\xf0\x5f\x53\x7f\x79\xf7\x69\x96\xbf\x9b\xbf\x57\xeb\xd3\xbb\xa3\x62\xc3\xee\xe5\x0d\x9d\xcd\x56\xc7\x77\xef\xdb\x02\x77\xbb\xbb\xf8\xfa\x34\x5f\x9e\xa9\xa8\x5e\x5c\xfc\x31\x1e\x72\x74\x3a\xa0\x7d\x9f\x45\x9b\x62\x0f\xae\x86\x7e\x7e\xa5\x1f\xe2\x41\xf8\x9c\xd8\xf4\x00\xc3\xb6\x91\x3b\x64\x70\xbd\x22\xca\xc0\xf1\x00\x33\x0d\x95\x54\x2e\xa1\x4b\xbe\x46\xf1\x24\x95\xcf\xa1\x08\xaf\x62\xd1\xdf\x16\x3e\x0b\x8b\x38\xc9\x02\xcc\xa2\x3c\x0e\xd3\x22\x23\x69\x5a\x66\xa4\x28\x88\x5f\x30\x96\xd2\x2c\x62\x51\x92\xb2\x37\x50\xeb\x6f\x8b\x34\xf5\xa9\x1f\x15\x2c\x0a\x82\x38\x89\x48\xe5\xb3\x24\xa7\x49\x9a\xa6\x59\x18\xb1\x82\x86\x15\xc9\x58\x8a\xf4\x0d\x7c\xfb\xdb\xac\xca\x93\x98\x55\xa4\xc8\xfd\x20\x64\x59\x45\x92\x84\xe6\x7e\x54\x96\x24\x0c\x53\xbf\xa4\x0c\x31\x2e\x13\x64\x6f\x75\x82\xbf\x65\xa5\x9f\xe4\xc1\xac\x88\xc2\x3c\x4d\xe3\x3c\x49\xa2\x30\x9f\xb1\x93\xd2\x3f\x0d\x93\x20\xc8\xe3\x34\xf6\xab\x02\x93\x13\xd7\x33\x25\x2a\x41\x9a\x1a\xf9\xb2\x36\x03\xe8\x0e\x0e\x0e\x86\x0a\x7c\x94\x6b\x22\xe0\x6c\x76\x39\xfc\xf6\xe0\xd6\xb2\x1d\x17\x55\xa7\x08\xec\x64\x07\x4b\x4b\xd3\x02\x50\x29\xa9\x2c\x9c\x16\x35\xd7\xa0\xf0\x7b\x67\x2b\xc7\x35\x08\x69\x40\x77\x6d\x2b\x95\x41\x06\x25\x52\xd2\x69\xb4\x92\xca\x75\x8b\x3d\xa2\x3a\x21\x2c\xd5\x3a\x22\xd5\x86\x18\xdb\x32\x9d\x5d\x9a\xc0\x55\x27\xfa\x75\xcf\x1b\xd6\x7e\x23\x8a\xd6\x7c\x8d\x93\xf1\xdf\x06\xa7\x00\x36\xb6\xe3\x8c\x04\x26\xff\xee\x24\x08\x34\x8e\xc4\x5b\xa2\xb8\xd9\xf5\x86\x9c\x96\x7b\x17\x0f\x2e\xa7\xfd\xcf\xaf\xc3\x01\xcf\xa3\x35\xe1\xe2\xb7\x7e\xdb\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xda\xe1\x8f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x24\xbd\xd7\xfd\x9a\x46\xb5\x46\xaf\xb1\x49\x05\xcf\x5b\x91\xad\xd7\xda\xa6\x86\x30\xb1\x42\x5a\x90\x56\xd7\xd2\x0c\x8b\x6e\x6d\xc5\xc5\x93\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x05\xb3\x4d\x91\xac\xaa\xe7\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb5\xe7\xa5\x00\xad\x99\x0d\x89\xd0\x1a\x3d\xcd\x7f\x20\xc4\x7e\x91\x82\xe7\x7d\xd3\x52\xa8\x96\x7a\xb5\xd4\x46\x03\x69\x9a\x47\x6b\x5c\x18\x54\x15\xa1\x68\xd7\xbf\x3e\x2d\xf7\xf3\x64\xbe\x54\xf9\x23\x1b\x3e\x32\xdb\x7b\x02\x7b\x47\x8c\x84\x5b\x2c\xaf\xed\xba\xd1\xe0\x72\xa2\xa0\x52\x72\x05\x9d\x30\xaa\xd3\x16\x12\x52\xf1\x25\x17\x53\x98\x4c\xc6\xaf\xd6\xd3\x36\xf9\xb3\x5a\x7e\xf5\xbc\x4e\x68\x52\xa1\x87\xdb\x56\x6a\xfc\x0a\x55\x43\x96\xbf\x00\xf8\x3f\x63\xf6\xf0\x7f\x64\xf6\x27\xbd\xf4\x6f\x73\x7b\xe0\xc7\x93\x20\x89\x27\x41\x3e\x49\x9e\xdd\xee\x7b\xf2\x9d\xeb\x94\x13\xbc\xe9\xce\xee\x2e\xba\xe0\xdd\x76\xad\x77\x47\x8b\x6b\xb5\xd0\xc5\xda\x1c\xa5\xa5\xf9\x34\x13\xef\xcf\xe4\xf9\xb7\xf2\xfe\xc7\x31\x19\xbf\xa0\x3e\x99\x04\x79\x32\x09\xa3\xec\x55\x03\xc7\xef\xe8\x86\x2f\xbe\xc9\x8f\xb7\xef\xab\x23\x12\xe7\xe1\xcd\xdc\x10\xbc\xd9\x5e\x9c\x6f\x58\xfe\xa3\x14\x47\xc1\x75\xb6\xc1\xd9\xdd\xcd\xf6\xee\x6d\x76\x77\xa4\xf1\x2a\xb7\x87\xff\x07\x72\x7f\x83\xdb\xf3\xa4\x8c\xc2\x2a\x23\x51\x15\xfb\x71\x1e\x54\x41\x18\x45\xb1\x1f\x07\x69\xe6\xd3\x9c\x96\xe8\x67\x55\xc6\xb2\x82\xbe\xc9\xed\x49\x4c\x30\xca\xa2\xca\x2f\xd2\x8a\x54\x21\x2b\xd3\x32\x27\x71\x9a\x05\x19\xf5\xcb\x22\x47\x5a\x11\x3f\x4b\x18\x7b\x93\xdb\xe3\x38\xae\xd2\xb8\xc0\xc8\xcf\xe2\x38\xc4\x2c\xa5\xb4\xca\xa2\x2c\x4e\x53\x4c\xc2\x2a\x48\xfd\xa2\x2c\xf2\x30\xf5\xdf\xe6\x76\x3f\x0e\x32\x2c\xa3\xac\x88\x83\x20\x8d\xa3\x34\x8f\xfd\xe0\x24\x4d\xd3\x22\x8f\xe9\xe9\x49\x96\x16\xf1\xec\x88\x1e\x95\xc1\x78\x64\xc7\x61\x62\x08\x5c\x1b\xa9\xc8\x12\x47\xba\xff\xdb\x0f\xb9\x73\x62\x6a\x97\xe2\xc6\xce\x4a\x27\x47\x50\xf1\x06\x47\xd6\xa8\xa9\xa7\x70\x68\x56\xed\xe1\xcf\x61\xfb\x9f\x8c\x18\x32\x71\x27\x59\x69\xf5\x1e\x4b\x51\xf1\x65\xa7\x9c\x5b\x0f\x06\xa8\x5b\xbd\xfe\xef\xcd\xf4\x0a\x9e\x59\xfb\xf0\x40\x4d\x1b\x0b\x27\x87\x8a\xd9\xfc\x03\x10\xc1\x60\x1e\xce\xe1\xba\xe7\x15\xdb\xaa\x28\x6c\x2f\x8e\x6c\xb7\xbe\x97\xda\x08\xb2\xc2\x29\xf8\x6e\xc4\xf5\x47\x07\x30\x97\xca\x0c\x4a\xac\x82\x97\x05\xed\xa1\x29\xe4\x7e\x1e\x5a\xe3\xb6\x5f\x3d\x23\x1d\x35\x03\x7d\x1c\xb7\x1e\xb5\x61\xdb\x87\x79\xdd\x22\xe5\xd5\x0e\x4e\xb7\xc6\x31\x00\x7c\x98\x3f\xf2\xd5\x51\x16\x25\xc2\x3e\x18\x14\x5a\x56\x66\x40\x0c\xf0\x0a\x4a\xac\xb9\x60\x70\x31\x5b\x58\x35\x38\x48\x7f\x98\x4f\x61\x33\xd9\x4e\x76\x93\x1f\x7d\x12\xad\xd7\x9d\x46\xf6\xd0\x13\x36\xea\x86\xec\x50\xd9\x54\x3a\x77\x5d\x43\xbb\xd3\x0b\xbe\x42\xd9\xb9\x30\x05\xc8\x16\xc5\xf0\x8a\x19\x38\xd9\x71\x95\xbb\x67\x46\xb0\x5f\x1e\x44\xa6\x30\x8e\x7c\xed\x80\x73\xd9\x61\x87\xbf\x84\xeb\xac\x13\xbd\x13\xb4\x56\x52\xc8\x4e\x5b\xfa\xa3\xa8\x35\x17\xcb\xd1\x77\x2b\xd0\x27\xa3\x7f\x83\xe9\x3e\xf4\x6e\x55\xa2\xb2\x04\x6a\xfb\x1f\x95\x3e\xa4\x52\x68\xcb\xc9\x03\x99\x6e\xec\x10\x5c\xba\x4b\x47\x52\x62\xfa\xcc\x68\x43\x94\xe9\xda\x11\x58\xf9\xdb\x5e\x70\x0a\x7d\x78\x67\x0a\x51\x43\xd7\xc2\xf1\xfc\x06\xe8\x8e\x36\xa8\xfb\x50\x7b\x03\x76\x9e\xd8\x10\xee\x9e\x6e\xd6\x5f\x5c\xa3\x30\x36\xd4\x7e\xfb\x96\x70\x17\xed\xa7\xeb\x29\x04\x36\xd0\x07\x06\xd3\xae\x84\x9c\x3e\x0d\x7a\xb4\x67\xb0\xa1\xce\xd8\xa0\xe5\xa6\x4d\xcd\x69\xfd\xc0\x6e\x40\x28\x95\x9d\x70\x37\x96\x1d\x6e\x86\x8b\x46\xda\x24\x0c\x37\x04\x03\xde\xdf\x62\xb4\xd3\x46\xae\x06\x23\xfb\x6e\x18\x9e\xaa\xb3\x5e\xcd\x85\x03\xed\xd8\x3e\x4f\xc7\x0f\x0f\x52\xd7\x68\x83\xe2\x07\xbb\xb4\xb1\x73\x47\x8f\xaf\xbf\x6c\xd0\x8d\x5d\x5c\x21\x6c\x34\x48\x05\xbc\xa5\xc3\x2b\xd5\x3e\x4a\xed\x27\x25\xc6\xba\xed\x52\xf2\x57\x9b\x5d\xc9\xf0\xe6\xea\x7c\x0a\xb5\x31\xed\xf4\xf0\xd0\xdd\xf3\x76\x38\x98\x16\x49\x9c\xec\x8b\xe9\x5e\xd1\x4b\x62\x63\xe1\xd4\xba\xbb\x24\x7a\x6e\x3f\xa7\x10\xf8\xfb\x7f\xcf\x0e\x37\x7c\xc5\x4d\x7f\xf8\xdc\x7e\x4e\x21\xce\x82\x30\xca\xf3\x27\x20\x35\xd2\x55\xab\x87\x96\xf8\x19\x99\x51\x44\x68\xf2\x30\x44\xd8\x18\x18\xeb\x5f\xdd\x04\xdc\x9c\xe5\xba\xbf\x0f\x05\x8c\xe2\xcb\x25\x2a\x64\x3d\xa4\x0d\x6e\xcd\xbe\xd0\x3d\xac\x53\xdf\xe2\xfa\x35\xc3\x0a\x09\x03\x29\x9a\x9d\x6d\x97\x3d\xd8\xf7\xff\xf5\xb0\x77\xe9\xa7\xea\x2b\x24\xec\xa9\xfa\x20\x19\xb4\x5f\xd8\x4a\x3c\xf6\xbd\x95\xb2\x81\x15\xd9\x82\x42\xa3\x78\x3f\x28\x68\x14\x0c\xc8\x93\x63\x72\xed\x5a\x79\x45\xb6\x57\xfd\xb9\x29\x84\x43\x4e\x5f\x56\xe9\xa6\xb5\x35\x69\x9c\xde\x5d\xdf\x00\xc4\x3a\x48\x3b\xa5\xdc\xb3\xf7\x91\x44\x4d\x34\x94\x88\xf6\x5d\x6c\x90\x1a\x97\xa6\xbd\x02\x6b\xcf\x5e\x4f\xe1\x10\xc1\x09\xd7\x0e\x2d\x4e\xa3\x96\xab\x67\x68\xd3\xc0\xe4\xe3\xa1\x1e\xcc\xd6\x79\x44\x5a\x3e\x02\x30\xdb\xb9\x94\xcd\x8c\x5a\x5a\x38\x15\x56\x13\x9b\x82\x51\x1d\xda\x5e\x23\x62\x07\x0c\xcb\x6e\xb9\x1c\x28\xc9\xb6\x80\x23\x80\xa5\x04\x6b\x64\xe4\x76\xfb\x56\x6b\x5b\x25\x2b\x57\x9e\x07\x11\x4b\x76\x76\x75\x0a\x15\x69\x34\x8e\xfe\x15\x00\x00\xff\xff\x54\x43\x46\xfe\x3c\x12\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x49\x73\xdb\x3a\x12\xbe\xeb\x57\x74\xc9\x97\x99\xaa\xa1\xcc\x7d\x51\xd5\xab\x29\x79\x4b\xf2\xe2\x78\x64\x5b\x8e\x5f\x7c\x99\x80\x40\x53\x44\x4c\x01\x0c\x00\x6a\xc9\xaf\x9f\x02\x48\x39\x76\xbc\xbc\x59\x6a\x72\x31\x05\xa0\x1b\xbd\x7c\xfd\xa1\x3b\x07\x70\x82\x15\xe9\x1a\x03\x0c\xd7\xd8\xc8\x76\x85\xc2\x80\x41\x6d\x04\x1a\x20\x4b\xc2\x85\x36\xa0\xb8\xb8\xc7\x72\x37\xa2\x28\x8c\xe2\x55\xb7\xc4\x0b\x34\x1b\xa9\xee\xa7\xa0\x3a\xad\x39\x11\x35\x6f\x9a\x91\x53\xc6\x05\x82\xa9\x11\xd8\xa0\x57\xf4\x27\x35\x98\x9a\x18\x38\x7e\xd0\x00\x2b\xc2\x85\xb1\xfa\x47\xfb\x23\xd3\x11\xc0\x01\x9c\x4b\x4a\x1a\x67\x02\x17\x4b\xa0\x52\x18\x45\xa8\x01\xc2\x98\x42\xad\x51\x83\x40\x64\x60\x24\x94\x08\x1a\x0d\x6c\xb8\xa9\x01\xc5\x1a\xd6\x44\x71\x52\x36\xa8\x27\x23\xd8\xcb\x5b\x95\x00\x9c\x4d\x21\x8a\x22\xf7\x8d\xa6\x46\x85\xdd\x6a\xf0\xe0\x03\x9b\x42\x1e\xe5\xfd\x5e\x29\xa5\xd1\x46\x91\x76\x8e\xa8\x74\x2f\xeb\xc1\xf8\x90\xb7\xf1\x61\x10\x66\x13\x7f\xe2\x4f\x82\x43\x43\xdb\xc3\x28\x0f\xfd\xf0\x90\xb7\x95\x3e\xbc\x5c\x2d\x2e\xb7\xe5\xe6\xbe\xbb\xfb\xf2\xe5\xa4\xea\x7e\x2c\xca\xed\xe9\xec\x0a\x17\x17\xc7\xe7\xf2\xc7\x6e\x97\x24\xf9\xfa\x52\x2c\x3f\xaf\xe7\x9f\xbe\x9d\x7f\xb9\x1f\xff\x89\xd2\x68\xaf\xf4\x73\x95\x9e\x5e\xa4\xab\xfb\xef\xb7\xf8\xed\xf6\xe3\x6d\xf8\x7d\xde\x05\xe9\x1f\x2d\x7b\x17\xdd\xff\x2e\x83\x45\xb4\xaa\x49\x3d\x3f\x4a\xae\x31\x11\x41\xaf\x74\x1f\xaa\xd9\x3e\x52\xbd\x03\xd6\x7d\x14\x86\x9b\xdd\x19\xa1\x46\xaa\xdd\x14\xc6\xe3\x5f\x76\xae\x70\xc9\xb5\x79\xb2\x45\x04\xad\xa5\xba\xc2\x56\x6a\xfe\x8b\x54\x4b\x76\x16\x26\xff\x28\x1b\xbe\x24\x86\x4b\xe1\xf6\x5c\xf2\x3e\x11\x2e\x5e\x84\xd2\x90\xe3\x11\x3c\x46\x4c\x6f\xe0\x01\x5c\x74\x2b\x54\x9c\xc2\x87\x13\x90\x95\x43\xcf\x23\x9c\xfc\x94\xec\x13\x99\x04\x83\xd4\xd1\x3e\x5b\xd0\x70\x6d\xac\xa4\x90\x0c\x9f\x03\xad\x55\x72\xcd\xdd\x86\x74\xba\x1f\x19\xb0\x37\xef\x4f\xb3\x1f\x25\x93\x30\x4c\x26\xa1\xef\x4f\xe2\xf0\x57\x04\x04\xe1\x49\xf4\x51\xca\xdb\x73\xce\xe9\xe5\xe7\xcd\xa2\x5e\x1c\x7d\x49\xb7\x1f\xe9\x5c\x9e\x57\xe9\xd5\xe5\x97\xdf\xcf\xda\x4d\x15\xa8\x2c\xd9\x9c\x6f\xc3\xbb\xab\xa8\x3d\x66\xc1\xf8\x25\xf5\x79\x3a\x09\x03\xff\x35\xf5\x97\x77\x9f\x66\xf9\xbb\xf9\x7b\xb5\x3e\xbd\x3b\x2a\x36\xec\x5e\xde\xd0\xd9\x6c\x75\x7c\xf7\xbe\x2d\x70\xb7\xbb\x8b\xaf\x4f\xf3\xe5\x99\x8a\xea\xc5\xc5\x1f\xe3\x21\x46\xa7\x03\xda\xf7\x51\xb4\x21\xf6\xe0\x6a\xa8\xe7\x57\xea\x21\x1e\x84\xcf\x89\x0d\x0f\x30\x6c\x1b\xb9\x43\x06\xd7\x2b\xa2\x0c\x1c\x0f\x30\xd3\x50\x49\xe5\x02\xba\xe4\x6b\x14\x4f\x42\xf9\x1c\x8a\xf0\x2a\x16\xfd\x6d\xe1\xb3\xb0\x88\x93\x2c\xc0\x2c\xca\xe3\x30\x2d\x32\x92\xa6\x65\x46\x8a\x82\xf8\x05\x63\x29\xcd\x22\x16\x25\x29\x7b\x03\xb5\xfe\xb6\x48\x53\x9f\xfa\x51\xc1\xa2\x20\x88\x93\x88\x54\x3e\x4b\x72\x9a\xa4\x69\x9a\x85\x11\x2b\x68\x58\x91\x8c\xa5\x48\xdf\xc0\xb7\xbf\xcd\xaa\x3c\x89\x59\x45\x8a\xdc\x0f\x42\x96\x55\x24\x49\x68\xee\x47\x65\x49\xc2\x30\xf5\x4b\xca\x10\xe3\x32\x41\xf6\x56\x25\xf8\x5b\x56\xfa\x49\x1e\xcc\x8a\x28\xcc\xd3\x34\xce\x93\x24\x0a\xf3\x19\x3b\x29\xfd\xd3\x30\x09\x82\x3c\x4e\x63\xbf\x2a\x30\x39\x71\x35\x53\xa2\x12\xa4\xa9\x91\x2f\x6b\x33\x80\xee\xe0\xe0\x60\xc8\xc0\x47\xb9\x26\x02\xce\x66\x97\xc3\x6f\x0f\x6e\x2d\xdb\x71\x51\x75\x8a\xc0\x4e\x76\xb0\xb4\x34\x2d\x00\x95\x92\xca\xc2\x69\x51\x73\x0d\x0a\xbf\x77\x36\x73\x5c\x83\x90\x06\x74\xd7\xb6\x52\x19\x64\x50\x22\x25\x9d\x46\x2b\xa9\x5c\xb5\xd8\x23\xaa\x13\xc2\x52\xad\x23\x52\x6d\x88\xb1\x25\xd3\xd9\xa5\x09\x5c\x75\xa2\x5f\xf7\xbc\x61\xed\x37\xa2\x68\xcd\xd7\x38\x19\xff\x6d\x30\x0a\x60\x63\x2b\xce\x48\x60\xf2\xef\x4e\x82\x40\xe3\x48\xbc\x25\x8a\x9b\x5d\x7f\x91\xd3\x72\xef\xfc\xc1\xe5\xb4\xff\xf9\x75\x38\xe0\x79\xb4\x26\x5c\xfc\xd6\x6f\x7b\x9e\xb5\xf6\xb7\xc8\x8f\xfc\x18\x3c\x6f\x43\x54\x3b\xfc\xf1\x4a\xa2\x14\x47\x05\x49\x9a\xfb\xbe\xef\x83\xe7\x09\xe9\x11\x41\x39\x0a\xe3\x95\x8d\xa4\xf7\xba\x5f\xd3\xa8\xd6\xe8\x35\x36\xa8\xe0\x79\x2b\xb2\xf5\x5a\x5b\xd4\x10\x26\x56\x48\x0b\xd2\xea\x5a\x9a\x61\xd1\xad\xad\xb8\x78\xf2\xd3\xda\x4c\xa8\xe1\x6b\x04\xcf\xb3\x60\xb6\x21\x92\x55\xf5\x3c\x12\xe0\x79\xac\xf4\xa8\x5c\xb5\xf6\xbc\x14\xa0\x35\xb3\x2e\x11\x5a\xa3\xa7\xf9\x0f\x84\xd8\x2f\x52\xf0\xbc\x6f\x5a\x0a\xd5\x52\xaf\x96\xda\x68\x20\x4d\xf3\x68\x8d\x0b\x83\xaa\x22\x14\xed\xfa\xd7\xa7\xe9\x7e\x1e\xcc\x97\x32\x7f\x64\xdd\x47\x66\x6b\x4f\x60\x6f\x88\x91\x70\x8b\xe5\xb5\x5d\x37\x1a\x5c\x4c\x14\x54\x4a\xae\xa0\x13\x46\x75\xda\x42\x42\x2a\xbe\xe4\x62\x0a\x93\xc9\xf8\xd5\x7c\xda\x22\x7f\x96\xcb\xaf\x9e\xd7\x09\x4d\x2a\xf4\x70\xdb\x4a\x8d\x5f\xa1\x6a\xc8\xf2\x17\x00\xff\x67\xcc\x1e\xfe\x8f\xcc\xfe\xa4\x96\xfe\x6d\x6e\x0f\xfc\x78\x12\x24\xf1\x24\xc8\x27\xc9\xb3\xd7\x7d\x4f\xbe\x73\x9d\x72\x82\x37\xdd\xd9\xdd\x45\x17\xbc\xdb\xae\xf5\xee\x68\x71\xad\x16\xba\x58\x9b\xa3\xb4\x34\x9f\x66\xe2\xfd\x99\x3c\xff\x56\xde\xff\x38\x26\xe3\x17\xd4\x27\x93\x20\x4f\x26\x61\x94\xbd\x7a\xc1\xf1\x3b\xba\xe1\x8b\x6f\xf2\xe3\xed\xfb\xea\x88\xc4\x79\x78\x33\x37\x04\x6f\xb6\x17\xe7\x1b\x96\xff\x28\xc5\x51\x70\x9d\x6d\x70\x76\x77\xb3\xbd\x7b\x9b\xdd\x1d\x69\xbc\xca\xed\xe1\xff\x81\xdc\xdf\xe0\xf6\x3c\x29\xa3\xb0\xca\x48\x54\xc5\x7e\x9c\x07\x55\x10\x46\x51\xec\xc7\x41\x9a\xf9\x34\xa7\x25\xfa\x59\x95\xb1\xac\xa0\x6f\x72\x7b\x12\x13\x8c\xb2\xa8\xf2\x8b\xb4\x22\x55\xc8\xca\xb4\xcc\x49\x9c\x66\x41\x46\xfd\xb2\xc8\x91\x56\xc4\xcf\x12\xc6\xde\xe4\xf6\x38\x8e\xab\x34\x2e\x30\xf2\xb3\x38\x0e\x31\x4b\x29\xad\xb2\x28\x8b\xd3\x14\x93\xb0\x0a\x52\xbf\x28\x8b\x3c\x4c\xfd\xb7\xb9\xdd\x8f\x83\x0c\xcb\x28\x2b\xe2\x20\x48\xe3\x28\xcd\x63\x3f\x38\x49\xd3\xb4\xc8\x63\x7a\x7a\x92\xa5\x45\x3c\x3b\xa2\x47\x65\x30\x1e\xd9\x76\x98\x18\x02\xd7\x46\x2a\xb2\xc4\x91\xee\xff\xf6\x4d\xee\x9c\x98\xda\x85\xb8\xb1\xbd\xd2\xc9\x11\x54\xbc\xc1\x91\xbd\xd4\xd4\x53\x38\x34\xab\xf6\xf0\x67\xb3\xfd\x4f\x46\x0c\x99\xb8\x93\xac\xb4\x7a\x8f\xa5\xa8\xf8\xb2\x53\xce\xac\x87\x0b\xa8\x5b\xbd\xfe\xef\xaf\xe9\x15\x3c\xbb\x6d\x81\x82\x08\x03\xf7\xb8\x83\xc1\x87\x91\x71\x4b\x2e\xf1\xf7\xb8\xb3\xab\x38\xa8\x1b\x76\xac\xdc\x87\x07\x4a\xdb\x58\x18\x3a\x34\xcd\xe6\x1f\x80\x08\x06\xf3\x70\x0e\xd7\x3d\x1f\xd9\x12\x47\x61\x6b\x78\x64\xab\xfc\xbd\xd4\x46\x90\x15\x4e\xc1\x77\xad\xb1\x3f\x3a\x80\xb9\x54\x66\x50\x62\x15\xbc\x2c\x68\x0f\x4d\x21\xf7\xf3\xd0\x5e\x6e\xeb\xdc\x33\xd2\x51\x3a\xd0\xc7\xf1\xd2\xa3\x36\x6c\xfb\xf0\x5c\xb7\x48\x79\xb5\x83\xd3\xad\x71\xcc\x01\x1f\xe6\x8f\x6c\x75\x54\x47\x89\xb0\x83\x86\x42\xcb\xe6\x0c\x88\x01\x5e\x41\x89\x35\x17\x0c\x2e\x66\x0b\xab\x06\x07\xe9\x0f\xf3\x29\x6c\x26\xdb\xc9\x6e\xf2\xa3\x0f\xbe\xb5\xba\xd3\xc8\x1e\x6a\xc9\x7a\xdd\x90\x1d\x2a\x9b\x02\x67\xae\x23\x02\x77\x7a\xc1\x57\x28\x3b\xe7\xa6\x00\xd9\xa2\x18\xa6\x9f\x81\xcb\x1d\xc7\xb9\xf7\x69\x04\xfb\xe5\x41\x64\x0a\xe3\xc8\xd7\x0e\x70\x97\x1d\x76\xf8\x8b\xbb\xee\x76\xa2\x77\x82\xd6\x4a\x0a\xd9\x69\x4b\x9b\x14\xb5\xe6\x62\x39\xfa\x6e\x05\xfa\x60\xf4\xb3\x9b\xee\x5d\xef\x56\x25\x2a\x4b\xbc\x96\x37\x50\xe9\x43\x2a\x85\xb6\x5c\x3e\x90\xf0\xc6\x36\xcf\xa5\x7b\xac\x24\x25\xa6\x8f\x8c\x36\x44\x99\xae\x1d\x81\x95\xbf\xed\x05\xa7\xd0\xbb\x77\xa6\x10\x35\x74\x2d\x1c\xcf\x6f\x80\xee\x68\x83\xba\x77\xb5\xbf\xc0\xf6\x21\x1b\xc2\xdd\xc8\x67\xed\xc5\x35\x5a\x14\xc1\xb0\x7d\x4b\xb8\xf3\xf6\xd3\xf5\x14\x02\xeb\xe8\x03\xf3\x69\x97\x42\x4e\x9f\x3a\x3d\xda\x33\xdf\x90\x67\x6c\xd0\x72\xda\xa6\xe6\xb4\x7e\x60\x45\x20\x94\xca\x4e\xb8\x97\xce\x36\x45\xc3\x03\x25\x6d\x10\x86\x97\x85\x01\xef\x5f\x3f\xda\x69\x23\x57\xc3\x25\xfb\x2a\x1a\x46\xdc\x59\xaf\xe6\xc2\x81\x76\x6c\xc7\xda\xf1\xc3\x20\xeb\x0a\x74\x50\xfc\x70\x2f\x6d\x6c\xbf\xd2\xe3\xeb\x2f\x1b\x74\xed\x1a\x57\x08\x1b\x0d\x52\x01\x6f\xe9\x30\xdd\xda\x61\xd6\x7e\x52\x62\xac\xd9\x2e\x24\x7f\xb5\xd1\x95\x0c\x6f\xae\xce\xa7\x50\x1b\xd3\x4e\x0f\x0f\x5d\x7f\x60\x9b\x8a\x69\x91\xc4\xc9\x3e\x99\x6e\xfa\x5e\x12\xeb\x0b\xa7\xd6\xdc\x25\xd1\x73\xfb\x39\x85\xc0\xdf\xff\x7b\x76\xb8\xe1\x2b\x6e\xfa\xc3\xe7\xf6\x73\x0a\x71\x16\x84\x51\x9e\x3f\x01\xa9\x91\x2e\x5b\x3d\xb4\xc4\x4f\xcf\x8c\x22\x42\x93\x87\xe6\xc3\xfa\xc0\x58\x3f\xad\x13\x70\xfd\x99\xab\xfe\xde\x15\x30\x8a\x2f\x97\xa8\x90\xf5\x90\x36\xb8\x35\xfb\x44\xf7\xb0\x4e\x7d\x8b\xeb\xd7\x2e\x56\x48\x18\x48\xd1\xec\x6c\xb9\xec\xc1\xbe\xff\x2f\x8b\xbd\x49\x3f\x55\x5f\x21\x61\x4f\xd5\x07\xc9\xa0\xfd\xc2\x66\xe2\xb1\xed\xad\x94\x0d\xac\xc8\x16\x14\x1a\xc5\xfb\x06\x43\xa3\x60\x40\x9e\x1c\x93\x6b\x57\xca\x2b\xb2\xbd\xea\xcf\x4d\x21\x1c\x62\xfa\xb2\x4a\xd7\xe5\xad\x49\xe3\xf4\xee\xfa\x02\x20\xd6\x40\xda\x29\xe5\xc6\xe5\x47\x12\x35\xd1\x50\x22\xda\x79\xda\x20\x35\x2e\x4c\x7b\x05\xf6\x3e\xfb\xac\x85\x83\x07\x27\x5c\x3b\xb4\x38\x8d\x5a\xae\x9e\xa1\x4d\x03\x93\x8f\x87\x01\x30\x5b\x67\x11\x69\xf9\x08\xc0\x6c\xe7\x52\x36\x33\x6a\x69\xe1\x54\x58\x4d\x6c\x0a\x46\x75\x68\x6b\x8d\x88\x1d\x30\x2c\xbb\xe5\x72\xa0\x24\x5b\x02\x8e\x00\x96\x12\xec\x25\x23\xb7\xdb\x97\x5a\xdb\x2a\x59\xb9\xf4\x3c\x88\x58\xb2\xb3\xab\x53\xa8\x48\xa3\x71\xf4\xaf\x00\x00\x00\xff\xff\x32\xb3\x83\xb8\x74\x12\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,12 +84,12 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4668, mode: os.FileMode(420), modTime: time.Unix(1545075267, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4724, mode: os.FileMode(420), modTime: time.Unix(1547413673, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x92\xcd\x6e\x1c\x37\x0c\xc7\xef\xf3\x14\x02\x2f\xbe\xec\xae\xf5\xfd\xf5\x06\x45\xd0\x5e\x5a\x20\x67\x4a\xa2\x6c\x61\xbd\xb3\x53\x8d\xc6\xce\x22\xc8\xbb\x17\xb3\xb1\x9b\xab\x83\xb9\x90\x04\xff\xfc\x93\xa3\x5f\xa6\x79\xf4\x56\xb7\x27\xfa\x8b\xc6\xdb\xb5\x9f\x23\x1b\xb4\x8e\x36\x3f\x4d\x34\x9e\xa9\xd3\x76\x89\x13\x63\x98\xf3\x75\x9b\xc7\xba\xc7\x8c\x5d\xb0\xcd\x91\xdd\x43\xc6\xce\x74\x8b\xec\xe1\x3b\x60\x29\x9d\xd6\x15\x22\xf8\x90\x38\x7a\x6b\xbc\xca\x5a\x6b\x8d\xb9\x16\x27\x92\xb6\x8a\x78\x51\xd9\x18\x24\xa1\x85\x44\x03\x07\xc8\xfd\xb6\x8c\x2b\xc4\xef\x90\xdb\xf2\x4c\x1d\x22\x20\xad\x47\x21\xfd\x31\x8f\xbe\x37\xdc\xcb\x83\xbe\x0d\x88\x90\x9d\x0b\xd5\x2b\x17\x8a\x73\xbc\x04\x99\x6b\x16\xa5\x14\x8d\xbe\x2a\x51\x0c\x72\x2c\xd9\x57\x89\x3c\x49\x14\x9a\x0b\xe5\x78\x51\x56\xf1\xaa\x7c\xe6\xd9\xe3\xff\xf3\x16\xec\x78\x59\x77\xdb\xf6\x0a\x11\x94\xcd\xc2\x7a\x72\x2a\xd5\xe0\x79\x25\x67\x12\x77\xd2\x55\x1f\x38\x3a\x81\x05\x7e\x1c\xe0\x5c\x2a\x44\x58\xef\x0b\xc3\x3d\xfd\x35\xa4\x9c\x5f\x68\x86\xa8\xe4\x01\x66\x88\xd2\x4a\xa1\xf5\x01\x16\x88\xe2\x00\x1d\xa2\x3f\xc0\x8a\x2f\xfb\x01\x85\x44\x22\x61\x49\xe5\xe0\x45\xd0\xba\x08\xca\x28\x93\x4f\xd2\x91\x26\x4b\x3c\x99\x54\x93\x56\x89\xb8\x72\x16\x4d\xf1\xde\x87\x8a\xd6\x05\x94\x5e\x48\xb9\x2f\x72\xc1\xbc\xff\x8a\x2c\xa4\x4f\x5e\x18\x63\x4c\x42\x41\x58\x5c\x46\x0a\xdc\x72\xf2\x5e\x4b\xac\x19\xbd\x32\xb6\x70\xab\x8d\x49\x25\xa0\x71\x46\x26\xb4\x35\x67\x1e\x24\xd5\x7d\x52\x2b\x10\x41\x1b\xe2\x96\xa3\x3d\x16\x89\x74\xd4\x2a\xf9\x63\x90\xb2\x1e\xb5\xf6\x32\xe8\x10\x8a\x72\x05\x0e\xf0\x4a\x7d\x6d\xd7\xfd\xc8\x1f\x0f\xef\x0f\xbf\xe0\xba\xbe\x5d\x7b\x89\xec\xe1\xa3\xf4\xce\x40\x64\x9f\x45\x60\x9a\x5a\xa1\x79\xb4\x71\xfb\xa3\x44\x06\xfc\x1b\x17\xbf\x3e\x98\xa6\x7f\x37\xda\x68\x87\x6e\xde\x2e\x5f\xaf\xfd\x4c\x7d\x8d\x4c\x4e\x8c\xbd\xdd\x93\xaf\xd8\xc6\x3f\xed\x42\x7f\xfe\x1d\x99\x98\xa6\x33\xdd\xee\x84\xae\xed\x69\x6e\xf3\xd3\x4f\x58\x97\x2d\xbd\xb4\xfc\x65\xa7\xf4\x74\x7a\x3c\x9d\x1e\xd3\xd6\x5e\xca\x63\xa7\xf5\xba\xf5\x4c\xeb\xe3\x7b\xf7\x17\xba\x9d\x96\x2d\x9d\x16\xba\xfc\xd4\xf5\xf6\x8a\x83\x3e\x27\x3c\xef\xe2\xbb\x90\xc6\x33\x6e\xe3\xf9\x93\xde\xef\xdd\xbf\x69\xfc\xa1\xfa\x70\xfd\x2f\x00\x00\xff\xff\x56\xed\xff\x60\xc5\x03\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\xc9\x8e\xdc\x36\x10\xbd\xeb\x2b\x88\xca\x61\x2e\xbd\x70\x15\x97\x3f\x08\x8c\xe4\x12\x03\x3e\x17\xc9\x62\x8f\xd0\xd3\x6a\x85\xa4\x66\xdc\x30\xfc\xef\x81\xda\x3d\x99\xeb\x18\xba\x90\x4f\x6f\xa9\x92\x5e\xa2\xb9\xd7\xa9\xac\x27\xfa\x9b\xfa\xdb\xb5\x9e\x03\xeb\xd4\xfa\x34\x9f\x06\xea\xcf\x54\x69\xbd\x84\x81\x31\x4c\xe9\xba\xce\xbd\x6d\x67\xc6\x2e\x38\xcd\x81\xdd\x8f\x8c\x9d\xe9\x16\xd8\xd3\x0f\xc0\x9c\x2b\xb5\x06\x01\x9c\x8f\x1c\xdd\x68\x9c\x4a\x5a\x6b\x8d\xa9\x64\x2b\xa2\x1e\x15\xf1\xac\x92\x31\x48\x42\x0b\x89\x06\x76\x90\xea\x6d\xe9\x57\x08\x3f\x20\x4d\xcb\x33\x55\x08\x80\xd4\xf6\x42\xba\x7d\xea\x75\x23\xdc\xe1\x4e\xdf\x3b\x04\x48\xd6\xfa\xe2\x94\xf5\xd9\x5a\x9e\xbd\x4c\x25\x89\x9c\xb3\x46\x57\x94\xc8\x06\x39\xe6\xe4\x8a\x44\x1e\x25\x0a\xcd\x85\xb2\x3c\xab\x51\xf1\xa2\x5c\xe2\xc9\xe1\xff\x7e\x0b\x56\xbc\xb4\x2d\x76\x7a\x85\x00\x6a\x4c\x62\x74\x64\x55\x2c\xde\xf1\x42\xd6\x44\x6e\xa5\x2d\xce\x73\xb4\x02\x33\xfc\xdc\xc1\x39\x17\x08\xd0\xee\x03\xc3\xfd\xfa\x61\x92\xcf\x2f\x34\x43\x50\x72\x07\x33\x04\x39\x4a\xa1\xf5\x0e\x16\x08\x62\x07\x15\x82\xdb\x41\xc3\x97\x6d\x81\x4c\x22\x92\x18\x49\x25\xef\x84\xd7\x3a\x0b\x4a\x28\xa3\x8b\xd2\x92\xa6\x91\x78\x34\xb1\x44\xad\x22\x71\x65\x47\x34\xd9\x39\xe7\x0b\x8e\xd6\xa3\x74\x42\xca\x6d\x90\x0b\xa6\xed\x53\x24\x21\x5d\x74\xc2\x18\x63\x22\x0a\xc2\x6c\x13\x92\xe7\x23\x27\xe7\xb4\xc4\x92\xd0\x29\x33\x66\x3e\x6a\x63\x62\xf6\x68\xac\x91\x11\xc7\x92\x12\xf7\x92\xca\xe6\x34\x65\x08\xa0\x0d\xf1\x91\xe3\xb8\xcf\x12\x69\xaf\x55\x74\x7b\x2f\x65\xd9\x6b\xed\xa4\xd7\xde\x67\x65\x33\xec\xe0\x95\x6a\x9b\xae\xdb\x92\x3f\x9f\x1e\x3f\x7e\xc1\xd6\xde\xae\x35\x07\xf6\xf4\x0e\x3d\x3a\x10\xd8\x67\x2b\x30\x0c\x53\xa6\xb9\x4f\xfd\xf6\x67\x0e\x0c\xf8\x77\x2e\x3e\x1e\x18\x86\x3f\xd8\x57\x9a\x71\xee\x5b\xcb\x58\xeb\xd7\x8a\x27\x1a\xfa\x1d\xba\x77\xf1\x4c\xb7\x0d\xa5\xc0\x8e\xfd\xb2\x1c\x1f\x6f\x86\xe1\xdf\x95\x56\xda\x08\xf3\x7a\xf9\x76\xad\x67\xaa\x2d\x30\x39\x30\xf6\x76\xbf\x7c\xc3\xa9\x7f\x9d\x2e\xf4\xd7\x3f\x81\x89\x61\xd8\x5c\x36\x72\x9b\x4e\xf3\x34\x9f\x7e\x95\x7c\x59\xe3\xcb\x94\xbe\x6c\xed\x3e\x1c\x8e\x87\xc3\x31\xae\xd3\x4b\x3e\x56\x6a\xd7\xb5\x26\x6a\xc7\x07\xfb\x0b\xdd\x0e\xcb\x1a\x0f\x0b\x5d\x7e\xe9\xea\xf4\x8a\x9d\x3e\x27\x3c\x6f\xe2\xbb\x90\xfa\x33\xae\xfd\xf9\x93\xd9\x0f\xf6\x6f\x06\xbf\xab\xde\x53\xff\x0b\x00\x00\xff\xff\x35\xa4\xa3\x67\xfd\x03\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 965, mode: os.FileMode(420), modTime: time.Unix(1545556716, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1021, mode: os.FileMode(420), modTime: time.Unix(1547419676, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testworld/config_test.go b/testworld/config_test.go index e3046b7cb..34c695a66 100644 --- a/testworld/config_test.go +++ b/testworld/config_test.go @@ -26,4 +26,9 @@ func TestConfig_Happy(t *testing.T) { tenants := res.Value("data").Array() tenants.Length().Equal(1) tenants.Element(0).Path("$.identity_id").String().NotEmpty().Equal(charlie.id.String()) + + // generate a tenant within Charlie + res = generateTenant(charlie.httpExpect, http.StatusOK) + tcID := res.Value("identity_id").String().NotEmpty() + tcID.NotEqual(charlie.id.String()) } diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 0f361727c..062eac5fa 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -3,8 +3,10 @@ package testworld import ( + "math/rand" "net/http" "testing" + "time" ) func TestHost_AddExternalCollaborator(t *testing.T) { @@ -31,6 +33,8 @@ func TestHost_AddExternalCollaborator(t *testing.T) { } func addExternalCollaborator(t *testing.T, documentType string) { + // TODO remove this when we have retry for tasks + time.Sleep(time.Duration(rand.Intn(5)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") diff --git a/testworld/httputils.go b/testworld/httputils.go index 20bc640ba..714732bd3 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -117,6 +117,14 @@ func getAllTenantConfigs(e *httpexpect.Expect, httpStatus int) *httpexpect.Objec return resp.JSON().Object() } +func generateTenant(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { + resp := e.POST("/config/tenants/generate"). + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + Expect().Status(httpStatus) + return resp.JSON().Object() +} + // TODO add rest of the endpoints for config func createInsecureClient() *http.Client { diff --git a/testworld/nft_test.go b/testworld/nft_test.go index a7f5c565a..1e1fcf277 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -3,8 +3,10 @@ package testworld import ( + "math/rand" "net/http" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -18,12 +20,12 @@ func TestPaymentObligationMint_invoice_successful(t *testing.T) { func TestPaymentObligationMint_po_successful(t *testing.T) { t.Parallel() paymentObligationMint(t, typePO) - } */ func paymentObligationMint(t *testing.T, documentType string) { - + // TODO remove this when we have retry for tasks + time.Sleep(time.Duration(rand.Intn(5)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") diff --git a/testworld/park.go b/testworld/park.go index 618c1638c..86d46b59f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -8,8 +8,6 @@ import ( "os" "os/signal" - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "testing" @@ -248,7 +246,7 @@ func (h *host) init() error { return err } h.config = h.bootstrappedCtx[bootstrap.BootstrappedConfig].(config.Configuration) - idService := h.bootstrappedCtx[ethid.BootstrappedIDService].(identity.Service) + idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) idBytes, err := h.config.GetIdentityID() if err != nil { return err diff --git a/transactions/handler_test.go b/transactions/handler_test.go index fbbffc910..3fdf3eda2 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -10,15 +10,13 @@ import ( "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/stretchr/testify/assert" ) func TestGRPCHandler_GetTransactionStatus(t *testing.T) { - cService := ctx[configstore.BootstrappedConfigStorage].(config.Service) + cService := ctx[config.BootstrappedConfigStorage].(config.Service) h := GRPCHandler(ctx[BootstrappedService].(Service), cService) req := new(transactionspb.TransactionStatusRequest) ctxl := context.Background() diff --git a/transactions/repository_test.go b/transactions/repository_test.go index ae1e6e0fe..9198babbb 100644 --- a/transactions/repository_test.go +++ b/transactions/repository_test.go @@ -7,6 +7,8 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/identity" @@ -30,6 +32,7 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, Bootstrapper{}, } + ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) From fdd07469d8f026f967cd9eb34e6e93bfc4765acc Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 14 Jan 2019 17:44:29 +0100 Subject: [PATCH 132/220] Success message added (#641) * Success message added * further user instructions for success message --- cmd/common.go | 2 ++ config/configuration.go | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/common.go b/cmd/common.go index 7ba8f9c0b..9486ea584 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -120,6 +120,8 @@ func CreateConfig( dbCfg := ctx[storage.BootstrappedConfigDB].(storage.Repository) db.Close() dbCfg.Close() + log.Infof("---------Centrifuge node configuration file successfully created!---------") + log.Infof("Please run the Centrifuge node using the following command: centrifuge run -c %s\n", v.ConfigFileUsed()) return nil } diff --git a/config/configuration.go b/config/configuration.go index ab612d8fe..a6a15ef88 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -527,7 +527,6 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { if err != nil { log.Fatalf("error: %v", err) } - return v, nil } From 5f821f28737ea536782fc48fa4e05890af1074bd Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 14 Jan 2019 18:15:05 +0100 Subject: [PATCH 133/220] Added signature to header + handshake validation (#640) * Added signature to header + handshake validation * fix tests * address comments * added eth key check * fix integration test --- crypto/ed25519/ed25519.go | 5 + crypto/verify.go | 3 +- p2p/bootstrapper.go | 8 +- p2p/bootstrapper_test.go | 5 + p2p/client_test.go | 12 +-- p2p/common/protocol.go | 10 ++ p2p/common/protocol_test.go | 3 + p2p/messenger_test.go | 2 +- p2p/receiver/handler.go | 2 +- p2p/receiver/handler_integration_test.go | 2 +- p2p/receiver/handler_test.go | 49 +++++---- p2p/receiver/validator.go | 72 ++++++++++--- p2p/receiver/validator_test.go | 125 +++++++++++++++++------ p2p/server_test.go | 8 +- 14 files changed, 227 insertions(+), 79 deletions(-) diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index fb085749c..d542beb7b 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -64,3 +64,8 @@ func PublicKeyToP2PKey(publicKey [32]byte) (p2pID peer.ID, err error) { return peer.IDFromPublicKey(pk) } + +// VerifySignature validates signature with payload message +func VerifySignature(publicKey, message, sign []byte) bool { + return ed25519.Verify(ed25519.PublicKey(publicKey), message, sign) +} diff --git a/crypto/verify.go b/crypto/verify.go index 8a368a434..19f763c3a 100644 --- a/crypto/verify.go +++ b/crypto/verify.go @@ -1,6 +1,7 @@ package crypto import ( + "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -22,7 +23,7 @@ func VerifyMessage(publicKey, message []byte, signature []byte, curveType string return secp256k1.VerifySignature(publicKey, msg, signatureBytes) case CurveEd25519: - return false + return ed25519.VerifySignature(publicKey, message, signature) default: return false } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index df37e2a36..14821afcc 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -6,6 +6,7 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/receiver" ) @@ -29,8 +30,13 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("registry not initialised") } + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + srv := &peer{config: cfgService, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) + return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService)) }} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[bootstrap.BootstrappedP2PClient] = srv diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index bead4a968..3a714ab0c 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,6 +5,9 @@ package p2p import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -30,6 +33,8 @@ func TestBootstrapper_Bootstrap(t *testing.T) { m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() + ids := new(testingcommons.MockIDService) + m[identity.BootstrappedIDService] = ids err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/client_test.go b/p2p/client_test.go index 7ee027ee9..2e14aa3d3 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -56,10 +56,10 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) + m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -78,10 +78,10 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.NoError(t, err) ctx := testingconfig.CreateTenantContext(t, c) - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) + m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -101,12 +101,12 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, mock.Anything, envelope, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go index 1d7c8a997..90be5a380 100644 --- a/p2p/common/protocol.go +++ b/p2p/common/protocol.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" @@ -122,6 +124,14 @@ func PrepareP2PEnvelope(ctx context.Context, networkID uint32, messageType Messa Body: body, } + signRequest, err := proto.Marshal(envelope) + if err != nil { + return nil, err + } + + signKeys := self.Keys[identity.KeyPurposeSigning] + envelope.Header.Signature = crypto.Sign(self.ID[:], signKeys.PrivateKey, signKeys.PublicKey, signRequest) + marshalledRequest, err := proto.Marshal(envelope) if err != nil { return nil, err diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index 836a61b32..fa4d67416 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -112,4 +112,7 @@ func TestPrepareP2PEnvelope(t *testing.T) { p2pEnv, err = PrepareP2PEnvelope(ctx, uint32(0), MessageTypeRequestSignature, msg) assert.NoError(t, err) assert.NotNil(t, p2pEnv) + dataEnv, err := ResolveDataEnvelope(p2pEnv) + assert.NoError(t, err) + assert.NotNil(t, dataEnv.Header.Signature) } diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go index 62d481261..ff1f466c1 100644 --- a/p2p/messenger_test.go +++ b/p2p/messenger_test.go @@ -75,7 +75,7 @@ func TestHandleNewMessage(t *testing.T) { // 1. happy path // from h1 to h2 (with a message size ~ MessageSizeMax, has to be less because of the length bytes) - p2pEnv, err := p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax - 200)}) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax - 400)}) assert.NoError(t, err) msg, err := m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) assert.NoError(t, err) diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index d3c65a329..c2495c7eb 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -82,7 +82,7 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - err = srv.handshakeValidator.Validate(envelope.Header) + err = srv.handshakeValidator.Validate(envelope) if err != nil { return convertToErrorEnvelop(err) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index d35c2ab86..008d7f81a 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -49,7 +49,7 @@ func TestMain(m *testing.M) { registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID())) + handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService)) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 5408da492..b9a4348f4 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -7,13 +7,17 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/version" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/version" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-protocol" @@ -40,10 +44,11 @@ import ( ) var ( - handler *Handler - registry *documents.ServiceRegistry - coreDoc = testingcoredocument.GenerateCoreDocument() - cfg config.Configuration + handler *Handler + registry *documents.ServiceRegistry + coreDoc = testingcoredocument.GenerateCoreDocument() + cfg config.Configuration + mockIDService *testingcommons.MockIDService ) func TestMain(m *testing.M) { @@ -62,7 +67,9 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID())) + mockIDService = &testingcommons.MockIDService{} + mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil) + handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID(), mockIDService)) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -143,9 +150,16 @@ func TestHandler_HandleInterceptor_UnsupportedMessageType(t *testing.T) { p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) - // Manipulate message type in Header + // Manipulate message type in Header + Signature dataEnv, _ := p2pcommon.ResolveDataEnvelope(p2pEnv) dataEnv.Header.Type = "UnsupportedType" + dataEnv.Header.Signature = nil + signRequest, err := proto.Marshal(dataEnv) + assert.NoError(t, err) + self, err := contextutil.Self(ctx) + assert.NoError(t, err) + signKeys := self.Keys[identity.KeyPurposeSigning] + dataEnv.Header.Signature = crypto.Sign(self.ID[:], signKeys.PrivateKey, signKeys.PublicKey, signRequest) marshalledRequest, err := proto.Marshal(dataEnv) assert.NoError(t, err) p2pEnv = &protocolpb.P2PEnvelope{Body: marshalledRequest} @@ -184,31 +198,28 @@ func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { func TestP2PService_basicChecks(t *testing.T) { tests := []struct { - header *p2ppb.Header - err error + envelope *p2ppb.Envelope + err error }{ { - header: &p2ppb.Header{NodeVersion: "someversion", NetworkIdentifier: 12}, - err: errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), + envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: "someversion", NetworkIdentifier: 12}}, + err: errors.AppendError(errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), errors.New("signature header missing")), }, { - header: &p2ppb.Header{NodeVersion: "0.0.1", NetworkIdentifier: 12}, - err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), + envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: "0.0.1", NetworkIdentifier: 12}}, + err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), errors.New("signature header missing")), }, { - header: &p2ppb.Header{NodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}, + envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}}, + err: errors.AppendError(errors.New("signature header missing"), nil), }, } for _, c := range tests { - err := HandshakeValidator(cfg.GetNetworkID()).Validate(c.header) + err := HandshakeValidator(cfg.GetNetworkID(), mockIDService).Validate(c.envelope) if err != nil { - if c.err == nil { - t.Fatalf("unexpected error: %v\n", err) - } - assert.EqualError(t, err, c.err.Error(), "error mismatch") } } diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 90e157848..a078b5aa7 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -3,6 +3,11 @@ package receiver import ( "fmt" + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" @@ -13,16 +18,16 @@ import ( // Validator defines method that must be implemented by any validator type. type Validator interface { // Validate validates p2p requests - Validate(header *p2ppb.Header) error + Validate(envelope *p2ppb.Envelope) error } // ValidatorGroup implements Validator for validating a set of validators. type ValidatorGroup []Validator // Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(header *p2ppb.Header) (errs error) { +func (group ValidatorGroup) Validate(envelope *p2ppb.Envelope) (errs error) { for _, v := range group { - if err := v.Validate(header); err != nil { + if err := v.Validate(envelope); err != nil { errs = errors.AppendError(errs, err) } } @@ -31,43 +36,76 @@ func (group ValidatorGroup) Validate(header *p2ppb.Header) (errs error) { // ValidatorFunc implements Validator and can be used as a adaptor for functions // with specific function signature -type ValidatorFunc func(header *p2ppb.Header) error +type ValidatorFunc func(envelope *p2ppb.Envelope) error // Validate passes the arguments to the underlying validator // function and returns the results -func (vf ValidatorFunc) Validate(header *p2ppb.Header) error { - return vf(header) +func (vf ValidatorFunc) Validate(envelope *p2ppb.Envelope) error { + return vf(envelope) } func versionValidator() Validator { - return ValidatorFunc(func(header *p2ppb.Header) error { - if header == nil { - return errors.New("nil header") + return ValidatorFunc(func(envelope *p2ppb.Envelope) error { + if envelope == nil || envelope.Header == nil { + return errors.New("nil envelope/header") } - if !version.CheckVersion(header.NodeVersion) { - return version.IncompatibleVersionError(header.NodeVersion) + if !version.CheckVersion(envelope.Header.NodeVersion) { + return version.IncompatibleVersionError(envelope.Header.NodeVersion) } return nil }) } func networkValidator(networkID uint32) Validator { - return ValidatorFunc(func(header *p2ppb.Header) error { - if header == nil { - return errors.New("nil header") + return ValidatorFunc(func(envelope *p2ppb.Envelope) error { + if envelope == nil || envelope.Header == nil { + return errors.New("nil envelope/header") } - if networkID != header.NetworkIdentifier { - return incompatibleNetworkError(networkID, header.NetworkIdentifier) + if networkID != envelope.Header.NetworkIdentifier { + return incompatibleNetworkError(networkID, envelope.Header.NetworkIdentifier) } return nil }) } +func signatureValidator(idService identity.Service) Validator { + return ValidatorFunc(func(envelope *p2ppb.Envelope) error { + if envelope == nil || envelope.Header == nil { + return errors.New("nil envelope/header") + } + + if envelope.Header.Signature == nil { + return errors.New("signature header missing") + } + + envData := proto.Clone(envelope).(*p2ppb.Envelope) + // Remove Signature header so we can verify the message signed + envData.Header.Signature = nil + + data, err := proto.Marshal(envData) + if err != nil { + return err + } + + valid := crypto.VerifyMessage(envelope.Header.Signature.PublicKey, data, envelope.Header.Signature.Signature, crypto.CurveEd25519, false) + if !valid { + return errors.New("signature validation failure") + } + + centID, err := identity.ToCentID(envelope.Header.Signature.EntityId) + if err != nil { + return err + } + return idService.ValidateKey(centID, envelope.Header.Signature.PublicKey, identity.KeyPurposeSigning) + }) +} + // HandshakeValidator validates the p2p handshake details -func HandshakeValidator(networkID uint32) ValidatorGroup { +func HandshakeValidator(networkID uint32, idService identity.Service) ValidatorGroup { return ValidatorGroup{ versionValidator(), networkValidator(networkID), + signatureValidator(idService), } } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 6be5b3f31..e3afb5b49 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -5,11 +5,25 @@ package receiver import ( "testing" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/stretchr/testify/mock" + + "github.com/golang/protobuf/proto" + + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" ) +var ( + key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} + id1 = []byte{1, 1, 1, 1, 1, 1} +) + func TestValidate_versionValidator(t *testing.T) { vv := versionValidator() @@ -18,23 +32,23 @@ func TestValidate_versionValidator(t *testing.T) { assert.NotNil(t, err) // Empty header - header := &p2ppb.Header{} - err = vv.Validate(header) + envelope := &p2ppb.Envelope{Header: &p2ppb.Header{}} + err = vv.Validate(envelope) assert.NotNil(t, err) // Incompatible Major - header.NodeVersion = "1.1.1" - err = vv.Validate(header) + envelope.Header.NodeVersion = "1.1.1" + err = vv.Validate(envelope) assert.NotNil(t, err) // Compatible Minor - header.NodeVersion = "0.1.1" - err = vv.Validate(header) + envelope.Header.NodeVersion = "0.1.1" + err = vv.Validate(envelope) assert.Nil(t, err) //Same version - header.NodeVersion = version.GetVersion().String() - err = vv.Validate(header) + envelope.Header.NodeVersion = version.GetVersion().String() + err = vv.Validate(envelope) assert.Nil(t, err) } @@ -45,45 +59,98 @@ func TestValidate_networkValidator(t *testing.T) { err := nv.Validate(nil) assert.NotNil(t, err) - header := &p2ppb.Header{} - err = nv.Validate(header) + envelope := &p2ppb.Envelope{Header: &p2ppb.Header{}} + err = nv.Validate(envelope) assert.NotNil(t, err) // Incompatible network - header.NetworkIdentifier = 12 - err = nv.Validate(header) + envelope.Header.NetworkIdentifier = 12 + err = nv.Validate(envelope) assert.NotNil(t, err) // Compatible network - header.NetworkIdentifier = cfg.GetNetworkID() - err = nv.Validate(header) + envelope.Header.NetworkIdentifier = cfg.GetNetworkID() + err = nv.Validate(envelope) assert.Nil(t, err) } -func TestValidate_handshakeValidator(t *testing.T) { - hv := HandshakeValidator(cfg.GetNetworkID()) +func TestValidate_signatureValidator(t *testing.T) { + idService := &testingcommons.MockIDService{} + sv := signatureValidator(idService) + + // Nil envelope + err := sv.Validate(nil) + assert.Error(t, err) + + // Nil Header + envelope := &p2ppb.Envelope{} + err = sv.Validate(envelope) + assert.Error(t, err) + + // Nil Signature + envelope.Header = &p2ppb.Header{} + err = sv.Validate(envelope) + assert.Error(t, err) + + // Signature validation failure + envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, key1Pub) + err = sv.Validate(envelope) + assert.Error(t, err) + + // Ethereum Identity validation failure + envelope.Header.Signature = nil + data, err := proto.Marshal(envelope) + assert.NoError(t, err) + envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, data) + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() + err = sv.Validate(envelope) + assert.Error(t, err) + + // Success + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + err = sv.Validate(envelope) + assert.NoError(t, err) +} - // Incompatible version and network - header := &p2ppb.Header{ - NodeVersion: "version", - NetworkIdentifier: 52, +func TestValidate_handshakeValidator(t *testing.T) { + idService := &testingcommons.MockIDService{} + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + hv := HandshakeValidator(cfg.GetNetworkID(), idService) + + // Incompatible version network and wrong signature + envelope := &p2ppb.Envelope{ + Header: &p2ppb.Header{ + NodeVersion: "version", + NetworkIdentifier: 52, + Signature: crypto.Sign(id1, key1, key1Pub, key1Pub), + }, + Body: key1Pub, } - err := hv.Validate(header) + err := hv.Validate(envelope) assert.NotNil(t, err) // Incompatible version, correct network - header.NetworkIdentifier = cfg.GetNetworkID() - err = hv.Validate(header) + envelope.Header.NetworkIdentifier = cfg.GetNetworkID() + err = hv.Validate(envelope) assert.NotNil(t, err) // Compatible version, incorrect network - header.NetworkIdentifier = 52 - header.NodeVersion = version.GetVersion().String() - err = hv.Validate(header) + envelope.Header.NetworkIdentifier = 52 + envelope.Header.NodeVersion = version.GetVersion().String() + err = hv.Validate(envelope) assert.NotNil(t, err) - // Compatible version and network - header.NetworkIdentifier = cfg.GetNetworkID() - err = hv.Validate(header) + // Compatible version, network and wrong signature + envelope.Header.NetworkIdentifier = cfg.GetNetworkID() + err = hv.Validate(envelope) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "signature validation failure") + + // Compatible version, network and signature + envelope.Header.Signature = nil + data, err := proto.Marshal(envelope) + assert.NoError(t, err) + envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, data) + err = hv.Validate(envelope) assert.Nil(t, err) } diff --git a/p2p/server_test.go b/p2p/server_test.go index 497bd16e7..eb713e392 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -29,7 +29,8 @@ import ( ) var ( - cfg config.Service + cfg config.Service + idService identity.Service ) func TestMain(m *testing.M) { @@ -43,7 +44,8 @@ func TestMain(m *testing.M) { documents.Bootstrapper{}, } ctx := make(map[string]interface{}) - ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} + idService = &testingcommons.MockIDService{} + ctx[identity.BootstrappedIDService] = idService bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[config.BootstrappedConfigStorage].(config.Service) c, _ := cfg.GetConfig() @@ -66,7 +68,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { _, err = cfg.UpdateConfig(c) assert.NoError(t, err) cp2p := &peer{config: cfg, handlerCreator: func() *receiver.Handler { - return receiver.New(cfg, nil, receiver.HandshakeValidator(n.NetworkID)) + return receiver.New(cfg, nil, receiver.HandshakeValidator(n.NetworkID, idService)) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) From dccc0546f4adc7aab4d5b87b65bfa51029a5a7a9 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 15 Jan 2019 15:43:53 +0100 Subject: [PATCH 134/220] Multitenant(Account) api (#642) * Enable auth header for API * Minor * Minor * Minor * More tests and fixes * non exisiting document check * Fix tests * lint * fix * remove comment --- api/server.go | 2 +- config/configstore/bootstrapper.go | 4 +- config/configstore/mock_service.go | 2 +- config/configstore/model.go | 1 + config/configstore/service.go | 20 ++- .../configstore/service_integration_test.go | 9 + contextutil/context.go | 16 +- coredocument/processor.go | 3 +- documents/handler_test.go | 17 +- documents/invoice/handler_test.go | 32 ++-- documents/purchaseorder/handler_test.go | 16 +- ethereum/geth_client.go | 3 +- identity/ethid/ethereum_identity.go | 2 - .../key_registration_confirmation_task.go | 9 +- nft/handler_test.go | 26 +-- p2p/server.go | 29 ++- testingutils/config/config.go | 10 ++ testingutils/setup.go | 2 +- testworld/config_test.go | 14 +- testworld/document_consensus_test.go | 167 +++++++++++++++--- testworld/httputils.go | 86 +++++---- testworld/nft_test.go | 14 +- testworld/park.go | 53 ++++-- testworld/park_test.go | 10 +- testworld/proof_test.go | 12 +- testworld/start_test.go | 8 + transactions/handler.go | 26 ++- transactions/handler_test.go | 5 +- 28 files changed, 420 insertions(+), 178 deletions(-) diff --git a/api/server.go b/api/server.go index b3146e3d7..bfee456d6 100644 --- a/api/server.go +++ b/api/server.go @@ -75,7 +75,7 @@ func (c apiServer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr cha opts := []grpc.ServerOption{ grpc.Creds(creds), - // grpcInterceptor(), // enable this once we start requiring the tenant id to passed as header + grpcInterceptor(), } grpcServer := grpc.NewServer(opts...) diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index ffd1f4b9f..35356e74d 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -27,7 +27,9 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } repo := &repo{configdb} - service := &service{repo, idService} + service := &service{repo, idService, func() ProtocolSetter { + return context[bootstrap.BootstrappedP2PServer].(ProtocolSetter) + }} nc := NewNodeConfig(cfg) configdb.Register(nc) diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 8a9710478..9fa3dbb95 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -23,7 +23,7 @@ func (m MockService) GetConfig() (config.Configuration, error) { func (m MockService) GetTenant(identifier []byte) (config.TenantConfiguration, error) { args := m.Called(identifier) - return args.Get(0).(*TenantConfig), args.Error(0) + return args.Get(0).(config.TenantConfiguration), args.Error(1) } func (m MockService) GetAllTenants() ([]config.TenantConfiguration, error) { diff --git a/config/configstore/model.go b/config/configstore/model.go index 18a5eed5b..b7c97c5da 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -451,6 +451,7 @@ type TenantConfig struct { IdentityID []byte SigningKeyPair KeyPair EthAuthKeyPair KeyPair + P2PKeyPair KeyPair } // GetEthereumAccount gets EthereumAccount diff --git a/config/configstore/service.go b/config/configstore/service.go index 8086724dd..6c2e9d3a1 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -21,9 +21,15 @@ const ( ethAuthPrivKeyName = "ethauth.key.pem" ) +// ProtocolSetter sets the protocol on host for the centID +type ProtocolSetter interface { + InitProtocolForCID(CID identity.CentID) +} + type service struct { - repo repository - idService identity.Service + repo repository + idService identity.Service + protocolSetterFinder func() ProtocolSetter } // DefaultService returns an implementation of the config.Service @@ -89,6 +95,14 @@ func (s service) GenerateTenant() (config.TenantConfiguration, error) { return nil, err } + // minor hack to set same p2p keys as node to tenant: Set the new tenant ID to copy of main tenant and create p2p keys + mtcc := mtc.(*TenantConfig) + mtcc.IdentityID = CID[:] + err = s.idService.AddKeyFromConfig(mtcc, identity.KeyPurposeP2P) + if err != nil { + return nil, err + } + err = s.idService.AddKeyFromConfig(tc, identity.KeyPurposeSigning) if err != nil { return nil, err @@ -104,6 +118,8 @@ func (s service) GenerateTenant() (config.TenantConfiguration, error) { return nil, err } + // initiate network handling + s.protocolSetterFinder().InitProtocolForCID(CID) return tc, nil } diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go index 612926466..3e104d529 100644 --- a/config/configstore/service_integration_test.go +++ b/config/configstore/service_integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/stretchr/testify/assert" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" @@ -17,11 +19,18 @@ import ( var identityService identity.Service var cfg config.Service +type MockProtocolSetter struct{} + +func (MockProtocolSetter) InitProtocolForCID(CID identity.CentID) { + // do nothing +} + func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[config.BootstrappedConfigStorage].(config.Service) + ctx[bootstrap.BootstrappedP2PServer] = &MockProtocolSetter{} identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() diff --git a/contextutil/context.go b/contextutil/context.go index 83f932d91..812c44b0f 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/centerrors" @@ -47,13 +49,19 @@ func Tenant(ctx context.Context) (config.TenantConfiguration, error) { } // CentContext updates a context with tenant info using the configstore, must only be used for api handlers -func CentContext(ctx context.Context, config config.Service) (context.Context, error) { - // TODO [multi-tenancy] remove following and read the tenantID from the context - tc, err := config.GetAllTenants() +func CentContext(ctx context.Context, cs config.Service) (context.Context, error) { + tcIDHex := ctx.Value(config.TenantKey).(string) + tcID, err := hexutil.Decode(tcIDHex) + if err != nil { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + + tc, err := cs.GetTenant(tcID) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - ctxHeader, err := NewCentrifugeContext(ctx, tc[0]) + + ctxHeader, err := NewCentrifugeContext(ctx, tc) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } diff --git a/coredocument/processor.go b/coredocument/processor.go index daed38976..5a618c685 100644 --- a/coredocument/processor.go +++ b/coredocument/processor.go @@ -49,8 +49,7 @@ type defaultProcessor struct { identityService identity.Service p2pClient client anchorRepository anchors.AnchorRepository - // TODO [multi-tenancy] replace this with config service - config Config + config Config } // DefaultProcessor returns the default implementation of CoreDocument Processor diff --git a/documents/handler_test.go b/documents/handler_test.go index 884cb190d..08782e903 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -3,9 +3,10 @@ package documents_test import ( - "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -30,7 +31,7 @@ func TestGrpcHandler_CreateDocumentProof(t *testing.T) { doc := &documents.DocumentProof{} service.On("CreateProofs", id, req.Fields).Return(doc, nil) grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - retDoc, _ := grpcHandler.CreateDocumentProof(context.TODO(), req) + retDoc, _ := grpcHandler.CreateDocumentProof(testingconfig.HandlerContext(documents.ConfigService), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) assert.Equal(t, conv, retDoc) @@ -47,7 +48,7 @@ func TestGrpcHandler_CreateDocumentProofUnableToLocateService(t *testing.T) { Fields: []string{"field1"}, } grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) + _, err := grpcHandler.CreateDocumentProof(testingconfig.HandlerContext(documents.ConfigService), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") } @@ -63,7 +64,7 @@ func TestGrpcHandler_CreateDocumentProofInvalidHex(t *testing.T) { Fields: []string{"field1"}, } grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - _, err := grpcHandler.CreateDocumentProof(context.TODO(), req) + _, err := grpcHandler.CreateDocumentProof(testingconfig.HandlerContext(documents.ConfigService), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofs") } @@ -84,7 +85,7 @@ func TestGrpcHandler_CreateDocumentProofForVersion(t *testing.T) { doc := &documents.DocumentProof{DocumentID: utils.RandomSlice(32)} service.On("CreateProofsForVersion", id, version, req.Fields).Return(doc, nil) grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - retDoc, _ := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) + retDoc, _ := grpcHandler.CreateDocumentProofForVersion(testingconfig.HandlerContext(documents.ConfigService), req) service.AssertExpectations(t) conv, _ := documents.ConvertDocProofToClientFormat(doc) assert.Equal(t, conv, retDoc) @@ -102,7 +103,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionUnableToLocateService(t *testi Fields: []string{"field1"}, } grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) + _, err := grpcHandler.CreateDocumentProofForVersion(testingconfig.HandlerContext(documents.ConfigService), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") } @@ -119,7 +120,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForId(t *testing.T) Fields: []string{"field1"}, } grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) + _, err := grpcHandler.CreateDocumentProofForVersion(testingconfig.HandlerContext(documents.ConfigService), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") } @@ -136,7 +137,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForVersion(t *testin Fields: []string{"field1"}, } grpcHandler := documents.GRPCHandler(documents.ConfigService, registry) - _, err := grpcHandler.CreateDocumentProofForVersion(context.TODO(), req) + _, err := grpcHandler.CreateDocumentProofForVersion(testingconfig.HandlerContext(documents.ConfigService), req) assert.NotNil(t, err) service.AssertNotCalled(t, "CreateProofsForVersion") } diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 3f89c7458..abb35e2f8 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -80,7 +82,7 @@ func TestGRPCHandler_Create_derive_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(nil, errors.New("derive failed")).Once() - _, err := h.Create(context.Background(), nil) + _, err := h.Create(testingconfig.HandlerContext(configService), nil) srv.AssertExpectations(t) assert.Error(t, err, "must be non nil") assert.Contains(t, err.Error(), "derive failed") @@ -92,7 +94,7 @@ func TestGRPCHandler_Create_create_fail(t *testing.T) { srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(new(Invoice), nil).Once() srv.On("Create", mock.Anything, mock.Anything).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}} - _, err := h.Create(context.Background(), payload) + _, err := h.Create(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.Error(t, err, "must be non nil") assert.Contains(t, err.Error(), "create failed") @@ -124,7 +126,7 @@ func TestGRPCHandler_Create_DeriveInvoiceResponse_fail(t *testing.T) { srv.On("Create", mock.Anything, mock.Anything).Return(model, uuid.Nil.String(), nil).Once() srv.On("DeriveInvoiceResponse", mock.Anything).Return(nil, errors.New("derive response failed")) payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{Currency: "EUR"}} - _, err := h.Create(context.Background(), payload) + _, err := h.Create(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.Error(t, err, "must be non nil") assert.Contains(t, err.Error(), "derive response failed") @@ -140,7 +142,7 @@ func TestGrpcHandler_Create(t *testing.T) { srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() srv.On("Create", mock.Anything, mock.Anything).Return(model, txID.String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(response, nil) - res, err := h.Create(context.Background(), payload) + res, err := h.Create(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.Nil(t, err, "must be nil") assert.NotNil(t, res, "must be non nil") @@ -154,13 +156,13 @@ func TestGrpcHandler_Get_invalid_input(t *testing.T) { srv := h.service.(*mockService) payload := &clientinvoicepb.GetRequest{Identifier: "invalid"} - res, err := h.Get(context.Background(), payload) + res, err := h.Get(testingconfig.HandlerContext(configService), payload) assert.Nil(t, res) assert.EqualError(t, err, "identifier is an invalid hex string: hex string without 0x prefix") payload.Identifier = identifier srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(nil, errors.New("not found")) - res, err = h.Get(context.Background(), payload) + res, err = h.Get(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.Nil(t, res) assert.EqualError(t, err, "document not found: not found") @@ -176,7 +178,7 @@ func TestGrpcHandler_Get(t *testing.T) { response := &clientinvoicepb.InvoiceResponse{} srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(model, nil) srv.On("DeriveInvoiceResponse", model).Return(response, nil) - res, err := h.Get(context.Background(), payload) + res, err := h.Get(testingconfig.HandlerContext(configService), payload) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Nil(t, err, "must be nil") @@ -188,19 +190,19 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { h := getHandler() srv := h.service.(*mockService) payload := &clientinvoicepb.GetVersionRequest{Identifier: "0x0x", Version: "0x00"} - res, err := h.GetVersion(context.Background(), payload) + res, err := h.GetVersion(testingconfig.HandlerContext(configService), payload) assert.EqualError(t, err, "identifier is invalid: invalid hex string") payload.Version = "0x0x" payload.Identifier = "0x01" - res, err = h.GetVersion(context.Background(), payload) + res, err = h.GetVersion(testingconfig.HandlerContext(configService), payload) assert.EqualError(t, err, "version is invalid: invalid hex string") payload.Version = "0x00" payload.Identifier = "0x01" mockErr := errors.New("not found") srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(nil, mockErr) - res, err = h.GetVersion(context.Background(), payload) + res, err = h.GetVersion(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.EqualError(t, err, "document not found: not found") assert.Nil(t, res) @@ -215,7 +217,7 @@ func TestGrpcHandler_GetVersion(t *testing.T) { response := &clientinvoicepb.InvoiceResponse{} srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(model, nil) srv.On("DeriveInvoiceResponse", model).Return(response, nil) - res, err := h.GetVersion(context.Background(), payload) + res, err := h.GetVersion(testingconfig.HandlerContext(configService), payload) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Nil(t, err) @@ -228,7 +230,7 @@ func TestGrpcHandler_Update_derive_fail(t *testing.T) { srv := h.service.(*mockService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(nil, errors.New("derive error")).Once() - res, err := h.Update(context.Background(), payload) + res, err := h.Update(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "derive error") @@ -239,7 +241,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) model := &mockModel{} - ctx := context.Background() + ctx := testingconfig.HandlerContext(configService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() @@ -254,7 +256,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) model := &mockModel{} - ctx := context.Background() + ctx := testingconfig.HandlerContext(configService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() @@ -270,7 +272,7 @@ func TestGrpcHandler_Update(t *testing.T) { h := getHandler() srv := h.service.(*mockService) model := &mockModel{} - ctx := context.Background() + ctx := testingconfig.HandlerContext(configService) txID := uuid.Must(uuid.NewV4()) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{Header: new(clientinvoicepb.ResponseHeader)} diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 12c8caf81..b585d7554 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -75,7 +77,7 @@ func (m mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clien func TestGRPCHandler_Create(t *testing.T) { h := getHandler() req := testingdocuments.CreatePOPayload() - ctx := context.Background() + ctx := testingconfig.HandlerContext(configService) model := &testingdocuments.MockModel{} // derive fails @@ -129,7 +131,7 @@ func TestGrpcHandler_Update(t *testing.T) { Data: p.Data, Collaborators: p.Collaborators, } - ctx := context.Background() + ctx := testingconfig.HandlerContext(configService) model := &testingdocuments.MockModel{} // derive fails @@ -196,7 +198,7 @@ func TestGrpcHandler_Get(t *testing.T) { response := &clientpopb.PurchaseOrderResponse{} srv.On("GetCurrentVersion", mock.Anything, identifierBytes).Return(model, nil) srv.On("DerivePurchaseOrderResponse", model).Return(response, nil) - res, err := h.Get(context.Background(), payload) + res, err := h.Get(testingconfig.HandlerContext(configService), payload) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Nil(t, err, "must be nil") @@ -208,19 +210,19 @@ func TestGrpcHandler_GetVersion_invalid_input(t *testing.T) { h := getHandler() srv := h.service.(*mockService) payload := &clientpopb.GetVersionRequest{Identifier: "0x0x", Version: "0x00"} - res, err := h.GetVersion(context.Background(), payload) + res, err := h.GetVersion(testingconfig.HandlerContext(configService), payload) assert.EqualError(t, err, "identifier is invalid: invalid hex string") payload.Version = "0x0x" payload.Identifier = "0x01" - res, err = h.GetVersion(context.Background(), payload) + res, err = h.GetVersion(testingconfig.HandlerContext(configService), payload) assert.EqualError(t, err, "version is invalid: invalid hex string") payload.Version = "0x00" payload.Identifier = "0x01" mockErr := errors.New("not found") srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(nil, mockErr) - res, err = h.GetVersion(context.Background(), payload) + res, err = h.GetVersion(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) assert.EqualError(t, err, "document not found: not found") assert.Nil(t, res) @@ -235,7 +237,7 @@ func TestGrpcHandler_GetVersion(t *testing.T) { response := &clientpopb.PurchaseOrderResponse{} srv.On("GetVersion", mock.Anything, []byte{0x01}, []byte{0x00}).Return(model, nil) srv.On("DerivePurchaseOrderResponse", model).Return(response, nil) - res, err := h.GetVersion(context.Background(), payload) + res, err := h.GetVersion(testingconfig.HandlerContext(configService), payload) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Nil(t, err) diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index ebf9610d3..ffa7dbf70 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -80,8 +80,7 @@ type gethClient struct { host *url.URL accounts map[string]*bind.TransactOpts accMu sync.Mutex // accMu to protect accounts - // TODO [multi-tenancy] replace this with config service - config Config + config Config // txMu to ensure one transaction at a time per client txMu sync.Mutex diff --git a/identity/ethid/ethereum_identity.go b/identity/ethid/ethereum_identity.go index cae6a7dd4..dca7dc080 100644 --- a/identity/ethid/ethereum_identity.go +++ b/identity/ethid/ethereum_identity.go @@ -83,7 +83,6 @@ type ethereumIdentity struct { contract contract contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) registryContract registry - // TODO [multi-tenancy] replace this with config service config identity.Config gethClientFinder func() ethereum.Client queue *queue.Server @@ -352,7 +351,6 @@ func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue // ethereumIdentityService implements `Service` type ethereumIdentityService struct { - // TODO [multi-tenancy] replace this with config service config identity.Config factoryContract factory registryContract registry diff --git a/identity/ethid/key_registration_confirmation_task.go b/identity/ethid/key_registration_confirmation_task.go index 80a03b896..c2aacb5b7 100644 --- a/identity/ethid/key_registration_confirmation_task.go +++ b/identity/ethid/key_registration_confirmation_task.go @@ -39,11 +39,10 @@ type keyRegistrationConfirmationTask struct { ctx context.Context filterer keyRegisteredFilterer contract *EthereumIdentityRegistryContract - // TODO [multi-tenancy] replace this with config service - config identity.Config - gethClientFinder func() ethereum.Client - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) - queue *queue.Server + config identity.Config + gethClientFinder func() ethereum.Client + contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) + queue *queue.Server } func newKeyRegistrationConfirmationTask( diff --git a/nft/handler_test.go b/nft/handler_test.go index 1cf4dd97e..2dd449404 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -9,6 +9,8 @@ import ( "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" @@ -31,7 +33,7 @@ func (m *mockPaymentObligationService) MintNFT(ctx context.Context, documentID [ func TestNFTMint_success(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &mockPaymentObligationService{} - mockConfigStore := mockConfigService() + mockConfigStore := mockmockConfigStore() docID, _ := hexutil.Decode(nftMintRequest.Identifier) tokID := big.NewInt(1) @@ -41,14 +43,16 @@ func TestNFTMint_success(t *testing.T) { Return(nftResponse, nil) handler := grpcHandler{mockConfigStore, mockService} - nftMintResponse, err := handler.MintNFT(context.Background(), nftMintRequest) + nftMintResponse, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) mockService.AssertExpectations(t) assert.Nil(t, err, "mint nft should be successful") assert.Equal(t, tokID.String(), nftMintResponse.TokenId, "TokenID should have a dummy value") } -func mockConfigService() *configstore.MockService { +func mockmockConfigStore() *configstore.MockService { mockConfigStore := &configstore.MockService{} + //var tc config.TenantConfiguration = &configstore.TenantConfig{} + mockConfigStore.On("GetTenant", mock.Anything).Return(&configstore.TenantConfig{}, nil) mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{}}, nil) return mockConfigStore } @@ -56,10 +60,10 @@ func mockConfigService() *configstore.MockService { func TestNFTMint_InvalidIdentifier(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.Identifier = "32321" - mockConfigStore := mockConfigService() - mockConfigStore.On("GetAllTenants").Return(context.Background()) + mockConfigStore := mockmockConfigStore() + mockConfigStore.On("GetAllTenants").Return(testingconfig.HandlerContext(mockConfigStore)) handler := grpcHandler{mockConfigStore, &mockPaymentObligationService{}} - _, err := handler.MintNFT(context.Background(), nftMintRequest) + _, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) assert.Error(t, err, "invalid identifier should throw an error") } @@ -71,9 +75,9 @@ func TestNFTMint_ServiceError(t *testing.T) { On("MintNFT", mock.Anything, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). Return(nil, errors.New("service error")) - mockConfigStore := mockConfigService() + mockConfigStore := mockmockConfigStore() handler := grpcHandler{mockConfigStore, mockService} - _, err := handler.MintNFT(context.Background(), nftMintRequest) + _, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) mockService.AssertExpectations(t) assert.NotNil(t, err) } @@ -81,15 +85,15 @@ func TestNFTMint_ServiceError(t *testing.T) { func TestNFTMint_InvalidAddresses(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.RegistryAddress = "0x1234" - mockConfigStore := mockConfigService() + mockConfigStore := mockmockConfigStore() handler := grpcHandler{mockConfigStore, &mockPaymentObligationService{}} - _, err := handler.MintNFT(context.Background(), nftMintRequest) + _, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) assert.Error(t, err, "invalid registry address should throw an error") nftMintRequest = getTestSetupData() nftMintRequest.DepositAddress = "abc" handler = grpcHandler{mockConfigStore, &mockPaymentObligationService{}} - _, err = handler.MintNFT(context.Background(), nftMintRequest) + _, err = handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) assert.Error(t, err, "invalid deposit address should throw an error") } diff --git a/p2p/server.go b/p2p/server.go index 9bf70a910..829db6415 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -85,31 +85,42 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- } s.mes = newP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout(), s.handlerCreator().HandleInterceptor) - tcs, err := s.config.GetAllTenants() + err = s.initProtocols() if err != nil { startupErr <- err return } + + // Start DHT and properly ignore errors :) + _ = runDHT(ctx, s.host, nc.GetBootstrapPeers()) + <-ctx.Done() + +} + +func (s *peer) initProtocols() error { + tcs, err := s.config.GetAllTenants() + if err != nil { + return err + } var protocols []protocol.ID for _, t := range tcs { tid, err := t.GetIdentityID() if err != nil { - startupErr <- err - return + return err } CID, err := identity.ToCentID(tid) if err != nil { - startupErr <- err - return + return err } protocols = append(protocols, p2pcommon.ProtocolForCID(CID)) } s.mes.init(protocols...) + return nil +} - // Start DHT and properly ignore errors :) - _ = runDHT(ctx, s.host, nc.GetBootstrapPeers()) - <-ctx.Done() - +func (s *peer) InitProtocolForCID(CID identity.CentID) { + p := p2pcommon.ProtocolForCID(CID) + s.mes.init(p) } func (s *peer) createSigningKey(pubKey, privKey string) (priv crypto.PrivKey, pub crypto.PubKey, err error) { diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 937c149db..b05be2df6 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/stretchr/testify/assert" @@ -172,3 +174,11 @@ func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg confi assert.Nil(t, err) return contextHeader } + +func HandlerContext(service config.Service) context.Context { + tcs, _ := service.GetAllTenants() + cid, _ := tcs[0].GetIdentityID() + cidHex := hexutil.Encode(cid) + ctx := context.WithValue(context.Background(), config.TenantKey, cidHex) + return ctx +} diff --git a/testingutils/setup.go b/testingutils/setup.go index 78312b68d..4c03a3689 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -135,7 +135,7 @@ func SetupSmartContractAddresses(cfg config.Configuration, sca *config.SmartCont func BuildIntegrationTestingContext() map[string]interface{} { projDir := getProjectDir() StartPOAGeth() - RunSmartContractMigrations() + //RunSmartContractMigrations() addresses := GetSmartContractAddresses() cfg := LoadTestConfig() cfg.Set("keys.signing.publicKey", fmt.Sprintf("%s/build/resources/signingKey.pub.pem", projDir)) diff --git a/testworld/config_test.go b/testworld/config_test.go index 34c695a66..149237b43 100644 --- a/testworld/config_test.go +++ b/testworld/config_test.go @@ -12,23 +12,25 @@ func TestConfig_Happy(t *testing.T) { charlie := doctorFord.getHostTestSuite(t, "Charlie") // check charlies node config - res := getNodeConfig(charlie.httpExpect, http.StatusOK) + res := getNodeConfig(charlie.httpExpect, charlie.id.String(), http.StatusOK) tenantID := res.Value("main_identity").Path("$.identity_id").String().NotEmpty() tenantID.Equal(charlie.id.String()) // check charlies main tenant config - res = getTenantConfig(charlie.httpExpect, http.StatusOK, charlie.id.String()) + res = getAccount(charlie.httpExpect, charlie.id.String(), http.StatusOK, charlie.id.String()) tenantID2 := res.Value("identity_id").String().NotEmpty() tenantID2.Equal(charlie.id.String()) // check charlies all tenant configs - res = getAllTenantConfigs(charlie.httpExpect, http.StatusOK) + res = getAllAccounts(charlie.httpExpect, charlie.id.String(), http.StatusOK) tenants := res.Value("data").Array() - tenants.Length().Equal(1) - tenants.Element(0).Path("$.identity_id").String().NotEmpty().Equal(charlie.id.String()) + tids := getAccounts(tenants) + if _, ok := tids[charlie.id.String()]; !ok { + t.Error("Charlies id needs to exist in the accounts list") + } // generate a tenant within Charlie - res = generateTenant(charlie.httpExpect, http.StatusOK) + res = generateAccount(charlie.httpExpect, charlie.id.String(), http.StatusOK) tcID := res.Value("identity_id").String().NotEmpty() tcID.NotEqual(charlie.id.String()) } diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 062eac5fa..9b9ea239a 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -12,37 +12,153 @@ import ( func TestHost_AddExternalCollaborator(t *testing.T) { t.Parallel() tests := []struct { - name string - docType string + name string + docType string + testType testType }{ { - "Invoice_AddExternalCollaborator", + "Invoice_multiHost_AddExternalCollaborator", typeInvoice, + multiHost, + }, + { + "Invoice_withinhost_AddExternalCollaborator", + typeInvoice, + withinHost, + }, + { + "Invoice_multiHostMultiAccount_AddExternalCollaborator", + typeInvoice, + multiHostMultiAccount, }, { "PO_AddExternalCollaborator", typePO, + multiHost, }, } for _, test := range tests { - t.Run(test.docType, func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { t.Parallel() - addExternalCollaborator(t, test.docType) + switch test.testType { + case multiHost: + addExternalCollaborator(t, test.docType) + case multiHostMultiAccount: + addExternalCollaborator_multiHostMultiAccount(t, test.docType) + case withinHost: + addExternalCollaborator_withinHost(t, test.docType) + } }) } } +func addExternalCollaborator_withinHost(t *testing.T, documentType string) { + // TODO remove this when we have retry for tasks + time.Sleep(time.Duration(rand.Intn(10)) * time.Second) + bob := doctorFord.getHostTestSuite(t, "Bob") + accounts := doctorFord.getHost("Bob").accounts + a := accounts[0] + b := accounts[1] + c := accounts[2] + + // a shares document with b first + res := createDocument(bob.httpExpect, a, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{b})) + txID := getTransactionID(t, res) + waitTillStatus(t, bob.httpExpect, a, txID, "success") + + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + + params := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "USD", + } + getDocumentAndCheck(bob.httpExpect, a, documentType, params) + getDocumentAndCheck(bob.httpExpect, b, documentType, params) + nonExistingDocumentCheck(bob.httpExpect, c, documentType, params) + + // Bob updates invoice and shares with Charlie as well + res = updateDocument(bob.httpExpect, bob.id.String(), documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{a, c})) + txID = getTransactionID(t, res) + waitTillStatus(t, bob.httpExpect, bob.id.String(), txID, "success") + + docIdentifier = getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + params["currency"] = "EUR" + getDocumentAndCheck(bob.httpExpect, a, documentType, params) + getDocumentAndCheck(bob.httpExpect, b, documentType, params) + getDocumentAndCheck(bob.httpExpect, c, documentType, params) +} + +func addExternalCollaborator_multiHostMultiAccount(t *testing.T, documentType string) { + // TODO remove this when we have retry for tasks + time.Sleep(time.Duration(rand.Intn(10)) * time.Second) + alice := doctorFord.getHostTestSuite(t, "Alice") + bob := doctorFord.getHostTestSuite(t, "Bob") + accounts := doctorFord.getHost("Bob").accounts + a := accounts[0] + b := accounts[1] + c := accounts[2] + charlie := doctorFord.getHostTestSuite(t, "Charlie") + accounts2 := doctorFord.getHost("Charlie").accounts + d := accounts2[0] + e := accounts2[1] + f := accounts2[2] + + // Alice shares document with Bobs accounts a and b + res := createDocument(alice.httpExpect, alice.id.String(), documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{a, b})) + txID := getTransactionID(t, res) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") + + docIdentifier := getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + + params := map[string]interface{}{ + "document_id": docIdentifier, + "currency": "USD", + } + getDocumentAndCheck(alice.httpExpect, alice.id.String(), documentType, params) + getDocumentAndCheck(bob.httpExpect, a, documentType, params) + getDocumentAndCheck(bob.httpExpect, b, documentType, params) + nonExistingDocumentCheck(bob.httpExpect, c, documentType, params) + + // Bob updates invoice and shares with bobs account c as well using account a and to accounts d and e of Charlie + res = updateDocument(bob.httpExpect, a, documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{alice.id.String(), b, c, d, e})) + txID = getTransactionID(t, res) + waitTillStatus(t, bob.httpExpect, a, txID, "success") + + docIdentifier = getDocumentIdentifier(t, res) + if docIdentifier == "" { + t.Error("docIdentifier empty") + } + params["currency"] = "EUR" + getDocumentAndCheck(alice.httpExpect, alice.id.String(), documentType, params) + // bobs accounts all have the document now + getDocumentAndCheck(bob.httpExpect, a, documentType, params) + getDocumentAndCheck(bob.httpExpect, b, documentType, params) + getDocumentAndCheck(bob.httpExpect, c, documentType, params) + getDocumentAndCheck(charlie.httpExpect, d, documentType, params) + getDocumentAndCheck(charlie.httpExpect, e, documentType, params) + nonExistingDocumentCheck(charlie.httpExpect, f, documentType, params) +} + func addExternalCollaborator(t *testing.T, documentType string) { // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(5)) * time.Second) + time.Sleep(time.Duration(rand.Intn(10)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") // Alice shares document with Bob first - res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) + res := createDocument(alice.httpExpect, alice.id.String(), documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) txID := getTransactionID(t, res) - waitTillSuccess(t, alice.httpExpect, txID) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -53,22 +169,23 @@ func addExternalCollaborator(t *testing.T, documentType string) { "document_id": docIdentifier, "currency": "USD", } - getDocumentAndCheck(alice.httpExpect, documentType, params) - getDocumentAndCheck(bob.httpExpect, documentType, params) + getDocumentAndCheck(alice.httpExpect, alice.id.String(), documentType, params) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), documentType, params) + nonExistingDocumentCheck(charlie.httpExpect, charlie.id.String(), documentType, params) // Bob updates invoice and shares with Charlie as well - res = updateDocument(bob.httpExpect, documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{alice.id.String(), charlie.id.String()})) + res = updateDocument(bob.httpExpect, bob.id.String(), documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{alice.id.String(), charlie.id.String()})) txID = getTransactionID(t, res) - waitTillSuccess(t, bob.httpExpect, txID) + waitTillStatus(t, bob.httpExpect, bob.id.String(), txID, "success") docIdentifier = getDocumentIdentifier(t, res) if docIdentifier == "" { t.Error("docIdentifier empty") } params["currency"] = "EUR" - getDocumentAndCheck(alice.httpExpect, documentType, params) - getDocumentAndCheck(bob.httpExpect, documentType, params) - getDocumentAndCheck(charlie.httpExpect, documentType, params) + getDocumentAndCheck(alice.httpExpect, alice.id.String(), documentType, params) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), documentType, params) + getDocumentAndCheck(charlie.httpExpect, charlie.id.String(), documentType, params) } func TestHost_CollaboratorTimeOut(t *testing.T) { @@ -87,9 +204,9 @@ func collaboratorTimeOut(t *testing.T, documentType string) { bob := doctorFord.getHostTestSuite(t, "Bob") // Kenny shares a document with Bob - response := createDocument(kenny.httpExpect, documentType, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) + response := createDocument(kenny.httpExpect, kenny.id.String(), documentType, http.StatusOK, defaultInvoicePayload([]string{bob.id.String()})) txID := getTransactionID(t, response) - waitTillSuccess(t, kenny.httpExpect, txID) + waitTillStatus(t, kenny.httpExpect, kenny.id.String(), txID, "success") // check if Bob and Kenny received the document docIdentifier := getDocumentIdentifier(t, response) @@ -97,31 +214,31 @@ func collaboratorTimeOut(t *testing.T, documentType string) { "document_id": docIdentifier, "currency": "USD", } - getDocumentAndCheck(kenny.httpExpect, documentType, paramsV1) - getDocumentAndCheck(bob.httpExpect, documentType, paramsV1) + getDocumentAndCheck(kenny.httpExpect, kenny.id.String(), documentType, paramsV1) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), documentType, paramsV1) // Kenny gets killed kenny.host.kill() - // Bob updates and sends to Alice + // Bob updates and sends to Kenny updatedPayload := updatedDocumentPayload(documentType, []string{kenny.id.String()}) - // Bob will anchor the document without Alice signature but will receive an error because kenny is dead - response = updateDocument(bob.httpExpect, documentType, http.StatusInternalServerError, docIdentifier, updatedPayload) + // Bob will anchor the document without Kennys signature + response = updateDocument(bob.httpExpect, bob.id.String(), documentType, http.StatusOK, docIdentifier, updatedPayload) txID = getTransactionID(t, response) - waitTillSuccess(t, bob.httpExpect, txID) + waitTillStatus(t, bob.httpExpect, bob.id.String(), txID, "failed") // check if bob saved the updated document paramsV2 := map[string]interface{}{ "document_id": docIdentifier, "currency": "EUR", } - getDocumentAndCheck(bob.httpExpect, documentType, paramsV2) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), documentType, paramsV2) // bring Kenny back to life doctorFord.reLive(t, kenny.name) // Kenny should NOT have latest version - getDocumentAndCheck(kenny.httpExpect, documentType, paramsV1) + getDocumentAndCheck(kenny.httpExpect, kenny.id.String(), documentType, paramsV1) } diff --git a/testworld/httputils.go b/testworld/httputils.go index 714732bd3..c7d451705 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -25,12 +25,10 @@ func createInsecureClientWithExpect(t *testing.T, baseURL string) *httpexpect.Ex return httpexpect.WithConfig(config) } -func getDocumentAndCheck(e *httpexpect.Expect, documentType string, params map[string]interface{}) *httpexpect.Value { +func getDocumentAndCheck(e *httpexpect.Expect, auth string, documentType string, params map[string]interface{}) *httpexpect.Value { docIdentifier := params["document_id"].(string) - objGet := e.GET("/"+documentType+"/"+docIdentifier). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). + objGet := addCommonHeaders(e.GET("/"+documentType+"/"+docIdentifier), auth). Expect().Status(http.StatusOK).JSON().NotNull() objGet.Path("$.header.document_id").String().Equal(docIdentifier) objGet.Path("$.data.currency").String().Equal(params["currency"].(string)) @@ -38,19 +36,23 @@ func getDocumentAndCheck(e *httpexpect.Expect, documentType string, params map[s return objGet } -func createDocument(e *httpexpect.Expect, documentType string, status int, payload map[string]interface{}) *httpexpect.Object { - obj := e.POST("/"+documentType). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func nonExistingDocumentCheck(e *httpexpect.Expect, auth string, documentType string, params map[string]interface{}) *httpexpect.Value { + docIdentifier := params["document_id"].(string) + + objGet := addCommonHeaders(e.GET("/"+documentType+"/"+docIdentifier), auth). + Expect().Status(500).JSON().NotNull() + return objGet +} + +func createDocument(e *httpexpect.Expect, auth string, documentType string, status int, payload map[string]interface{}) *httpexpect.Object { + obj := addCommonHeaders(e.POST("/"+documentType), auth). WithJSON(payload). Expect().Status(status).JSON().Object() return obj } -func updateDocument(e *httpexpect.Expect, documentType string, status int, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { - obj := e.PUT("/"+documentType+"/"+docIdentifier). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func updateDocument(e *httpexpect.Expect, auth string, documentType string, status int, docIdentifier string, payload map[string]interface{}) *httpexpect.Object { + obj := addCommonHeaders(e.PUT("/"+documentType+"/"+docIdentifier), auth). WithJSON(payload). Expect().Status(status).JSON().Object() return obj @@ -73,10 +75,8 @@ func getTransactionID(t *testing.T, resp *httpexpect.Object) string { return txID } -func mintNFT(e *httpexpect.Expect, httpStatus int, payload map[string]interface{}) *httpexpect.Object { - resp := e.POST("/token/mint"). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func mintNFT(e *httpexpect.Expect, auth string, httpStatus int, payload map[string]interface{}) *httpexpect.Object { + resp := addCommonHeaders(e.POST("/token/mint"), auth). WithJSON(payload). Expect().Status(httpStatus) @@ -84,43 +84,33 @@ func mintNFT(e *httpexpect.Expect, httpStatus int, payload map[string]interface{ return httpObj } -func getProof(e *httpexpect.Expect, httpStatus int, documentID string, payload map[string]interface{}) *httpexpect.Object { - resp := e.POST("/document/"+documentID+"/proof"). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func getProof(e *httpexpect.Expect, auth string, httpStatus int, documentID string, payload map[string]interface{}) *httpexpect.Object { + resp := addCommonHeaders(e.POST("/document/"+documentID+"/proof"), auth). WithJSON(payload). Expect().Status(httpStatus) return resp.JSON().Object() } -func getNodeConfig(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { - resp := e.GET("/config/node"). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func getNodeConfig(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { + resp := addCommonHeaders(e.GET("/config/node"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } -func getTenantConfig(e *httpexpect.Expect, httpStatus int, identifier string) *httpexpect.Object { - resp := e.GET("/config/tenants/"+identifier). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func getAccount(e *httpexpect.Expect, auth string, httpStatus int, identifier string) *httpexpect.Object { + resp := addCommonHeaders(e.GET("/config/tenants/"+identifier), auth). Expect().Status(httpStatus) return resp.JSON().Object() } -func getAllTenantConfigs(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { - resp := e.GET("/config/tenants"). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func getAllAccounts(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { + resp := addCommonHeaders(e.GET("/config/tenants"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } -func generateTenant(e *httpexpect.Expect, httpStatus int) *httpexpect.Object { - resp := e.POST("/config/tenants/generate"). - WithHeader("accept", "application/json"). - WithHeader("Content-Type", "application/json"). +func generateAccount(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { + resp := addCommonHeaders(e.POST("/config/tenants/generate"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } @@ -134,9 +124,9 @@ func createInsecureClient() *http.Client { return &http.Client{Transport: tr} } -func waitTillSuccess(t *testing.T, e *httpexpect.Expect, txID string) { +func waitTillStatus(t *testing.T, e *httpexpect.Expect, auth string, txID string, expectedStatus string) { for { - resp := e.GET("/transactions/" + txID).Expect().Status(200).JSON().Object() + resp := addCommonHeaders(e.GET("/transactions/"+txID), auth).Expect().Status(200).JSON().Object() status := resp.Path("$.status").String().Raw() if status == "pending" { @@ -144,10 +134,28 @@ func waitTillSuccess(t *testing.T, e *httpexpect.Expect, txID string) { continue } - if status == "failed" { + if status == expectedStatus { + break + } else { t.Error(resp.Path("$.message").String().Raw()) } break } } + +func addCommonHeaders(req *httpexpect.Request, auth string) *httpexpect.Request { + return req. + WithHeader("accept", "application/json"). + WithHeader("Content-Type", "application/json"). + WithHeader("authorization", auth) +} + +func getAccounts(accounts *httpexpect.Array) map[string]string { + tids := make(map[string]string) + for i := 0; i < int(accounts.Length().Raw()); i++ { + val := accounts.Element(i).Path("$.identity_id").String().NotEmpty().Raw() + tids[val] = val + } + return tids +} diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 1e1fcf277..fc60722a5 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -30,10 +30,10 @@ func paymentObligationMint(t *testing.T, documentType string) { bob := doctorFord.getHostTestSuite(t, "Bob") // Alice shares document with Bob - res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultNFTPayload(documentType, []string{bob.id.String()})) + res := createDocument(alice.httpExpect, alice.id.String(), documentType, http.StatusOK, defaultNFTPayload(documentType, []string{bob.id.String()})) txID := getTransactionID(t, res) - waitTillSuccess(t, alice.httpExpect, txID) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -44,8 +44,8 @@ func paymentObligationMint(t *testing.T, documentType string) { "document_id": docIdentifier, "currency": "USD", } - getDocumentAndCheck(alice.httpExpect, documentType, params) - getDocumentAndCheck(bob.httpExpect, documentType, params) + getDocumentAndCheck(alice.httpExpect, alice.id.String(), documentType, params) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), documentType, params) proofPrefix := documentType if proofPrefix == typePO { @@ -67,9 +67,9 @@ func paymentObligationMint(t *testing.T, documentType string) { }, } - response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) txID = getTransactionID(t, response) - waitTillSuccess(t, alice.httpExpect, txID) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") assert.Nil(t, err, "mintNFT should be successful") assert.True(t, len(response.Value("token_id").String().Raw()) > 0, "successful tokenId should have length 77") @@ -116,7 +116,7 @@ func TestPaymentObligationMint_errors(t *testing.T) { for _, test := range tests { t.Run(test.errorMsg, func(t *testing.T) { t.Parallel() - response, err := alice.host.mintNFT(alice.httpExpect, test.httpStatus, test.payload) + response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) assert.Nil(t, err, "it should be possible to call the API endpoint") response.Value("error").String().Contains(test.errorMsg) }) diff --git a/testworld/park.go b/testworld/park.go index 86d46b59f..70b3ef5c3 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -31,11 +31,12 @@ var log = logging.Logger("host") var hostConfig = []struct { name string apiPort, p2pPort int64 + multiAccount bool }{ - {"Alice", 8084, 38204}, - {"Bob", 8085, 38205}, - {"Charlie", 8086, 38206}, - {"Kenny", 8087, 38207}, + {"Alice", 8084, 38204, false}, + {"Bob", 8085, 38205, true}, + {"Charlie", 8086, 38206, true}, + {"Kenny", 8087, 38207, false}, } const defaultP2PTimeout = "10s" @@ -108,7 +109,7 @@ func (r *hostManager) startHost(name string) { func (r *hostManager) init(createConfig bool) error { r.cancCtx, r.canc = context.WithCancel(context.Background()) - r.bernard = r.createHost("Bernard", defaultP2PTimeout, 8081, 38201, createConfig, nil) + r.bernard = r.createHost("Bernard", defaultP2PTimeout, 8081, 38201, createConfig, false, nil) err := r.bernard.init() if err != nil { return err @@ -128,7 +129,7 @@ func (r *hostManager) init(createConfig bool) error { // start hosts for _, h := range hostConfig { - r.niceHosts[h.name] = r.createHost(h.name, defaultP2PTimeout, h.apiPort, h.p2pPort, createConfig, []string{bootnode}) + r.niceHosts[h.name] = r.createHost(h.name, defaultP2PTimeout, h.apiPort, h.p2pPort, createConfig, h.multiAccount, []string{bootnode}) err := r.niceHosts[h.name].init() if err != nil { @@ -148,6 +149,10 @@ func (r *hostManager) init(createConfig bool) error { return err } fmt.Printf("CentID for %s is %s \n", name, i) + if createConfig { + _ = host.createAccounts(r.getHostTestSuite(&testing.T{}, host.name).httpExpect) + } + _ = host.loadAccounts(r.getHostTestSuite(&testing.T{}, host.name).httpExpect) } return nil } @@ -163,7 +168,7 @@ func (r *hostManager) stop() { r.canc() } -func (r *hostManager) createHost(name, p2pTimeout string, apiPort, p2pPort int64, createConfig bool, bootstraps []string) *host { +func (r *hostManager) createHost(name, p2pTimeout string, apiPort, p2pPort int64, createConfig, multiAccount bool, bootstraps []string) *host { return newHost( name, r.ethNodeUrl, @@ -174,6 +179,7 @@ func (r *hostManager) createHost(name, p2pTimeout string, apiPort, p2pPort int64 apiPort, p2pPort, bootstraps, r.txPoolAccess, createConfig, + multiAccount, r.contractAddresses, ) } @@ -202,13 +208,15 @@ type host struct { node *node.Node canc context.CancelFunc createConfig bool + multiAccount bool + accounts []string } func newHost( name, ethNodeUrl, accountKeyPath, accountPassword, network, p2pTimeout string, apiPort, p2pPort int64, bootstraps []string, - txPoolAccess, createConfig bool, + txPoolAccess, createConfig, multiAccount bool, smartContractAddrs *config.SmartContractAddresses, ) *host { return &host{ @@ -225,6 +233,7 @@ func newHost( smartContractAddrs: smartContractAddrs, dir: "peerconfigs/" + name, createConfig: createConfig, + multiAccount: multiAccount, } } @@ -329,8 +338,32 @@ func (h *host) isLive(softTimeOut time.Duration) (bool, error) { } } -func (h *host) mintNFT(e *httpexpect.Expect, status int, inv map[string]interface{}) (*httpexpect.Object, error) { - return mintNFT(e, status, inv), nil +func (h *host) mintNFT(e *httpexpect.Expect, auth string, status int, inv map[string]interface{}) (*httpexpect.Object, error) { + return mintNFT(e, auth, status, inv), nil +} + +func (h *host) createAccounts(e *httpexpect.Expect) error { + if !h.multiAccount { + return nil + } + // create 3 accounts + for i := 0; i < 3; i++ { + res := generateAccount(e, h.identity.CentID().String(), http.StatusOK) + res.Value("identity_id").String().NotEmpty() + } + return nil +} + +func (h *host) loadAccounts(e *httpexpect.Expect) error { + res := getAllAccounts(e, h.identity.CentID().String(), http.StatusOK) + tenants := res.Value("data").Array() + tids := getAccounts(tenants) + keys := make([]string, 0, len(tids)) + for k := range tids { + keys = append(keys, k) + } + h.accounts = keys + return nil } func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { diff --git a/testworld/park_test.go b/testworld/park_test.go index a4cff665f..8840d777e 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -15,9 +15,9 @@ func TestHost_Happy(t *testing.T) { charlie := doctorFord.getHostTestSuite(t, "Charlie") // alice shares a document with bob and charlie - res := createDocument(alice.httpExpect, typeInvoice, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) + res := createDocument(alice.httpExpect, alice.id.String(), typeInvoice, http.StatusOK, defaultInvoicePayload([]string{bob.id.String(), charlie.id.String()})) txID := getTransactionID(t, res) - waitTillSuccess(t, alice.httpExpect, txID) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") docIdentifier := getDocumentIdentifier(t, res) @@ -28,8 +28,8 @@ func TestHost_Happy(t *testing.T) { "document_id": docIdentifier, "currency": "USD", } - getDocumentAndCheck(alice.httpExpect, typeInvoice, params) - getDocumentAndCheck(bob.httpExpect, typeInvoice, params) - getDocumentAndCheck(charlie.httpExpect, typeInvoice, params) + getDocumentAndCheck(alice.httpExpect, alice.id.String(), typeInvoice, params) + getDocumentAndCheck(bob.httpExpect, bob.id.String(), typeInvoice, params) + getDocumentAndCheck(charlie.httpExpect, charlie.id.String(), typeInvoice, params) fmt.Println("Host test success") } diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 742541aab..191f6dbc1 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -3,8 +3,10 @@ package testworld import ( + "math/rand" "net/http" "testing" + "time" "github.com/gavv/httpexpect" ) @@ -22,13 +24,15 @@ func TestProofWithMultipleFields_po_successful(t *testing.T) { } func proofWithMultipleFields_successful(t *testing.T, documentType string) { + // TODO remove this when we have retry for tasks + time.Sleep(time.Duration(rand.Intn(5)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") // Alice shares a document with Bob - res := createDocument(alice.httpExpect, documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) + res := createDocument(alice.httpExpect, alice.id.String(), documentType, http.StatusOK, defaultDocumentPayload(documentType, []string{bob.id.String()})) txID := getTransactionID(t, res) - waitTillSuccess(t, alice.httpExpect, txID) + waitTillStatus(t, alice.httpExpect, alice.id.String(), txID, "success") docIdentifier := getDocumentIdentifier(t, res) if docIdentifier == "" { @@ -37,8 +41,8 @@ func proofWithMultipleFields_successful(t *testing.T, documentType string) { proofPayload := defaultProofPayload(documentType) - proofFromAlice := getProof(alice.httpExpect, http.StatusOK, docIdentifier, proofPayload) - proofFromBob := getProof(bob.httpExpect, http.StatusOK, docIdentifier, proofPayload) + proofFromAlice := getProof(alice.httpExpect, alice.id.String(), http.StatusOK, docIdentifier, proofPayload) + proofFromBob := getProof(bob.httpExpect, bob.id.String(), http.StatusOK, docIdentifier, proofPayload) checkProof(proofFromAlice, documentType, docIdentifier) checkProof(proofFromBob, documentType, docIdentifier) diff --git a/testworld/start_test.go b/testworld/start_test.go index 1f1b918b8..7cef275cb 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -11,6 +11,14 @@ import ( "github.com/centrifuge/go-centrifuge/config" ) +type testType string + +const ( + withinHost testType = "withinHost" + multiHost testType = "multiHost" + multiHostMultiAccount testType = "multiHostMultiAccount" +) + var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 // Adjust these based on local testing requirments, please revert for CI server diff --git a/transactions/handler.go b/transactions/handler.go index 2ac312938..43afb80ab 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -4,11 +4,11 @@ import ( "context" "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/identity" - + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) @@ -18,6 +18,8 @@ const ErrInvalidTransactionID = errors.Error("Invalid Transaction ID") // ErrInvalidTenantID error for Invalid tenant ID. const ErrInvalidTenantID = errors.Error("Invalid Tenant ID") +var apiLog = logging.Logger("transaction-api") + // GRPCHandler returns an implementation of the TransactionServiceServer func GRPCHandler(srv Service, configService config.Service) transactionspb.TransactionServiceServer { return grpcHandler{srv: srv, configService: configService} @@ -31,22 +33,28 @@ type grpcHandler struct { // GetTransactionStatus returns transaction status of the given transaction id. func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactionspb.TransactionStatusRequest) (*transactionspb.TransactionStatusResponse, error) { - // TODO [multi-tenancy] use the tenant ID in the context for this - tcs, err := h.configService.GetAllTenants() - if err != nil || len(tcs) == 0 { - return nil, ErrInvalidTenantID + ctxHeader, err := contextutil.CentContext(ctx, h.configService) + if err != nil { + apiLog.Error(err) + return nil, err } + id := uuid.FromStringOrNil(req.TransactionId) if id == uuid.Nil { return nil, ErrInvalidTransactionID } - tid, err := tcs[0].GetIdentityID() + tc, err := contextutil.Tenant(ctxHeader) + if err != nil { + return nil, ErrInvalidTenantID + } + + tid, err := tc.GetIdentityID() if err != nil { return nil, ErrInvalidTenantID } cid, err := identity.ToCentID(tid) - if err != nil || len(tcs) == 0 { + if err != nil { return nil, ErrInvalidTenantID } diff --git a/transactions/handler_test.go b/transactions/handler_test.go index 3fdf3eda2..dd477cedb 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -3,9 +3,10 @@ package transactions import ( - "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" @@ -19,7 +20,7 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { cService := ctx[config.BootstrappedConfigStorage].(config.Service) h := GRPCHandler(ctx[BootstrappedService].(Service), cService) req := new(transactionspb.TransactionStatusRequest) - ctxl := context.Background() + ctxl := testingconfig.HandlerContext(cService) // empty ID res, err := h.GetTransactionStatus(ctxl, req) From ce9b0ce1fc41ec915430bb91bab089649d25b7c7 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 16 Jan 2019 09:54:26 +0100 Subject: [PATCH 135/220] P2P Key check (#648) * Added signature to header + handshake validation * fix tests * address comments * added eth key check * fix integration test * Remove signature * Remove signature * typo * fix pk --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- p2p/common/protocol.go | 10 -- p2p/common/protocol_test.go | 2 +- p2p/receiver/handler.go | 9 +- p2p/receiver/handler_integration_test.go | 46 ++++++++- p2p/receiver/handler_test.go | 43 +++++---- p2p/receiver/validator.go | 72 +++++++------- p2p/receiver/validator_test.go | 114 ++++++++++------------- 9 files changed, 159 insertions(+), 143 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 8546c404e..593ec870f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:68feb6f4b546c63e2b1089484d8905d46389a47af9858434a5636438ff16c09e" + digest = "1:3d0c4f984f055ca85e5d2d74ac26413644ca894279dc6d3369cd845041afe63e" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "1a7c385dace67bd54096f2c8379fab514f2a41d3" + revision = "e9b3e7ce470fd8e11d29450fcdd49873ae102dc7" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" diff --git a/Gopkg.toml b/Gopkg.toml index c91c2d022..b0df5c831 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "1a7c385dace67bd54096f2c8379fab514f2a41d3" + revision = "e9b3e7ce470fd8e11d29450fcdd49873ae102dc7" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go index 90be5a380..1d7c8a997 100644 --- a/p2p/common/protocol.go +++ b/p2p/common/protocol.go @@ -5,8 +5,6 @@ import ( "fmt" "strings" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" @@ -124,14 +122,6 @@ func PrepareP2PEnvelope(ctx context.Context, networkID uint32, messageType Messa Body: body, } - signRequest, err := proto.Marshal(envelope) - if err != nil { - return nil, err - } - - signKeys := self.Keys[identity.KeyPurposeSigning] - envelope.Header.Signature = crypto.Sign(self.ID[:], signKeys.PrivateKey, signKeys.PublicKey, signRequest) - marshalledRequest, err := proto.Marshal(envelope) if err != nil { return nil, err diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index fa4d67416..7e5d4f291 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -114,5 +114,5 @@ func TestPrepareP2PEnvelope(t *testing.T) { assert.NotNil(t, p2pEnv) dataEnv, err := ResolveDataEnvelope(p2pEnv) assert.NoError(t, err) - assert.NotNil(t, dataEnv.Header.Signature) + assert.NotNil(t, dataEnv) } diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index c2495c7eb..534db3b33 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -3,6 +3,8 @@ package receiver import ( "context" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/p2p/common" @@ -82,7 +84,12 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - err = srv.handshakeValidator.Validate(envelope) + fromID, err := identity.ToCentID(envelope.Header.SenderId) + if err != nil { + return convertToErrorEnvelop(err) + } + + err = srv.handshakeValidator.Validate(envelope.Header, &fromID, &peer) if err != nil { return convertToErrorEnvelop(err) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 008d7f81a..5b8b0ff0d 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -5,6 +5,13 @@ package receiver_test import ( "context" "flag" + + "github.com/centrifuge/go-centrifuge/contextutil" + cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/golang/protobuf/proto" + "os" "testing" @@ -39,13 +46,14 @@ var ( anchorRepo anchors.AnchorRepository cfg config.Configuration idService identity.Service + cfgService config.Service ) func TestMain(m *testing.M) { flag.Parse() ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) + cfgService = ctx[config.BootstrappedConfigStorage].(config.Service) registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) @@ -56,6 +64,33 @@ func TestMain(m *testing.M) { os.Exit(result) } +func TestHandler_HandleInterceptorReqSignature(t *testing.T) { + centID := createIdentity(t) + ctxh := testingconfig.CreateTenantContext(t, cfg) + tc, err := contextutil.Tenant(ctxh) + _, err = cfgService.CreateTenant(tc) + assert.NoError(t, err) + doc := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(doc) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, req) + + pub, _ := cfg.GetSigningKeyPair() + publicKey, err := cented25519.GetPublicSigningKey(pub) + assert.NoError(t, err) + var bPk [32]byte + copy(bPk[:], publicKey) + peerID, err := cented25519.PublicKeyToP2PKey(bPk) + assert.NoError(t, err) + + p2pResp, err := handler.HandleInterceptor(ctxh, peerID, p2pcommon.ProtocolForCID(centID), p2pEnv) + assert.Nil(t, err, "must be nil") + assert.NotNil(t, p2pResp, "must be non nil") + resp := resolveSignatureResponse(t, p2pResp) + assert.NotNil(t, resp.Signature.Signature, "must be non nil") + sig := resp.Signature + assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") +} + func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) @@ -269,3 +304,12 @@ func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentR func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureRequest { return &p2ppb.SignatureRequest{Document: doc} } + +func resolveSignatureResponse(t *testing.T, p2pEnv *protocolpb.P2PEnvelope) *p2ppb.SignatureResponse { + signResp := new(p2ppb.SignatureResponse) + dataEnv, err := p2pcommon.ResolveDataEnvelope(p2pEnv) + assert.NoError(t, err) + err = proto.Unmarshal(dataEnv.Body, signResp) + assert.NoError(t, err) + return signResp +} diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index b9a4348f4..b28310bc8 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -4,6 +4,7 @@ package receiver import ( "context" + "crypto/rand" "os" "testing" @@ -12,9 +13,6 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -38,6 +36,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/transactions" "github.com/golang/protobuf/ptypes/any" + "github.com/libp2p/go-libp2p-crypto" libp2pPeer "github.com/libp2p/go-libp2p-peer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -49,6 +48,7 @@ var ( coreDoc = testingcoredocument.GenerateCoreDocument() cfg config.Configuration mockIDService *testingcommons.MockIDService + defaultPID libp2pPeer.ID ) func TestMain(m *testing.M) { @@ -68,6 +68,8 @@ func TestMain(m *testing.M) { cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) mockIDService = &testingcommons.MockIDService{} + _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) + defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil) handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID(), mockIDService)) result := m.Run() @@ -153,19 +155,12 @@ func TestHandler_HandleInterceptor_UnsupportedMessageType(t *testing.T) { // Manipulate message type in Header + Signature dataEnv, _ := p2pcommon.ResolveDataEnvelope(p2pEnv) dataEnv.Header.Type = "UnsupportedType" - dataEnv.Header.Signature = nil - signRequest, err := proto.Marshal(dataEnv) - assert.NoError(t, err) - self, err := contextutil.Self(ctx) - assert.NoError(t, err) - signKeys := self.Keys[identity.KeyPurposeSigning] - dataEnv.Header.Signature = crypto.Sign(self.ID[:], signKeys.PrivateKey, signKeys.PublicKey, signRequest) marshalledRequest, err := proto.Marshal(dataEnv) assert.NoError(t, err) p2pEnv = &protocolpb.P2PEnvelope{Body: marshalledRequest} id, _ := cfg.GetIdentityID() - resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "MessageType [UnsupportedType] not found") assert.Nil(t, resp, "must be nil") @@ -177,7 +172,7 @@ func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { assert.NoError(t, err) id, _ := cfg.GetIdentityID() - resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "nil core document") assert.Nil(t, resp, "must be nil") @@ -190,7 +185,7 @@ func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { assert.NoError(t, err) id, _ := cfg.GetIdentityID() - resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID(hexutil.Encode(id)), p2pEnv) + resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "failed to get type of the document") assert.Nil(t, resp, "must be nil") @@ -198,28 +193,32 @@ func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { func TestP2PService_basicChecks(t *testing.T) { tests := []struct { - envelope *p2ppb.Envelope - err error + header *p2ppb.Header + err error }{ { - envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: "someversion", NetworkIdentifier: 12}}, - err: errors.AppendError(errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), errors.New("signature header missing")), + header: &p2ppb.Header{NodeVersion: "someversion", NetworkIdentifier: 12}, + err: errors.AppendError(version.IncompatibleVersionError("someversion"), incompatibleNetworkError(cfg.GetNetworkID(), 12)), }, { - envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: "0.0.1", NetworkIdentifier: 12}}, - err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), errors.New("signature header missing")), + header: &p2ppb.Header{NodeVersion: "0.0.1", NetworkIdentifier: 12}, + err: errors.AppendError(incompatibleNetworkError(cfg.GetNetworkID(), 12), nil), }, { - envelope: &p2ppb.Envelope{Header: &p2ppb.Header{NodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}}, - err: errors.AppendError(errors.New("signature header missing"), nil), + header: &p2ppb.Header{NodeVersion: version.GetVersion().String(), NetworkIdentifier: cfg.GetNetworkID()}, }, } + id, _ := cfg.GetIdentityID() + centID, _ := identity.ToCentID(id) for _, c := range tests { - err := HandshakeValidator(cfg.GetNetworkID(), mockIDService).Validate(c.envelope) + err := HandshakeValidator(cfg.GetNetworkID(), mockIDService).Validate(c.header, ¢ID, &defaultPID) if err != nil { + if c.err == nil { + t.Fatalf("unexpected error: %v\n", err) + } assert.EqualError(t, err, c.err.Error(), "error mismatch") } } diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index a078b5aa7..8d4d6a001 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -5,29 +5,27 @@ import ( "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/golang/protobuf/proto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/version" + libp2pPeer "github.com/libp2p/go-libp2p-peer" ) // Validator defines method that must be implemented by any validator type. type Validator interface { // Validate validates p2p requests - Validate(envelope *p2ppb.Envelope) error + Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error } // ValidatorGroup implements Validator for validating a set of validators. type ValidatorGroup []Validator // Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(envelope *p2ppb.Envelope) (errs error) { +func (group ValidatorGroup) Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) (errs error) { for _, v := range group { - if err := v.Validate(envelope); err != nil { + if err := v.Validate(header, centID, peerID); err != nil { errs = errors.AppendError(errs, err) } } @@ -36,67 +34,61 @@ func (group ValidatorGroup) Validate(envelope *p2ppb.Envelope) (errs error) { // ValidatorFunc implements Validator and can be used as a adaptor for functions // with specific function signature -type ValidatorFunc func(envelope *p2ppb.Envelope) error +type ValidatorFunc func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error // Validate passes the arguments to the underlying validator // function and returns the results -func (vf ValidatorFunc) Validate(envelope *p2ppb.Envelope) error { - return vf(envelope) +func (vf ValidatorFunc) Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + return vf(header, centID, peerID) } func versionValidator() Validator { - return ValidatorFunc(func(envelope *p2ppb.Envelope) error { - if envelope == nil || envelope.Header == nil { - return errors.New("nil envelope/header") + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + if header == nil { + return errors.New("nil header") } - if !version.CheckVersion(envelope.Header.NodeVersion) { - return version.IncompatibleVersionError(envelope.Header.NodeVersion) + if !version.CheckVersion(header.NodeVersion) { + return version.IncompatibleVersionError(header.NodeVersion) } return nil }) } func networkValidator(networkID uint32) Validator { - return ValidatorFunc(func(envelope *p2ppb.Envelope) error { - if envelope == nil || envelope.Header == nil { - return errors.New("nil envelope/header") + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + if header == nil { + return errors.New("nil header") } - if networkID != envelope.Header.NetworkIdentifier { - return incompatibleNetworkError(networkID, envelope.Header.NetworkIdentifier) + if networkID != header.NetworkIdentifier { + return incompatibleNetworkError(networkID, header.NetworkIdentifier) } return nil }) } -func signatureValidator(idService identity.Service) Validator { - return ValidatorFunc(func(envelope *p2ppb.Envelope) error { - if envelope == nil || envelope.Header == nil { - return errors.New("nil envelope/header") +func peerValidator(idService identity.Service) Validator { + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + if header == nil { + return errors.New("nil header") } - - if envelope.Header.Signature == nil { - return errors.New("signature header missing") + if centID == nil { + return errors.New("nil centID") } - - envData := proto.Clone(envelope).(*p2ppb.Envelope) - // Remove Signature header so we can verify the message signed - envData.Header.Signature = nil - - data, err := proto.Marshal(envData) + if peerID == nil { + return errors.New("nil peerID") + } + pk, err := peerID.ExtractPublicKey() if err != nil { return err } - - valid := crypto.VerifyMessage(envelope.Header.Signature.PublicKey, data, envelope.Header.Signature.Signature, crypto.CurveEd25519, false) - if !valid { - return errors.New("signature validation failure") + if pk == nil { + return errors.New("cannot extract public key out of peer ID") } - - centID, err := identity.ToCentID(envelope.Header.Signature.EntityId) + idKey, err := pk.Raw() if err != nil { return err } - return idService.ValidateKey(centID, envelope.Header.Signature.PublicKey, identity.KeyPurposeSigning) + return idService.ValidateKey(*centID, idKey, identity.KeyPurposeSigning) }) } @@ -105,7 +97,7 @@ func HandshakeValidator(networkID uint32, idService identity.Service) ValidatorG return ValidatorGroup{ versionValidator(), networkValidator(networkID), - signatureValidator(idService), + peerValidator(idService), } } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index e3afb5b49..777adc41d 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -5,14 +5,12 @@ package receiver import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/stretchr/testify/mock" - "github.com/golang/protobuf/proto" - - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" @@ -28,27 +26,27 @@ func TestValidate_versionValidator(t *testing.T) { vv := versionValidator() // Nil header - err := vv.Validate(nil) + err := vv.Validate(nil, nil, nil) assert.NotNil(t, err) // Empty header - envelope := &p2ppb.Envelope{Header: &p2ppb.Header{}} - err = vv.Validate(envelope) + header := &p2ppb.Header{} + err = vv.Validate(header, nil, nil) assert.NotNil(t, err) // Incompatible Major - envelope.Header.NodeVersion = "1.1.1" - err = vv.Validate(envelope) + header.NodeVersion = "1.1.1" + err = vv.Validate(header, nil, nil) assert.NotNil(t, err) // Compatible Minor - envelope.Header.NodeVersion = "0.1.1" - err = vv.Validate(envelope) + header.NodeVersion = "0.1.1" + err = vv.Validate(header, nil, nil) assert.Nil(t, err) //Same version - envelope.Header.NodeVersion = version.GetVersion().String() - err = vv.Validate(envelope) + header.NodeVersion = version.GetVersion().String() + err = vv.Validate(header, nil, nil) assert.Nil(t, err) } @@ -56,101 +54,87 @@ func TestValidate_networkValidator(t *testing.T) { nv := networkValidator(cfg.GetNetworkID()) // Nil header - err := nv.Validate(nil) + err := nv.Validate(nil, nil, nil) assert.NotNil(t, err) - envelope := &p2ppb.Envelope{Header: &p2ppb.Header{}} - err = nv.Validate(envelope) + header := &p2ppb.Header{} + err = nv.Validate(header, nil, nil) assert.NotNil(t, err) // Incompatible network - envelope.Header.NetworkIdentifier = 12 - err = nv.Validate(envelope) + header.NetworkIdentifier = 12 + err = nv.Validate(header, nil, nil) assert.NotNil(t, err) // Compatible network - envelope.Header.NetworkIdentifier = cfg.GetNetworkID() - err = nv.Validate(envelope) + header.NetworkIdentifier = cfg.GetNetworkID() + err = nv.Validate(header, nil, nil) assert.Nil(t, err) } -func TestValidate_signatureValidator(t *testing.T) { - idService := &testingcommons.MockIDService{} - sv := signatureValidator(idService) +func TestValidate_peerValidator(t *testing.T) { + cID, _ := identity.ToCentID(id1) - // Nil envelope - err := sv.Validate(nil) - assert.Error(t, err) + idService := &testingcommons.MockIDService{} + sv := peerValidator(idService) - // Nil Header - envelope := &p2ppb.Envelope{} - err = sv.Validate(envelope) + // Nil headers + err := sv.Validate(nil, nil, nil) assert.Error(t, err) - // Nil Signature - envelope.Header = &p2ppb.Header{} - err = sv.Validate(envelope) + // Nil centID + header := &p2ppb.Header{} + err = sv.Validate(header, nil, nil) assert.Error(t, err) - // Signature validation failure - envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, key1Pub) - err = sv.Validate(envelope) + // Nil peerID + err = sv.Validate(header, &cID, nil) assert.Error(t, err) - // Ethereum Identity validation failure - envelope.Header.Signature = nil - data, err := proto.Marshal(envelope) - assert.NoError(t, err) - envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, data) + // Identity validation failure idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() - err = sv.Validate(envelope) + err = sv.Validate(header, &cID, &defaultPID) assert.Error(t, err) // Success idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - err = sv.Validate(envelope) + err = sv.Validate(header, &cID, &defaultPID) assert.NoError(t, err) } func TestValidate_handshakeValidator(t *testing.T) { + cID, _ := identity.ToCentID(id1) idService := &testingcommons.MockIDService{} - idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() hv := HandshakeValidator(cfg.GetNetworkID(), idService) // Incompatible version network and wrong signature - envelope := &p2ppb.Envelope{ - Header: &p2ppb.Header{ - NodeVersion: "version", - NetworkIdentifier: 52, - Signature: crypto.Sign(id1, key1, key1Pub, key1Pub), - }, - Body: key1Pub, + header := &p2ppb.Header{ + NodeVersion: "version", + NetworkIdentifier: 52, } - err := hv.Validate(envelope) + err := hv.Validate(header, nil, nil) assert.NotNil(t, err) // Incompatible version, correct network - envelope.Header.NetworkIdentifier = cfg.GetNetworkID() - err = hv.Validate(envelope) + header.NetworkIdentifier = cfg.GetNetworkID() + err = hv.Validate(header, nil, nil) assert.NotNil(t, err) // Compatible version, incorrect network - envelope.Header.NetworkIdentifier = 52 - envelope.Header.NodeVersion = version.GetVersion().String() - err = hv.Validate(envelope) + header.NetworkIdentifier = 52 + header.NodeVersion = version.GetVersion().String() + err = hv.Validate(header, nil, nil) assert.NotNil(t, err) - // Compatible version, network and wrong signature - envelope.Header.NetworkIdentifier = cfg.GetNetworkID() - err = hv.Validate(envelope) + // Compatible version, network and wrong eth key + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() + header.NetworkIdentifier = cfg.GetNetworkID() + err = hv.Validate(header, &cID, &defaultPID) assert.NotNil(t, err) - assert.Contains(t, err.Error(), "signature validation failure") + assert.Contains(t, err.Error(), "key not linked to identity") // Compatible version, network and signature - envelope.Header.Signature = nil - data, err := proto.Marshal(envelope) + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + err = hv.Validate(header, &cID, &defaultPID) assert.NoError(t, err) - envelope.Header.Signature = crypto.Sign(id1, key1, key1Pub, data) - err = hv.Validate(envelope) - assert.Nil(t, err) } From 45197a1a999e2a9157b2a50ca557e0d253a76ad1 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 16 Jan 2019 13:16:52 +0100 Subject: [PATCH 136/220] Import main node config file everytime node starts(simpler than removing config service usage) (#649) * Import main node config file everytime node starts(simpler than removing config service usage) * Remove dead code * Fix tests * Fix test * Fix problem with creat * review comments --- config/configstore/bootstrapper.go | 10 +- config/configstore/handler.go | 33 -- config/configstore/handler_test.go | 66 +--- config/configstore/mock_service.go | 10 - config/configstore/service.go | 14 +- config/configstore/service_test.go | 47 +-- config/configuration.go | 2 - contextutil/context.go | 10 +- documents/handler.go | 4 +- documents/invoice/handler.go | 8 +- documents/purchaseorder/handler.go | 8 +- nft/handler.go | 2 +- nft/handler_test.go | 1 - p2p/client_test.go | 3 + p2p/messenger_test.go | 1 + p2p/server_test.go | 40 ++- protobufs/config/service.proto | 26 -- protobufs/gen/go/config/service.pb.go | 291 ++++++------------ protobufs/gen/go/config/service.pb.gw.go | 134 -------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 65 ---- transactions/handler.go | 2 +- 22 files changed, 157 insertions(+), 622 deletions(-) diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 35356e74d..81f52aed3 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -33,14 +33,12 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { nc := NewNodeConfig(cfg) configdb.Register(nc) - _, err := service.GetConfig() - // if node config doesn't exist in the db, add it + // install the file based config everytime so that file updates are reflected in the db, direct updates to db are not allowed + nc, err := service.CreateConfig(NewNodeConfig(cfg)) if err != nil { - nc, err = service.CreateConfig(NewNodeConfig(cfg)) - if err != nil { - return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) - } + return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } + tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), cfg) if err != nil { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 93d87570a..8f396b894 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -59,20 +59,6 @@ func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*config return h.deriveAllTenantResponse(cfgs) } -func (h grpcHandler) CreateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { - apiLog.Infof("Creating node config: %v", data) - nodeConfig := new(NodeConfig) - err := nodeConfig.loadFromProtobuf(data) - if err != nil { - return nil, err - } - nc, err := h.service.CreateConfig(nodeConfig) - if err != nil { - return nil, err - } - return nc.CreateProtobuf(), nil -} - func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData) (*configpb.TenantData, error) { apiLog.Infof("Creating tenant config: %v", data) tenantConfig := new(TenantConfig) @@ -93,20 +79,6 @@ func (h grpcHandler) GenerateTenant(context.Context, *empty.Empty) (*configpb.Te return tc.CreateProtobuf(), nil } -func (h grpcHandler) UpdateConfig(ctx context.Context, data *configpb.ConfigData) (*configpb.ConfigData, error) { - apiLog.Infof("Updating node config: %v", data) - nodeConfig := new(NodeConfig) - err := nodeConfig.loadFromProtobuf(data) - if err != nil { - return nil, err - } - nc, err := h.service.UpdateConfig(nodeConfig) - if err != nil { - return nil, err - } - return nc.CreateProtobuf(), nil -} - func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenantRequest) (*configpb.TenantData, error) { apiLog.Infof("Updating tenant config: %v", req) tenantConfig := new(TenantConfig) @@ -118,11 +90,6 @@ func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenan return tc.CreateProtobuf(), nil } -func (h grpcHandler) DeleteConfig(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) { - apiLog.Infof("Deleting node config") - return nil, h.service.DeleteConfig() -} - func (h grpcHandler) DeleteTenant(ctx context.Context, req *configpb.GetTenantRequest) (*empty.Empty, error) { apiLog.Infof("Deleting tenant config: %v", req.Identifier) id, err := hexutil.Decode(req.Identifier) diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 6c9634d0f..9d95ce520 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -33,7 +33,7 @@ func TestGrpcHandler_GetConfig(t *testing.T) { svc := DefaultService(repo, idService) h := GRPCHandler(svc) nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) + _, err = svc.CreateConfig(nodeCfg) assert.Nil(t, err) readCfg, err := h.GetConfig(context.Background(), nil) assert.Nil(t, err) @@ -91,22 +91,6 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { assert.Equal(t, 2, len(resp.Data)) } -func TestGrpcHandler_CreateConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo, idService) - h := GRPCHandler(svc) - nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) - assert.Nil(t, err) - - // Already exists - _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) - assert.NotNil(t, err) -} - func TestGrpcHandler_CreateTenant(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() @@ -134,31 +118,6 @@ func TestGrpcHandler_GenerateTenant(t *testing.T) { assert.NotNil(t, tc) } -func TestGrpcHandler_UpdateConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo, idService) - h := GRPCHandler(svc) - nodeCfg := NewNodeConfig(cfg) - - // Config doesn't exist - _, err = h.UpdateConfig(context.Background(), nodeCfg.CreateProtobuf()) - assert.NotNil(t, err) - - _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) - assert.Nil(t, err) - n := nodeCfg.(*NodeConfig) - n.NetworkString = "other" - _, err = h.UpdateConfig(context.Background(), n.CreateProtobuf()) - assert.Nil(t, err) - - readCfg, err := h.GetConfig(context.Background(), nil) - assert.Nil(t, err) - assert.Equal(t, n.GetNetworkString(), readCfg.Network) -} - func TestGrpcHandler_UpdateTenant(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() @@ -189,29 +148,6 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { assert.Equal(t, tc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) } -func TestGrpcHandler_DeleteConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo, idService) - h := GRPCHandler(svc) - - //No error when no config - _, err = h.DeleteConfig(context.Background(), nil) - assert.Nil(t, err) - - nodeCfg := NewNodeConfig(cfg) - _, err = h.CreateConfig(context.Background(), nodeCfg.CreateProtobuf()) - assert.Nil(t, err) - _, err = h.DeleteConfig(context.Background(), nil) - assert.Nil(t, err) - - readCfg, err := h.GetConfig(context.Background(), nil) - assert.NotNil(t, err) - assert.Nil(t, readCfg) -} - func TestGrpcHandler_DeleteTenant(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 9fa3dbb95..3284eb99b 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -42,21 +42,11 @@ func (m MockService) CreateTenant(data config.TenantConfiguration) (config.Tenan return args.Get(0).(*TenantConfig), args.Error(0) } -func (m MockService) UpdateConfig(data config.Configuration) (config.Configuration, error) { - args := m.Called() - return args.Get(0).(*NodeConfig), args.Error(0) -} - func (m MockService) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { args := m.Called(data) return args.Get(0).(*TenantConfig), args.Error(0) } -func (m MockService) DeleteConfig() error { - args := m.Called() - return args.Error(0) -} - func (m MockService) DeleteTenant(identifier []byte) error { args := m.Called(identifier) return args.Error(0) diff --git a/config/configstore/service.go b/config/configstore/service.go index 6c2e9d3a1..42b51b9bd 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -50,7 +50,11 @@ func (s service) GetAllTenants() ([]config.TenantConfiguration, error) { } func (s service) CreateConfig(data config.Configuration) (config.Configuration, error) { - return data, s.repo.CreateConfig(data) + _, err := s.repo.GetConfig() + if err != nil { + return data, s.repo.CreateConfig(data) + } + return data, s.repo.UpdateConfig(data) } func (s service) CreateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { @@ -172,10 +176,6 @@ func createKeyPath(keyStorepath string, CID identity.CentID, keyName string) (st return fmt.Sprintf("%s/%s", tdir, keyName), nil } -func (s service) UpdateConfig(data config.Configuration) (config.Configuration, error) { - return data, s.repo.UpdateConfig(data) -} - func (s service) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { id, err := data.GetIdentityID() if err != nil { @@ -184,10 +184,6 @@ func (s service) UpdateTenant(data config.TenantConfiguration) (config.TenantCon return data, s.repo.UpdateTenant(id, data) } -func (s service) DeleteConfig() error { - return s.repo.DeleteConfig() -} - func (s service) DeleteTenant(identifier []byte) error { return s.repo.DeleteTenant(identifier) } diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index 71f2a23c7..d8d1158f3 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -78,7 +78,7 @@ func TestService_CreateConfig(t *testing.T) { //Config already exists _, err = svc.CreateConfig(nodeCfg) - assert.NotNil(t, err) + assert.Nil(t, err) } func TestService_CreateTenant(t *testing.T) { @@ -102,29 +102,6 @@ func TestService_CreateTenant(t *testing.T) { assert.NotNil(t, err) } -func TestService_UpdateConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo, idService) - nodeCfg := NewNodeConfig(cfg) - - //Config doesn't exists - _, err = svc.UpdateConfig(nodeCfg) - assert.NotNil(t, err) - - newCfg, err := svc.CreateConfig(nodeCfg) - assert.Nil(t, err) - assert.Equal(t, nodeCfg.GetStoragePath(), newCfg.GetStoragePath()) - - n := nodeCfg.(*NodeConfig) - n.NetworkString = "something" - newCfg, err = svc.UpdateConfig(n) - assert.Nil(t, err) - assert.Equal(t, n.GetNetworkString(), newCfg.GetNetworkString()) -} - func TestService_UpdateTenant(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() @@ -152,28 +129,6 @@ func TestService_UpdateTenant(t *testing.T) { assert.Equal(t, tc.EthereumDefaultAccountName, newCfg.GetEthereumDefaultAccountName()) } -func TestService_DeleteConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterConfig(&NodeConfig{}) - svc := DefaultService(repo, idService) - - //No config, no error - err = svc.DeleteConfig() - assert.Nil(t, err) - - nodeCfg := NewNodeConfig(cfg) - _, err = svc.CreateConfig(nodeCfg) - assert.Nil(t, err) - - err = svc.DeleteConfig() - assert.Nil(t, err) - - _, err = svc.GetConfig() - assert.NotNil(t, err) -} - func TestService_DeleteTenant(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() diff --git a/config/configuration.go b/config/configuration.go index a6a15ef88..e9fd2289d 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -134,9 +134,7 @@ type Service interface { CreateConfig(data Configuration) (Configuration, error) CreateTenant(data TenantConfiguration) (TenantConfiguration, error) GenerateTenant() (TenantConfiguration, error) - UpdateConfig(data Configuration) (Configuration, error) UpdateTenant(data TenantConfiguration) (TenantConfiguration, error) - DeleteConfig() error DeleteTenant(identifier []byte) error } diff --git a/contextutil/context.go b/contextutil/context.go index 812c44b0f..524867d21 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -48,9 +48,13 @@ func Tenant(ctx context.Context) (config.TenantConfiguration, error) { return tc, nil } -// CentContext updates a context with tenant info using the configstore, must only be used for api handlers -func CentContext(ctx context.Context, cs config.Service) (context.Context, error) { - tcIDHex := ctx.Value(config.TenantKey).(string) +// Context updates a context with tenant info using the configstore, must only be used for api handlers +func Context(ctx context.Context, cs config.Service) (context.Context, error) { + tcIDHex, ok := ctx.Value(config.TenantKey).(string) + if !ok { + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header %v", config.TenantKey)) + } + tcID, err := hexutil.Decode(tcIDHex) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/documents/handler.go b/documents/handler.go index f64941501..2565458a2 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -29,7 +29,7 @@ func GRPCHandler(config config.Service, registry *ServiceRegistry) documentpb.Do // CreateDocumentProof creates precise proofs for the given fields func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProofEnvelope *documentpb.CreateDocumentProofRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofEnvelope) - cctx, err := contextutil.CentContext(ctx, h.config) + cctx, err := contextutil.Context(ctx, h.config) if err != nil { return &documentpb.DocumentProof{}, err } @@ -54,7 +54,7 @@ func (h grpcHandler) CreateDocumentProof(ctx context.Context, createDocumentProo // CreateDocumentProofForVersion creates precise proofs for the given fields for the given version of the document func (h grpcHandler) CreateDocumentProofForVersion(ctx context.Context, createDocumentProofForVersionEnvelope *documentpb.CreateDocumentProofForVersionRequest) (*documentpb.DocumentProof, error) { apiLog.Infof("Document proof request %v", createDocumentProofForVersionEnvelope) - cctx, err := contextutil.CentContext(ctx, h.config) + cctx, err := contextutil.Context(ctx, h.config) if err != nil { return &documentpb.DocumentProof{}, err } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 850c74284..ba9d43321 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -38,7 +38,7 @@ func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (cl // Create handles the creation of the invoices and anchoring the documents on chain func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCreatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Create request %v", req) - cctx, err := contextutil.CentContext(ctx, h.config) + cctx, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -70,7 +70,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr // Update handles the document update and anchoring func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -101,7 +101,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi // GetVersion returns the requested version of the document func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clientinvoicepb.GetVersionRequest) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Get version request %v", getVersionRequest) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -137,7 +137,7 @@ func (h *grpcHandler) GetVersion(ctx context.Context, getVersionRequest *clienti // Get returns the invoice the latest version of the document with given identifier func (h *grpcHandler) Get(ctx context.Context, getRequest *clientinvoicepb.GetRequest) (*clientinvoicepb.InvoiceResponse, error) { apiLog.Debugf("Get request %v", getRequest) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index c6004beef..7d550d834 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -39,7 +39,7 @@ func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (cl // Create validates the purchase order, persists it to DB, and anchors it the chain func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.PurchaseOrderCreatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Create request %v", req) - ctxh, err := contextutil.CentContext(ctx, h.config) + ctxh, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -71,7 +71,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc // Update handles the document update and anchoring func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb.PurchaseOrderUpdatePayload) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Update request %v", payload) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -102,7 +102,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. // GetVersion returns the requested version of a purchase order func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb.GetVersionRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("GetVersion request %v", req) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err @@ -138,7 +138,7 @@ func (h grpcHandler) GetVersion(ctx context.Context, req *clientpurchaseorderpb. // Get returns the purchase order the latest version of the document with given identifier func (h grpcHandler) Get(ctx context.Context, getRequest *clientpurchaseorderpb.GetRequest) (*clientpurchaseorderpb.PurchaseOrderResponse, error) { apiLog.Debugf("Get request %v", getRequest) - ctxHeader, err := contextutil.CentContext(ctx, h.config) + ctxHeader, err := contextutil.Context(ctx, h.config) if err != nil { apiLog.Error(err) return nil, err diff --git a/nft/handler.go b/nft/handler.go index cbf2569c9..7dfba6d05 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -30,7 +30,7 @@ func GRPCHandler(config config.Service, payOb PaymentObligation) nftpb.NFTServic // MintNFT will be called from the client API to mint an NFT func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) (*nftpb.NFTMintResponse, error) { apiLog.Infof("Received request to Mint an NFT with %s with proof fields %s", request.Identifier, request.ProofFields) - ctxHeader, err := contextutil.CentContext(ctx, g.config) + ctxHeader, err := contextutil.Context(ctx, g.config) if err != nil { apiLog.Error(err) return nil, err diff --git a/nft/handler_test.go b/nft/handler_test.go index 2dd449404..5cecdf5e3 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -51,7 +51,6 @@ func TestNFTMint_success(t *testing.T) { func mockmockConfigStore() *configstore.MockService { mockConfigStore := &configstore.MockService{} - //var tc config.TenantConfiguration = &configstore.TenantConfig{} mockConfigStore.On("GetTenant", mock.Anything).Return(&configstore.TenantConfig{}, nil) mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{}}, nil) return mockConfigStore diff --git a/p2p/client_test.go b/p2p/client_test.go index 2e14aa3d3..5d9dcec15 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -50,6 +50,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) @@ -76,6 +77,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) ctx := testingconfig.CreateTenantContext(t, c) _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) @@ -95,6 +97,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) ctx := testingconfig.CreateTenantContext(t, c) centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go index ff1f466c1..f02d9812c 100644 --- a/p2p/messenger_test.go +++ b/p2p/messenger_test.go @@ -54,6 +54,7 @@ var mockedHandler = func(ctx context.Context, peer libp2pPeer.ID, protoc protoco func TestHandleNewMessage(t *testing.T) { cfg, err := cfg.GetConfig() assert.NoError(t, err) + cfg = updateKeys(cfg) ctx, canc := context.WithCancel(context.Background()) c := testingconfig.CreateTenantContextWithContext(t, ctx, cfg) r := rand.Reader diff --git a/p2p/server_test.go b/p2p/server_test.go index eb713e392..f6d644c92 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -48,13 +50,6 @@ func TestMain(m *testing.M) { ctx[identity.BootstrappedIDService] = idService bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[config.BootstrappedConfigStorage].(config.Service) - c, _ := cfg.GetConfig() - n := c.(*configstore.NodeConfig) - n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" - n.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" - n.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" - n.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" - cfg.UpdateConfig(c) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -63,12 +58,13 @@ func TestMain(m *testing.M) { func TestCentP2PServer_StartContextCancel(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) n := c.(*configstore.NodeConfig) n.P2PPort = 38203 - _, err = cfg.UpdateConfig(c) + cfgMock := mockmockConfigStore(n) assert.NoError(t, err) - cp2p := &peer{config: cfg, handlerCreator: func() *receiver.Handler { - return receiver.New(cfg, nil, receiver.HandshakeValidator(n.NetworkID, idService)) + cp2p := &peer{config: cfgMock, handlerCreator: func() *receiver.Handler { + return receiver.New(cfgMock, nil, receiver.HandshakeValidator(n.NetworkID, idService)) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) @@ -86,11 +82,12 @@ func TestCentP2PServer_StartListenError(t *testing.T) { // cause an error by using an invalid port c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) n := c.(*configstore.NodeConfig) n.P2PPort = 100000000 - _, err = cfg.UpdateConfig(n) + cfgMock := mockmockConfigStore(n) assert.NoError(t, err) - cp2p := &peer{config: cfg} + cp2p := &peer{config: cfgMock} ctx, _ := context.WithCancel(context.Background()) startErr := make(chan error) var wg sync.WaitGroup @@ -105,6 +102,7 @@ func TestCentP2PServer_StartListenError(t *testing.T) { func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) listenPort := 38202 cp2p := &peer{config: cfg} pu, pr := c.GetSigningKeyPair() @@ -117,6 +115,7 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) externalIP := "100.100.100.100" listenPort := 38202 cp2p := &peer{config: cfg} @@ -134,6 +133,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) + c = updateKeys(c) externalIP := "100.200.300.400" listenPort := 38202 cp2p := &peer{config: cfg} @@ -143,3 +143,19 @@ func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { assert.NotNil(t, err) assert.Nil(t, h) } + +func updateKeys(c config.Configuration) config.Configuration { + n := c.(*configstore.NodeConfig) + n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" + n.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" + n.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" + n.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" + return c +} + +func mockmockConfigStore(n config.Configuration) *configstore.MockService { + mockConfigStore := &configstore.MockService{} + mockConfigStore.On("GetConfig").Return(n, nil) + mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{IdentityID: utils.RandomSlice(identity.CentIDLength)}}, nil) + return mockConfigStore +} diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index f6b729b51..80fbea6d8 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -38,15 +38,6 @@ service ConfigService { description: "Get All Tenant Configs" }; } - rpc CreateConfig(ConfigData) returns (ConfigData) { - option (google.api.http) = { - post: "/config/node" - body: "*" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Creates node config data" - }; - } rpc CreateTenant(TenantData) returns (TenantData) { option (google.api.http) = { post: "/config/tenants" @@ -64,15 +55,6 @@ service ConfigService { description: "Generates tenant config data taking defaults based on the main tenant" }; } - rpc UpdateConfig(ConfigData) returns (ConfigData) { - option (google.api.http) = { - put: "/config/node" - body: "*" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Updates node config" - }; - } rpc UpdateTenant(UpdateTenantRequest) returns (TenantData) { option (google.api.http) = { put: "/config/tenants/{identifier}" @@ -82,14 +64,6 @@ service ConfigService { description: "Updates tenant config" }; } - rpc DeleteConfig(google.protobuf.Empty) returns (google.protobuf.Empty) { - option (google.api.http) = { - delete: "/config/node" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Deletes node config" - }; - } rpc DeleteTenant(GetTenantRequest) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/config/tenants/{identifier}" diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 88b79de2f..753e8fe66 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -38,7 +38,7 @@ func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } func (*GetTenantRequest) ProtoMessage() {} func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{0} + return fileDescriptor_service_21a2bc638067bc54, []int{0} } func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) @@ -76,7 +76,7 @@ func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } func (*GetAllTenantResponse) ProtoMessage() {} func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{1} + return fileDescriptor_service_21a2bc638067bc54, []int{1} } func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) @@ -115,7 +115,7 @@ func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } func (*UpdateTenantRequest) ProtoMessage() {} func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{2} + return fileDescriptor_service_21a2bc638067bc54, []int{2} } func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) @@ -162,7 +162,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{3} + return fileDescriptor_service_21a2bc638067bc54, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -215,7 +215,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{4} + return fileDescriptor_service_21a2bc638067bc54, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -265,7 +265,7 @@ func (m *TenantData) Reset() { *m = TenantData{} } func (m *TenantData) String() string { return proto.CompactTextString(m) } func (*TenantData) ProtoMessage() {} func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{5} + return fileDescriptor_service_21a2bc638067bc54, []int{5} } func (m *TenantData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TenantData.Unmarshal(m, b) @@ -359,7 +359,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_f381bc5e00981892, []int{6} + return fileDescriptor_service_21a2bc638067bc54, []int{6} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -559,12 +559,9 @@ type ConfigServiceClient interface { GetConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ConfigData, error) GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*TenantData, error) GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) - CreateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) GenerateTenant(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*TenantData, error) - UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) - DeleteConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) } @@ -603,15 +600,6 @@ func (c *configServiceClient) GetAllTenants(ctx context.Context, in *empty.Empty return out, nil } -func (c *configServiceClient) CreateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) { - out := new(ConfigData) - err := c.cc.Invoke(ctx, "/config.ConfigService/CreateConfig", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *configServiceClient) CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) { out := new(TenantData) err := c.cc.Invoke(ctx, "/config.ConfigService/CreateTenant", in, out, opts...) @@ -630,15 +618,6 @@ func (c *configServiceClient) GenerateTenant(ctx context.Context, in *empty.Empt return out, nil } -func (c *configServiceClient) UpdateConfig(ctx context.Context, in *ConfigData, opts ...grpc.CallOption) (*ConfigData, error) { - out := new(ConfigData) - err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateConfig", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *configServiceClient) UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) { out := new(TenantData) err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateTenant", in, out, opts...) @@ -648,15 +627,6 @@ func (c *configServiceClient) UpdateTenant(ctx context.Context, in *UpdateTenant return out, nil } -func (c *configServiceClient) DeleteConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) { - out := new(empty.Empty) - err := c.cc.Invoke(ctx, "/config.ConfigService/DeleteConfig", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *configServiceClient) DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) { out := new(empty.Empty) err := c.cc.Invoke(ctx, "/config.ConfigService/DeleteTenant", in, out, opts...) @@ -671,12 +641,9 @@ type ConfigServiceServer interface { GetConfig(context.Context, *empty.Empty) (*ConfigData, error) GetTenant(context.Context, *GetTenantRequest) (*TenantData, error) GetAllTenants(context.Context, *empty.Empty) (*GetAllTenantResponse, error) - CreateConfig(context.Context, *ConfigData) (*ConfigData, error) CreateTenant(context.Context, *TenantData) (*TenantData, error) GenerateTenant(context.Context, *empty.Empty) (*TenantData, error) - UpdateConfig(context.Context, *ConfigData) (*ConfigData, error) UpdateTenant(context.Context, *UpdateTenantRequest) (*TenantData, error) - DeleteConfig(context.Context, *empty.Empty) (*empty.Empty, error) DeleteTenant(context.Context, *GetTenantRequest) (*empty.Empty, error) } @@ -738,24 +705,6 @@ func _ConfigService_GetAllTenants_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _ConfigService_CreateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ConfigData) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).CreateConfig(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/CreateConfig", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).CreateConfig(ctx, req.(*ConfigData)) - } - return interceptor(ctx, in, info, handler) -} - func _ConfigService_CreateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(TenantData) if err := dec(in); err != nil { @@ -792,24 +741,6 @@ func _ConfigService_GenerateTenant_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _ConfigService_UpdateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ConfigData) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).UpdateConfig(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/UpdateConfig", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).UpdateConfig(ctx, req.(*ConfigData)) - } - return interceptor(ctx, in, info, handler) -} - func _ConfigService_UpdateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(UpdateTenantRequest) if err := dec(in); err != nil { @@ -828,24 +759,6 @@ func _ConfigService_UpdateTenant_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } -func _ConfigService_DeleteConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).DeleteConfig(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/DeleteConfig", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).DeleteConfig(ctx, req.(*empty.Empty)) - } - return interceptor(ctx, in, info, handler) -} - func _ConfigService_DeleteTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetTenantRequest) if err := dec(in); err != nil { @@ -880,10 +793,6 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetAllTenants", Handler: _ConfigService_GetAllTenants_Handler, }, - { - MethodName: "CreateConfig", - Handler: _ConfigService_CreateConfig_Handler, - }, { MethodName: "CreateTenant", Handler: _ConfigService_CreateTenant_Handler, @@ -892,18 +801,10 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ MethodName: "GenerateTenant", Handler: _ConfigService_GenerateTenant_Handler, }, - { - MethodName: "UpdateConfig", - Handler: _ConfigService_UpdateConfig_Handler, - }, { MethodName: "UpdateTenant", Handler: _ConfigService_UpdateTenant_Handler, }, - { - MethodName: "DeleteConfig", - Handler: _ConfigService_DeleteConfig_Handler, - }, { MethodName: "DeleteTenant", Handler: _ConfigService_DeleteTenant_Handler, @@ -913,95 +814,91 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_f381bc5e00981892) } - -var fileDescriptor_service_f381bc5e00981892 = []byte{ - // 1385 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xe9, 0x6e, 0x1b, 0x47, - 0x12, 0x06, 0x25, 0xeb, 0x60, 0x93, 0xd4, 0xd1, 0x3a, 0x3c, 0x1e, 0xcb, 0xf2, 0x98, 0xc6, 0x7a, - 0x05, 0xc3, 0x22, 0x01, 0xee, 0x02, 0x3e, 0x7e, 0x18, 0xa0, 0x25, 0x82, 0x10, 0x76, 0xed, 0x10, - 0x63, 0x1b, 0x46, 0x12, 0x04, 0x83, 0x16, 0xa7, 0x44, 0x4e, 0x34, 0xec, 0x6e, 0xf7, 0x34, 0x29, - 0x11, 0x41, 0x80, 0xc0, 0xc8, 0x13, 0x30, 0x2f, 0x91, 0xb7, 0xc9, 0x8f, 0xbc, 0x42, 0xf2, 0x1e, - 0x41, 0x5f, 0x22, 0x25, 0x52, 0x12, 0xfc, 0x8b, 0x9c, 0xea, 0xaa, 0xef, 0xab, 0xfa, 0xaa, 0xfa, - 0x40, 0x9b, 0x6d, 0x46, 0x4f, 0x92, 0x4e, 0x35, 0x03, 0x31, 0x48, 0xda, 0x50, 0xe1, 0x82, 0x49, - 0x86, 0x17, 0x8d, 0xd5, 0xdf, 0xe9, 0x30, 0xd6, 0x49, 0xa1, 0x4a, 0x78, 0x52, 0x25, 0x94, 0x32, - 0x49, 0x64, 0xc2, 0x68, 0x66, 0xbc, 0xfc, 0x5d, 0xbb, 0xaa, 0xbf, 0x8e, 0xfb, 0x27, 0xd5, 0xb8, - 0x2f, 0xb4, 0x83, 0x5d, 0xbf, 0x7f, 0x75, 0x1d, 0x7a, 0x5c, 0x0e, 0xed, 0xe2, 0x33, 0xfd, 0xd3, - 0xde, 0xef, 0x00, 0xdd, 0xcf, 0xce, 0x48, 0xa7, 0x03, 0xa2, 0xca, 0xb8, 0x86, 0x9f, 0xa6, 0x2a, - 0xd7, 0xd0, 0x5a, 0x13, 0xe4, 0x07, 0xa0, 0x84, 0xca, 0x10, 0x3e, 0xf7, 0x21, 0x93, 0x78, 0x17, - 0xa1, 0x24, 0x06, 0x2a, 0x93, 0x93, 0x04, 0x84, 0x97, 0x0b, 0x72, 0x7b, 0xf9, 0x70, 0xc2, 0x52, - 0x7e, 0x8d, 0x36, 0x9b, 0x20, 0xeb, 0x69, 0xea, 0xc2, 0x32, 0xce, 0x68, 0x06, 0xf8, 0x09, 0xba, - 0x13, 0x13, 0x49, 0xbc, 0x5c, 0x30, 0xbf, 0x57, 0xa8, 0xe1, 0x8a, 0xa9, 0xb5, 0x62, 0xbc, 0x0e, - 0x89, 0x24, 0xa1, 0x5e, 0x2f, 0xff, 0x80, 0x36, 0x3e, 0xf2, 0x98, 0x48, 0xf8, 0x2a, 0xda, 0x0b, - 0xf8, 0xb9, 0x20, 0x77, 0x23, 0xfc, 0xb7, 0x68, 0xb5, 0x21, 0xbb, 0x20, 0xa0, 0xdf, 0xab, 0xb7, - 0xdb, 0xac, 0x4f, 0x25, 0xf6, 0xd0, 0x12, 0x89, 0x63, 0x01, 0x59, 0x66, 0x71, 0xdd, 0x27, 0x5e, - 0x43, 0xf3, 0xa7, 0x30, 0xd4, 0x98, 0xf9, 0x50, 0xfd, 0xc5, 0x3e, 0x5a, 0xe6, 0x24, 0xcb, 0xce, - 0x98, 0x88, 0xbd, 0x79, 0x6d, 0xbe, 0xf8, 0x2e, 0xef, 0xa3, 0xa5, 0xff, 0xc1, 0xb0, 0x45, 0x12, - 0xa1, 0x02, 0x79, 0xff, 0xd8, 0xc2, 0xa9, 0xbf, 0xda, 0x32, 0x90, 0x0e, 0x8a, 0x0f, 0x64, 0xf9, - 0xef, 0x39, 0x84, 0xc6, 0xe9, 0xe1, 0x17, 0xa8, 0x00, 0xb2, 0x1b, 0x11, 0x93, 0x94, 0x0e, 0x2d, - 0xd4, 0xee, 0xba, 0x3a, 0xae, 0xe4, 0x1c, 0x22, 0x90, 0x5d, 0x97, 0xff, 0x73, 0xe4, 0xa9, 0xc8, - 0x18, 0x4e, 0x48, 0x3f, 0x95, 0x0e, 0x21, 0xa2, 0xa4, 0x07, 0x96, 0x6f, 0x0b, 0x64, 0xf7, 0xd0, - 0x2c, 0xdb, 0xa0, 0x77, 0xa4, 0x07, 0xf8, 0x2d, 0x7a, 0x2c, 0xa0, 0x0d, 0xc9, 0x00, 0x22, 0x18, - 0x80, 0x0a, 0x61, 0x4a, 0xcd, 0xb6, 0x9e, 0x81, 0x08, 0x68, 0xcc, 0x59, 0x42, 0xa5, 0xad, 0x33, - 0xb0, 0xae, 0x0d, 0xe5, 0xf9, 0x6e, 0xc2, 0xb1, 0x61, 0xfd, 0xf0, 0x43, 0x54, 0x30, 0x0d, 0x91, - 0xc3, 0x28, 0x89, 0xbd, 0x3b, 0x93, 0x3d, 0x92, 0xc3, 0xa3, 0x18, 0xbf, 0x44, 0x6b, 0x59, 0xd2, - 0xa1, 0x09, 0xed, 0x44, 0xa7, 0x30, 0x8c, 0x38, 0x49, 0x84, 0xb7, 0xa0, 0xeb, 0x5c, 0x75, 0x75, - 0x5a, 0x01, 0xc3, 0x15, 0xeb, 0xe8, 0x04, 0x7d, 0x89, 0xd6, 0x40, 0x76, 0x49, 0x5f, 0x76, 0xc7, - 0xa1, 0x8b, 0xd7, 0x84, 0x5a, 0x47, 0xfb, 0x5d, 0xfe, 0x35, 0x8f, 0xd0, 0x81, 0x76, 0xd1, 0x3a, - 0x3f, 0x42, 0xc5, 0x4c, 0x32, 0x41, 0x3a, 0x10, 0x71, 0x22, 0xbb, 0xb6, 0x47, 0x05, 0x6b, 0x6b, - 0x11, 0xd9, 0xc5, 0xf7, 0xd0, 0x32, 0xaf, 0xf1, 0x88, 0x33, 0x61, 0x1a, 0xb6, 0x10, 0x2e, 0xf1, - 0x1a, 0x6f, 0x31, 0x21, 0xf1, 0x13, 0xb4, 0xaa, 0x96, 0xe0, 0x5c, 0x82, 0xa0, 0x24, 0x8d, 0x12, - 0x6e, 0xe5, 0x29, 0xf1, 0x1a, 0x6f, 0x58, 0xeb, 0x11, 0xc7, 0xdf, 0xa0, 0x6d, 0xe5, 0xd7, 0x66, - 0x94, 0x42, 0x5b, 0xcb, 0x29, 0x93, 0x1e, 0xb0, 0xbe, 0xd4, 0xb2, 0x14, 0x6a, 0xf7, 0x2a, 0x66, - 0x97, 0x56, 0xdc, 0x2e, 0xad, 0x1c, 0xda, 0x5d, 0x1c, 0x6e, 0xf2, 0x1a, 0x3f, 0xb8, 0x88, 0xfb, - 0x60, 0xc2, 0x94, 0xb8, 0xea, 0xb0, 0x00, 0x61, 0xd2, 0x5a, 0xd0, 0x69, 0x21, 0x63, 0xd2, 0x99, - 0xfd, 0x0b, 0xad, 0x58, 0x07, 0x37, 0xcc, 0x8b, 0x26, 0x31, 0x63, 0xad, 0xdb, 0x91, 0x7e, 0x88, - 0x0a, 0xb4, 0xdf, 0x8b, 0xce, 0x98, 0x38, 0x05, 0x91, 0x79, 0x4b, 0x06, 0x87, 0xf6, 0x7b, 0x9f, - 0x8c, 0x05, 0xef, 0xa3, 0x0d, 0xb3, 0x18, 0x9d, 0x91, 0x44, 0xea, 0xb4, 0xa3, 0x5e, 0xe6, 0x2d, - 0x6b, 0xc7, 0x35, 0xb3, 0xf4, 0x89, 0x24, 0x52, 0x25, 0xf6, 0x36, 0xc3, 0x01, 0x2a, 0xaa, 0xe1, - 0xa3, 0x2c, 0x86, 0xa8, 0x2f, 0x52, 0x2f, 0x6f, 0xba, 0x0e, 0xb2, 0xfb, 0x8e, 0xc5, 0xf0, 0x51, - 0xa4, 0xf8, 0x7b, 0xf4, 0x40, 0x79, 0xb4, 0x19, 0x95, 0x70, 0x2e, 0x23, 0x01, 0x24, 0x1e, 0x43, - 0x2b, 0x45, 0xd0, 0x6d, 0x8a, 0xdc, 0x03, 0xd9, 0x3d, 0x30, 0xe1, 0x21, 0x90, 0xd8, 0xb1, 0x2b, - 0x59, 0x42, 0x33, 0xfb, 0x0e, 0xfc, 0x12, 0x6e, 0xe1, 0x36, 0xdc, 0xad, 0x31, 0xee, 0x24, 0x66, - 0x13, 0x61, 0x85, 0x99, 0x50, 0x09, 0x62, 0x40, 0xd2, 0x48, 0x80, 0x14, 0x43, 0xaf, 0x78, 0x1b, - 0x9a, 0x1a, 0xd0, 0x23, 0x1b, 0x13, 0xaa, 0x10, 0x35, 0x2c, 0x0a, 0xa8, 0x47, 0xce, 0x35, 0x46, - 0x02, 0x99, 0x57, 0x0a, 0x72, 0x7b, 0xa5, 0xb0, 0x04, 0xb2, 0xfb, 0x96, 0x9c, 0x87, 0xc6, 0x88, - 0xcb, 0x48, 0x19, 0xa2, 0x0e, 0xc9, 0x22, 0x2e, 0x92, 0x36, 0x78, 0x2b, 0x41, 0x6e, 0xef, 0x4e, - 0xa8, 0xce, 0x83, 0x26, 0xc9, 0x5a, 0xca, 0x34, 0xe9, 0x93, 0x26, 0xbd, 0x44, 0x7a, 0xab, 0x93, - 0x3e, 0xff, 0x57, 0x26, 0xc5, 0x27, 0xcf, 0x23, 0xce, 0x58, 0x1a, 0x01, 0x25, 0xc7, 0x29, 0xc4, - 0xde, 0x5a, 0x90, 0xdb, 0x5b, 0x0e, 0x4b, 0xf2, 0xbc, 0xc5, 0x58, 0xda, 0x30, 0x46, 0x75, 0xe0, - 0x51, 0x90, 0xaa, 0x95, 0xde, 0xba, 0x39, 0xf0, 0xec, 0x27, 0xfe, 0x37, 0x5a, 0x3d, 0x66, 0x4c, - 0x66, 0x52, 0x10, 0x1e, 0x71, 0x50, 0x13, 0x82, 0x83, 0xf9, 0xbd, 0x7c, 0xb8, 0x72, 0x61, 0x6e, - 0x29, 0x2b, 0x7e, 0x80, 0x90, 0x8d, 0x51, 0x5b, 0x7d, 0x43, 0x57, 0x95, 0xb7, 0x96, 0xa3, 0x18, - 0x3f, 0x47, 0xa5, 0x1e, 0x49, 0x68, 0xe4, 0x36, 0xbf, 0xb7, 0x79, 0xed, 0xb1, 0x5c, 0x54, 0x8e, - 0x47, 0xd6, 0x0f, 0x77, 0x91, 0x97, 0xf5, 0x88, 0x90, 0xba, 0xa3, 0x82, 0xb4, 0xa5, 0x9b, 0x66, - 0xc8, 0xbc, 0x2d, 0x7d, 0x73, 0x54, 0x1c, 0xc6, 0x78, 0x4f, 0x57, 0xde, 0xab, 0x90, 0x03, 0x1b, - 0x51, 0x77, 0x01, 0x0d, 0x2a, 0xc5, 0x30, 0xdc, 0xce, 0x66, 0x2e, 0xe2, 0xc7, 0xa8, 0xc4, 0xb9, - 0x60, 0x27, 0x17, 0x52, 0x6d, 0x6b, 0xa9, 0x8a, 0xda, 0x68, 0x95, 0xf2, 0x8f, 0xd0, 0xfd, 0x1b, - 0xb0, 0xdd, 0xfd, 0x90, 0x1b, 0xdf, 0x0f, 0x9b, 0x68, 0x61, 0x40, 0xd2, 0xbe, 0x3b, 0x78, 0xcd, - 0xc7, 0xab, 0xb9, 0x17, 0xb9, 0xda, 0x1f, 0x79, 0x54, 0x32, 0x29, 0xbf, 0x37, 0x97, 0x3e, 0x26, - 0x28, 0xdf, 0x04, 0x69, 0x6c, 0x78, 0x7b, 0x6a, 0xb0, 0x1a, 0xea, 0xda, 0xf6, 0xf1, 0x74, 0xb9, - 0xe5, 0xbd, 0x51, 0x7d, 0xdd, 0x5f, 0x6d, 0x82, 0x0c, 0xd4, 0x1e, 0x0b, 0xcc, 0xca, 0x97, 0x3f, - 0xff, 0xfa, 0x6d, 0x6e, 0x05, 0x17, 0xab, 0xf6, 0x69, 0xa1, 0x76, 0x24, 0xee, 0x6b, 0x0a, 0xa3, - 0x36, 0xf6, 0x1c, 0xd4, 0xd5, 0x3b, 0xdd, 0x9f, 0xd1, 0x97, 0xf2, 0xab, 0x51, 0x7d, 0xc3, 0x5f, - 0x57, 0x24, 0xc6, 0x38, 0x49, 0xb3, 0x8b, 0x77, 0x1c, 0x8d, 0xd4, 0x8b, 0x59, 0xf5, 0xa7, 0xf1, - 0x5d, 0xfc, 0x33, 0x1e, 0xa2, 0xd2, 0xe4, 0x1b, 0x20, 0xbb, 0xb6, 0xba, 0x9d, 0x89, 0x94, 0xa6, - 0x9e, 0x0c, 0xe5, 0xda, 0xa8, 0xee, 0xf9, 0xdb, 0x2a, 0x85, 0x7a, 0x9a, 0x5e, 0x4e, 0x23, 0xd3, - 0x79, 0xac, 0xe3, 0xd5, 0x2b, 0x79, 0xe0, 0x14, 0x15, 0x0f, 0x04, 0x10, 0x09, 0x56, 0xd7, 0x19, - 0xfa, 0xcd, 0xd4, 0xf4, 0xbf, 0xa3, 0xba, 0xef, 0x7b, 0x26, 0x34, 0x0b, 0x94, 0x78, 0x81, 0x71, - 0x0a, 0xd4, 0xb3, 0xc1, 0xb0, 0x95, 0x2f, 0x89, 0xfb, 0x2a, 0xf7, 0x14, 0x7f, 0x76, 0x6c, 0x56, - 0xe2, 0x19, 0x42, 0xce, 0x14, 0xf7, 0xe5, 0xa8, 0xbe, 0xe3, 0xfb, 0x8e, 0xcd, 0xe4, 0x3e, 0xc5, - 0xb7, 0x59, 0xbe, 0x5a, 0x9d, 0xa2, 0xfc, 0x3d, 0x87, 0x56, 0x9a, 0x40, 0x41, 0x8c, 0x59, 0x6f, - 0x9d, 0x9d, 0x09, 0xe6, 0x1f, 0x47, 0xf5, 0xa6, 0xdf, 0x70, 0x00, 0xb3, 0xb8, 0x03, 0x49, 0x4e, - 0x13, 0xda, 0x09, 0xec, 0x7b, 0x22, 0x0b, 0x8e, 0x49, 0x06, 0x71, 0xc0, 0x68, 0x20, 0xbb, 0x10, - 0xa8, 0xdd, 0x6a, 0x83, 0x74, 0x92, 0x7e, 0xd9, 0xbb, 0x3a, 0x0a, 0x1d, 0x0b, 0x8e, 0x3b, 0xa8, - 0x68, 0x9e, 0x72, 0x5f, 0xd9, 0x8b, 0xea, 0xa8, 0xbe, 0xe5, 0xdb, 0x57, 0xe0, 0xa5, 0x5e, 0x98, - 0x36, 0xf8, 0x53, 0x6d, 0xf8, 0x92, 0x73, 0x4c, 0x56, 0x91, 0xfb, 0x0e, 0x75, 0xc6, 0x53, 0x72, - 0xa6, 0x2c, 0xf5, 0x51, 0xfd, 0xae, 0xbf, 0xe5, 0x28, 0x2f, 0x89, 0xa2, 0x49, 0x1f, 0xf9, 0x37, - 0x4e, 0xbc, 0x4a, 0x22, 0x45, 0xc5, 0x43, 0x48, 0xe1, 0xa2, 0xda, 0xeb, 0xba, 0x72, 0x8d, 0xbd, - 0xfc, 0x4c, 0x57, 0x6d, 0x20, 0xa6, 0xab, 0x5e, 0x79, 0x7a, 0x79, 0x67, 0xff, 0x92, 0x73, 0x74, - 0xb7, 0xee, 0xee, 0xeb, 0x08, 0x5f, 0xeb, 0x9a, 0x1d, 0xe1, 0x74, 0xcd, 0xbb, 0x4f, 0x6f, 0xac, - 0xf9, 0xcd, 0x13, 0x84, 0xda, 0xac, 0x67, 0x69, 0xdf, 0x14, 0xed, 0xb1, 0xd6, 0x52, 0x24, 0xad, - 0xdc, 0x77, 0xcb, 0xc6, 0xce, 0x8f, 0x8f, 0x17, 0x35, 0xef, 0x7f, 0xfe, 0x09, 0x00, 0x00, 0xff, - 0xff, 0xab, 0xbc, 0x5e, 0x33, 0xf5, 0x0c, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_21a2bc638067bc54) } + +var fileDescriptor_service_21a2bc638067bc54 = []byte{ + // 1317 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xdb, 0x6e, 0x1b, 0x37, + 0x13, 0xc6, 0xda, 0xf1, 0x89, 0x92, 0x7c, 0xa0, 0x0f, 0xd9, 0x6c, 0x1c, 0x67, 0xa3, 0xe0, 0xcf, + 0x6f, 0x04, 0xbf, 0x65, 0x40, 0xff, 0x45, 0x0e, 0x17, 0x01, 0x14, 0x5b, 0x10, 0x8c, 0x36, 0xa9, + 0xb0, 0x49, 0x10, 0xb4, 0x45, 0xb1, 0xa0, 0xb5, 0x63, 0x69, 0xeb, 0x15, 0xc9, 0x90, 0x5c, 0xdb, + 0x42, 0x51, 0xa0, 0x08, 0x7a, 0xd5, 0x4b, 0xf7, 0x25, 0xfa, 0x3e, 0x7d, 0x85, 0xf6, 0x3d, 0x0a, + 0x1e, 0x56, 0x52, 0x64, 0xd9, 0x46, 0xaf, 0xa4, 0xfd, 0x66, 0xe6, 0x9b, 0x8f, 0xc3, 0x19, 0x92, + 0x68, 0xa3, 0xc3, 0xe8, 0x49, 0xda, 0xdd, 0x97, 0x20, 0xce, 0xd2, 0x0e, 0xd4, 0xb8, 0x60, 0x8a, + 0xe1, 0x79, 0x8b, 0x06, 0xdb, 0x5d, 0xc6, 0xba, 0x19, 0xec, 0x13, 0x9e, 0xee, 0x13, 0x4a, 0x99, + 0x22, 0x2a, 0x65, 0x54, 0x5a, 0xaf, 0x60, 0xc7, 0x59, 0xcd, 0xd7, 0x71, 0x7e, 0xb2, 0x9f, 0xe4, + 0xc2, 0x38, 0x38, 0xfb, 0xfd, 0x49, 0x3b, 0xf4, 0xb9, 0x1a, 0x38, 0xe3, 0xff, 0xcc, 0x4f, 0x67, + 0xaf, 0x0b, 0x74, 0x4f, 0x9e, 0x93, 0x6e, 0x17, 0xc4, 0x3e, 0xe3, 0x86, 0xfe, 0x6a, 0xaa, 0x6a, + 0x1d, 0xad, 0xb6, 0x40, 0xbd, 0x07, 0x4a, 0xa8, 0x8a, 0xe0, 0x53, 0x0e, 0x52, 0xe1, 0x1d, 0x84, + 0xd2, 0x04, 0xa8, 0x4a, 0x4f, 0x52, 0x10, 0xbe, 0x17, 0x7a, 0xbb, 0x4b, 0xd1, 0x18, 0x52, 0x7d, + 0x85, 0x36, 0x5a, 0xa0, 0x1a, 0x59, 0x56, 0x84, 0x49, 0xce, 0xa8, 0x04, 0xfc, 0x04, 0xdd, 0x49, + 0x88, 0x22, 0xbe, 0x17, 0xce, 0xee, 0x96, 0xea, 0xb8, 0x66, 0xd7, 0x5a, 0xb3, 0x5e, 0x87, 0x44, + 0x91, 0xc8, 0xd8, 0xab, 0x3f, 0xa0, 0xf5, 0x0f, 0x3c, 0x21, 0x0a, 0xfe, 0x55, 0xda, 0x21, 0xfd, + 0x4c, 0xe8, 0xdd, 0x48, 0xff, 0x2d, 0x5a, 0x69, 0xaa, 0x1e, 0x08, 0xc8, 0xfb, 0x8d, 0x4e, 0x87, + 0xe5, 0x54, 0x61, 0x1f, 0x2d, 0x90, 0x24, 0x11, 0x20, 0xa5, 0xe3, 0x2d, 0x3e, 0xf1, 0x2a, 0x9a, + 0x3d, 0x85, 0x81, 0xe1, 0x5c, 0x8a, 0xf4, 0x5f, 0x1c, 0xa0, 0x45, 0x4e, 0xa4, 0x3c, 0x67, 0x22, + 0xf1, 0x67, 0x0d, 0x3c, 0xfc, 0xae, 0xee, 0xa1, 0x85, 0xaf, 0x60, 0xd0, 0x26, 0xa9, 0xd0, 0x81, + 0x3c, 0x3f, 0x76, 0x74, 0xfa, 0xaf, 0x41, 0xce, 0x54, 0x41, 0xc5, 0xcf, 0x54, 0xf5, 0xef, 0x19, + 0x84, 0x46, 0xf2, 0xf0, 0x73, 0x54, 0x02, 0xd5, 0x8b, 0x89, 0x15, 0x65, 0x42, 0x4b, 0xf5, 0xbb, + 0xc5, 0x3a, 0x26, 0x34, 0x47, 0x08, 0x54, 0xaf, 0xd0, 0xff, 0x0c, 0xf9, 0x3a, 0x32, 0x81, 0x13, + 0x92, 0x67, 0xaa, 0x60, 0x88, 0x29, 0xe9, 0x83, 0xcb, 0xb7, 0x09, 0xaa, 0x77, 0x68, 0xcd, 0x2e, + 0xe8, 0x2d, 0xe9, 0x03, 0x7e, 0x83, 0x1e, 0x0b, 0xe8, 0x40, 0x7a, 0x06, 0x31, 0x9c, 0x81, 0x0e, + 0x61, 0xba, 0x9a, 0x1d, 0xd3, 0x03, 0x31, 0xd0, 0x84, 0xb3, 0x94, 0x2a, 0xb7, 0xce, 0xd0, 0xb9, + 0x36, 0xb5, 0xe7, 0xdb, 0x31, 0xc7, 0xa6, 0xf3, 0xc3, 0x0f, 0x51, 0xc9, 0x6e, 0x88, 0x1a, 0xc4, + 0x69, 0xe2, 0xdf, 0x19, 0xdf, 0x23, 0x35, 0x38, 0x4a, 0xf0, 0x0b, 0xb4, 0x2a, 0xd3, 0x2e, 0x4d, + 0x69, 0x37, 0x3e, 0x85, 0x41, 0xcc, 0x49, 0x2a, 0xfc, 0x39, 0xb3, 0xce, 0x95, 0x62, 0x9d, 0xae, + 0x80, 0xd1, 0xb2, 0x73, 0x2c, 0x0a, 0xfa, 0x02, 0xad, 0x82, 0xea, 0x91, 0x5c, 0xf5, 0x46, 0xa1, + 0xf3, 0xd7, 0x84, 0x3a, 0x47, 0xf7, 0x5d, 0xfd, 0x75, 0x09, 0xa1, 0x03, 0xe3, 0x62, 0xea, 0xfc, + 0x08, 0x95, 0xa5, 0x62, 0x82, 0x74, 0x21, 0xe6, 0x44, 0xf5, 0xdc, 0x1e, 0x95, 0x1c, 0xd6, 0x26, + 0xaa, 0x87, 0xef, 0xa1, 0x45, 0x5e, 0xe7, 0x31, 0x67, 0xc2, 0x6e, 0xd8, 0x5c, 0xb4, 0xc0, 0xeb, + 0xbc, 0xcd, 0x84, 0xc2, 0x4f, 0xd0, 0x8a, 0x36, 0xc1, 0x85, 0x02, 0x41, 0x49, 0x16, 0xa7, 0xdc, + 0x95, 0xa7, 0xc2, 0xeb, 0xbc, 0xe9, 0xd0, 0x23, 0x8e, 0xbf, 0x41, 0x5b, 0xda, 0xaf, 0xc3, 0x28, + 0x85, 0x8e, 0x29, 0xa7, 0x4a, 0xfb, 0xc0, 0x72, 0x65, 0xca, 0x52, 0xaa, 0xdf, 0xab, 0xd9, 0x29, + 0xad, 0x15, 0x53, 0x5a, 0x3b, 0x74, 0x53, 0x1c, 0x6d, 0xf0, 0x3a, 0x3f, 0x18, 0xc6, 0xbd, 0xb7, + 0x61, 0xba, 0xb8, 0xfa, 0xb0, 0x00, 0x61, 0x65, 0xcd, 0x19, 0x59, 0xc8, 0x42, 0x46, 0xd9, 0x7f, + 0xd0, 0xb2, 0x73, 0x28, 0x9a, 0x79, 0xde, 0x0a, 0xb3, 0x68, 0xc3, 0xb5, 0xf4, 0x43, 0x54, 0xa2, + 0x79, 0x3f, 0x3e, 0x67, 0xe2, 0x14, 0x84, 0xf4, 0x17, 0x2c, 0x0f, 0xcd, 0xfb, 0x1f, 0x2d, 0x82, + 0xf7, 0xd0, 0xba, 0x35, 0xc6, 0xe7, 0x24, 0x55, 0x46, 0x76, 0xdc, 0x97, 0xfe, 0xa2, 0x71, 0x5c, + 0xb5, 0xa6, 0x8f, 0x24, 0x55, 0x5a, 0xd8, 0x1b, 0x89, 0x43, 0x54, 0xd6, 0xcd, 0x47, 0x59, 0x02, + 0x71, 0x2e, 0x32, 0x7f, 0xc9, 0xee, 0x3a, 0xa8, 0xde, 0x5b, 0x96, 0xc0, 0x07, 0x91, 0xe1, 0xef, + 0xd1, 0x03, 0xed, 0xd1, 0x61, 0x54, 0xc1, 0x85, 0x8a, 0x05, 0x90, 0x64, 0x44, 0xad, 0x2b, 0x82, + 0x6e, 0xab, 0xc8, 0x3d, 0x50, 0xbd, 0x03, 0x1b, 0x1e, 0x01, 0x49, 0x8a, 0xec, 0xba, 0x2c, 0x91, + 0xed, 0xfd, 0x82, 0xfc, 0x0b, 0xde, 0xd2, 0x6d, 0xbc, 0x9b, 0x23, 0xde, 0x71, 0xce, 0x16, 0xc2, + 0x9a, 0x33, 0xa5, 0x0a, 0xc4, 0x19, 0xc9, 0x62, 0x01, 0x4a, 0x0c, 0xfc, 0xf2, 0x6d, 0x6c, 0xba, + 0x41, 0x8f, 0x5c, 0x4c, 0xa4, 0x43, 0x74, 0xb3, 0x68, 0xa2, 0x3e, 0xb9, 0x30, 0x1c, 0x29, 0x48, + 0xbf, 0x12, 0x7a, 0xbb, 0x95, 0xa8, 0x02, 0xaa, 0xf7, 0x86, 0x5c, 0x44, 0x16, 0xc4, 0x55, 0xa4, + 0x81, 0xb8, 0x4b, 0x64, 0xcc, 0x45, 0xda, 0x01, 0x7f, 0x39, 0xf4, 0x76, 0xef, 0x44, 0xfa, 0x3c, + 0x68, 0x11, 0xd9, 0xd6, 0xd0, 0xb8, 0x4f, 0x96, 0xf6, 0x53, 0xe5, 0xaf, 0x8c, 0xfb, 0x7c, 0xad, + 0x21, 0x9d, 0x4f, 0x5d, 0xc4, 0x9c, 0xb1, 0x2c, 0x06, 0x4a, 0x8e, 0x33, 0x48, 0xfc, 0xd5, 0xd0, + 0xdb, 0x5d, 0x8c, 0x2a, 0xea, 0xa2, 0xcd, 0x58, 0xd6, 0xb4, 0xa0, 0x3e, 0xf0, 0x28, 0x28, 0xbd, + 0x95, 0xfe, 0x9a, 0x3d, 0xf0, 0xdc, 0x27, 0xfe, 0x2f, 0x5a, 0x39, 0x66, 0x4c, 0x49, 0x25, 0x08, + 0x8f, 0x39, 0xe8, 0x0e, 0xc1, 0xe1, 0xec, 0xee, 0x52, 0xb4, 0x3c, 0x84, 0xdb, 0x1a, 0xc5, 0x0f, + 0x10, 0x72, 0x31, 0x7a, 0xd4, 0xd7, 0xcd, 0xaa, 0x96, 0x1c, 0x72, 0x94, 0xe0, 0x67, 0xa8, 0xd2, + 0x27, 0x29, 0x8d, 0x8b, 0xe1, 0xf7, 0x37, 0xae, 0x3d, 0x96, 0xcb, 0xda, 0xf1, 0xc8, 0xf9, 0xe1, + 0x1e, 0xf2, 0x65, 0x9f, 0x08, 0x65, 0x76, 0x54, 0x90, 0x8e, 0x2a, 0xba, 0x19, 0xa4, 0xbf, 0x69, + 0x6e, 0x8e, 0x5a, 0xc1, 0x31, 0x9a, 0xe9, 0xda, 0x3b, 0x1d, 0x72, 0xe0, 0x22, 0x1a, 0x45, 0x40, + 0x93, 0x2a, 0x31, 0x88, 0xb6, 0xe4, 0x54, 0x23, 0x7e, 0x8c, 0x2a, 0x9c, 0x0b, 0x76, 0x32, 0x2c, + 0xd5, 0x96, 0x29, 0x55, 0xd9, 0x80, 0xae, 0x52, 0xc1, 0x11, 0xba, 0x7f, 0x03, 0x77, 0x71, 0x3f, + 0x78, 0xa3, 0xfb, 0x61, 0x03, 0xcd, 0x9d, 0x91, 0x2c, 0x2f, 0x0e, 0x5e, 0xfb, 0xf1, 0x72, 0xe6, + 0xb9, 0x57, 0xff, 0x6d, 0x01, 0x55, 0xac, 0xe4, 0x77, 0xf6, 0xd2, 0xc7, 0x04, 0x2d, 0xb5, 0x40, + 0x59, 0x0c, 0x6f, 0x5d, 0x69, 0xac, 0xa6, 0xbe, 0xb6, 0x03, 0x7c, 0x75, 0xb9, 0xd5, 0xdd, 0xcb, + 0xc6, 0x5a, 0xb0, 0xd2, 0x02, 0x15, 0xea, 0x19, 0x0b, 0xad, 0xe5, 0xf3, 0x9f, 0x7f, 0xfd, 0x3e, + 0xb3, 0x8c, 0xcb, 0xfb, 0xee, 0x69, 0xa1, 0x27, 0x12, 0xe7, 0x26, 0x85, 0xad, 0x36, 0xf6, 0x0b, + 0xaa, 0xc9, 0x3b, 0x3d, 0x98, 0xb2, 0x2f, 0xd5, 0x97, 0x97, 0x8d, 0xf5, 0x60, 0x4d, 0x27, 0xb1, + 0xe0, 0x78, 0x9a, 0x1d, 0xbc, 0x5d, 0xa4, 0x51, 0xc6, 0x28, 0xf7, 0x7f, 0x1a, 0xdd, 0xc5, 0x3f, + 0xe3, 0x01, 0xaa, 0x8c, 0xbf, 0x01, 0xe4, 0xb5, 0xab, 0xdb, 0x1e, 0x93, 0x74, 0xe5, 0xc9, 0x50, + 0xad, 0x5f, 0x36, 0xfc, 0x60, 0x4b, 0x4b, 0x68, 0x64, 0xd9, 0x97, 0x32, 0xa4, 0xd1, 0xb1, 0x86, + 0x57, 0x26, 0x74, 0xe0, 0x4f, 0xa8, 0x7c, 0x20, 0x60, 0xf8, 0x7c, 0xc0, 0x53, 0x96, 0x36, 0x75, + 0xb9, 0x2f, 0x2e, 0x1b, 0xdb, 0x41, 0x60, 0x43, 0x65, 0x68, 0xd9, 0x42, 0xeb, 0x16, 0xea, 0x87, + 0x83, 0xc9, 0xb7, 0x51, 0x9d, 0xcc, 0xf7, 0xd2, 0x7b, 0x8a, 0xff, 0xf0, 0xd0, 0x72, 0x0b, 0x28, + 0x88, 0x51, 0xd6, 0x5b, 0x77, 0x73, 0x2c, 0xf3, 0x8f, 0x97, 0x8d, 0x56, 0xd0, 0x2c, 0x08, 0xa6, + 0xe5, 0x0e, 0x15, 0x39, 0x4d, 0x69, 0x37, 0x74, 0x37, 0xbc, 0x0c, 0x8f, 0x89, 0x84, 0x24, 0x64, + 0x34, 0x54, 0x3d, 0x08, 0xf5, 0xfc, 0xb8, 0x20, 0x23, 0x32, 0xa8, 0xfa, 0x93, 0x9b, 0xd3, 0x75, + 0xe4, 0xf8, 0xb3, 0x87, 0xca, 0xe3, 0xaf, 0x2b, 0x7c, 0xbf, 0x10, 0x34, 0xe5, 0xcd, 0x35, 0x55, + 0x6d, 0xe3, 0xb2, 0x71, 0x37, 0xd8, 0xb4, 0xde, 0x13, 0x5a, 0x4d, 0xf6, 0x47, 0xc1, 0x8d, 0xad, + 0xa1, 0xeb, 0xf5, 0x8b, 0x87, 0xca, 0x87, 0x90, 0xc1, 0x50, 0xc4, 0xf5, 0x8d, 0x79, 0x4d, 0x1d, + 0xab, 0xaf, 0x8c, 0x0a, 0x4b, 0x32, 0x4d, 0xc5, 0xce, 0xd3, 0x1b, 0x55, 0xbc, 0x7e, 0x82, 0x50, + 0x87, 0xf5, 0x5d, 0xda, 0xd7, 0x65, 0x37, 0x91, 0x6d, 0x9d, 0xa4, 0xed, 0x7d, 0xb7, 0x68, 0x71, + 0x7e, 0x7c, 0x3c, 0x6f, 0xf2, 0xfe, 0xff, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x40, 0x4e, + 0x42, 0xb0, 0x0b, 0x00, 0x00, } diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go index 66f81783e..3c4ff61af 100644 --- a/protobufs/gen/go/config/service.pb.gw.go +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -74,19 +74,6 @@ func request_ConfigService_GetAllTenants_0(ctx context.Context, marshaler runtim } -func request_ConfigService_CreateConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ConfigData - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.CreateConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - func request_ConfigService_CreateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq TenantData var metadata runtime.ServerMetadata @@ -109,19 +96,6 @@ func request_ConfigService_GenerateTenant_0(ctx context.Context, marshaler runti } -func request_ConfigService_UpdateConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ConfigData - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.UpdateConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - func request_ConfigService_UpdateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateTenantRequest var metadata runtime.ServerMetadata @@ -153,15 +127,6 @@ func request_ConfigService_UpdateTenant_0(ctx context.Context, marshaler runtime } -func request_ConfigService_DeleteConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.DeleteConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - func request_ConfigService_DeleteTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetTenantRequest var metadata runtime.ServerMetadata @@ -314,35 +279,6 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("POST", pattern_ConfigService_CreateConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_CreateConfig_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_CreateConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("POST", pattern_ConfigService_CreateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -401,35 +337,6 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("PUT", pattern_ConfigService_UpdateConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_UpdateConfig_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_UpdateConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("PUT", pattern_ConfigService_UpdateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -459,35 +366,6 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("DELETE", pattern_ConfigService_DeleteConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_DeleteConfig_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_DeleteConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("DELETE", pattern_ConfigService_DeleteTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -527,18 +405,12 @@ var ( pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) - pattern_ConfigService_CreateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) pattern_ConfigService_GenerateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"config", "tenants", "generate"}, "")) - pattern_ConfigService_UpdateConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) - pattern_ConfigService_DeleteConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - pattern_ConfigService_DeleteTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) ) @@ -549,17 +421,11 @@ var ( forward_ConfigService_GetAllTenants_0 = runtime.ForwardResponseMessage - forward_ConfigService_CreateConfig_0 = runtime.ForwardResponseMessage - forward_ConfigService_CreateTenant_0 = runtime.ForwardResponseMessage forward_ConfigService_GenerateTenant_0 = runtime.ForwardResponseMessage - forward_ConfigService_UpdateConfig_0 = runtime.ForwardResponseMessage - forward_ConfigService_UpdateTenant_0 = runtime.ForwardResponseMessage - forward_ConfigService_DeleteConfig_0 = runtime.ForwardResponseMessage - forward_ConfigService_DeleteTenant_0 = runtime.ForwardResponseMessage ) diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 22c0ef890..d3c6f12e5 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]},"delete":{"description":"Deletes node config","operationId":"DeleteConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"tags":["ConfigService"]},"post":{"description":"Creates node config data","operationId":"CreateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]},"put":{"description":"Updates node config","operationId":"UpdateConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configConfigData"}}],"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index b3d4e504b..2168b7a6e 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -30,71 +30,6 @@ "tags": [ "ConfigService" ] - }, - "delete": { - "description": "Deletes node config", - "operationId": "DeleteConfig", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/protobufEmpty" - } - } - }, - "tags": [ - "ConfigService" - ] - }, - "post": { - "description": "Creates node config data", - "operationId": "CreateConfig", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configConfigData" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/configConfigData" - } - } - ], - "tags": [ - "ConfigService" - ] - }, - "put": { - "description": "Updates node config", - "operationId": "UpdateConfig", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configConfigData" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/configConfigData" - } - } - ], - "tags": [ - "ConfigService" - ] } }, "/config/tenants": { diff --git a/transactions/handler.go b/transactions/handler.go index 43afb80ab..3442f1d9d 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -33,7 +33,7 @@ type grpcHandler struct { // GetTransactionStatus returns transaction status of the given transaction id. func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactionspb.TransactionStatusRequest) (*transactionspb.TransactionStatusResponse, error) { - ctxHeader, err := contextutil.CentContext(ctx, h.configService) + ctxHeader, err := contextutil.Context(ctx, h.configService) if err != nil { apiLog.Error(err) return nil, err From f42b7eba6d013581286e7de4f449aa8bf00659c4 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 16 Jan 2019 14:58:37 +0100 Subject: [PATCH 137/220] add account fields to notification (#653) * add account fields to notification * comments + proto-gen --- Gopkg.lock | 4 ++-- Gopkg.toml | 2 +- documents/genericdoc/service.go | 4 +++- notification/notification_test.go | 16 ++++++++++++---- protobufs/gen/swagger.json | 2 +- .../swagger/notification/service.swagger.json | 15 ++++++++++++--- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 593ec870f..88dfe5839 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:3d0c4f984f055ca85e5d2d74ac26413644ca894279dc6d3369cd845041afe63e" + digest = "1:55060176e56680808b3d9be771d0baa31512b7743ffbaea4f61471dbba649be7" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "e9b3e7ce470fd8e11d29450fcdd49873ae102dc7" + revision = "f93686ceaf40283c7dc496c62fcc69b1c1a272e3" [[projects]] digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" diff --git a/Gopkg.toml b/Gopkg.toml index b0df5c831..84ba1b9ad 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "e9b3e7ce470fd8e11d29450fcdd49873ae102dc7" + revision = "f93686ceaf40283c7dc496c62fcc69b1c1a272e3" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 252eeb04b..24e92c44a 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -212,7 +212,9 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Mo ts, _ := ptypes.TimestampProto(time.Now().UTC()) notificationMsg := ¬ificationpb.NotificationMessage{ EventType: uint32(notification.ReceivedPayload), - CentrifugeId: hexutil.Encode(senderID), + AccountId: idConf.ID.String(), + FromId: hexutil.Encode(senderID), + ToId: idConf.ID.String(), Recorded: ts, DocumentType: doc.EmbeddedData.TypeUrl, DocumentId: hexutil.Encode(doc.DocumentIdentifier), diff --git a/notification/notification_test.go b/notification/notification_test.go index 262b2fc14..76383706e 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -50,7 +52,8 @@ func (m mockConfig) GetReceiveEventNotificationEndpoint() string { func TestWebhookSender_Send(t *testing.T) { docID := utils.RandomSlice(32) - cid := utils.RandomSlice(32) + accountID := utils.RandomSlice(identity.CentIDLength) + senderID := utils.RandomSlice(identity.CentIDLength) ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") var wg sync.WaitGroup @@ -59,7 +62,9 @@ func TestWebhookSender_Send(t *testing.T) { mux.HandleFunc("/webhook", func(writer http.ResponseWriter, request *http.Request) { var resp struct { EventType uint32 `json:"event_type,omitempty"` - CentrifugeId string `json:"centrifuge_id,omitempty"` + AccountId string `json:"account_id,omitempty"` + FromId string `json:"from_id,omitempty"` + ToId string `json:"to_id,omitempty"` Recorded *timestamp.Timestamp `json:"recorded,omitempty"` DocumentType string `json:"document_type,omitempty"` DocumentId string `json:"document_id,omitempty"` @@ -72,7 +77,8 @@ func TestWebhookSender_Send(t *testing.T) { assert.NoError(t, err) writer.Write([]byte("success")) assert.Equal(t, hexutil.Encode(docID), resp.DocumentId) - assert.Equal(t, hexutil.Encode(cid), resp.CentrifugeId) + assert.Equal(t, hexutil.Encode(accountID), resp.AccountId) + assert.Equal(t, hexutil.Encode(senderID), resp.FromId) wg.Done() }) @@ -84,7 +90,9 @@ func TestWebhookSender_Send(t *testing.T) { notif := ¬ificationpb.NotificationMessage{ DocumentId: hexutil.Encode(docID), DocumentType: documenttypes.InvoiceDataTypeUrl, - CentrifugeId: hexutil.Encode(cid), + AccountId: hexutil.Encode(accountID), + FromId: hexutil.Encode(senderID), + ToId: hexutil.Encode(accountID), EventType: uint32(ReceivedPayload), Recorded: ts, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index d3c6f12e5..6b44f7814 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"centrifuge_id":{"type":"string"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/notification/service.swagger.json b/protobufs/gen/swagger/notification/service.swagger.json index 8d1e1f753..66cbc2d89 100644 --- a/protobufs/gen/swagger/notification/service.swagger.json +++ b/protobufs/gen/swagger/notification/service.swagger.json @@ -41,9 +41,6 @@ "type": "integer", "format": "int64" }, - "centrifuge_id": { - "type": "string" - }, "recorded": { "type": "string", "format": "date-time" @@ -53,6 +50,18 @@ }, "document_id": { "type": "string" + }, + "account_id": { + "type": "string", + "title": "account_id is the account associated to webhook" + }, + "from_id": { + "type": "string", + "title": "from_id if provided, original trigger of the event" + }, + "to_id": { + "type": "string", + "title": "to_id if provided, final destination of the event" } }, "title": "NotificationMessage wraps a single CoreDocument to be notified to upstream services" From d25506ea30c2bbba94235139ad057f6699525686 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 16 Jan 2019 16:57:01 +0100 Subject: [PATCH 138/220] Account rename 1: move API /config/tenants => /accounts (#654) * move API /config/tenants => /accounts * move API /config/tenants => /accounts * Review comments --- api/service.go | 8 + config/configstore/handler.go | 41 +- config/configstore/handler_test.go | 69 +- config/configstore/model.go | 21 +- config/configuration.go | 3 +- protobufs/account/service.proto | 91 +++ protobufs/config/service.proto | 90 +-- protobufs/gen/go/account/service.pb.go | 591 +++++++++++++++ protobufs/gen/go/account/service.pb.gw.go | 329 ++++++++ protobufs/gen/go/config/service.pb.go | 701 +++--------------- protobufs/gen/go/config/service.pb.gw.go | 316 +------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/account/service.swagger.json | 206 +++++ .../gen/swagger/config/service.swagger.json | 253 ++----- protobufs/prototool.yaml | 2 +- resources/data.go | 4 +- testworld/httputils.go | 8 +- 17 files changed, 1417 insertions(+), 1318 deletions(-) create mode 100644 protobufs/account/service.proto create mode 100644 protobufs/gen/go/account/service.pb.go create mode 100644 protobufs/gen/go/account/service.pb.gw.go create mode 100644 protobufs/gen/swagger/account/service.swagger.json diff --git a/api/service.go b/api/service.go index ae90dbcea..9a0998581 100644 --- a/api/service.go +++ b/api/service.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/healthcheck" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/health" @@ -99,6 +100,13 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, return err } + // account api + accountpb.RegisterAccountServiceServer(grpcServer, configstore.GRPCAccountHandler(configService)) + err = accountpb.RegisterAccountServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) + if err != nil { + return err + } + // transactions txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Service) h := transactions.GRPCHandler(txSrv, configService) diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 8f396b894..18b72e877 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -4,15 +4,14 @@ import ( "context" "github.com/centrifuge/go-centrifuge/config" - - "github.com/ethereum/go-ethereum/common/hexutil" - + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/empty" logging "github.com/ipfs/go-log" ) -var apiLog = logging.Logger("config-api") +var apiLog = logging.Logger("account-api") type grpcHandler struct { service config.Service @@ -23,8 +22,13 @@ func GRPCHandler(svc config.Service) configpb.ConfigServiceServer { return &grpcHandler{service: svc} } -func (h grpcHandler) deriveAllTenantResponse(cfgs []config.TenantConfiguration) (*configpb.GetAllTenantResponse, error) { - response := new(configpb.GetAllTenantResponse) +// GRPCAccountHandler returns an implementation of accountpb.AccountServiceServer +func GRPCAccountHandler(svc config.Service) accountpb.AccountServiceServer { + return &grpcHandler{service: svc} +} + +func (h grpcHandler) deriveAllTenantResponse(cfgs []config.TenantConfiguration) (*accountpb.GetAllAccountResponse, error) { + response := new(accountpb.GetAllAccountResponse) for _, t := range cfgs { response.Data = append(response.Data, t.CreateProtobuf()) } @@ -39,7 +43,7 @@ func (h grpcHandler) GetConfig(ctx context.Context, _ *empty.Empty) (*configpb.C return nodeConfig.CreateProtobuf(), nil } -func (h grpcHandler) GetTenant(ctx context.Context, req *configpb.GetTenantRequest) (*configpb.TenantData, error) { +func (h grpcHandler) GetAccount(ctx context.Context, req *accountpb.GetAccountRequest) (*accountpb.AccountData, error) { id, err := hexutil.Decode(req.Identifier) if err != nil { return nil, err @@ -51,7 +55,7 @@ func (h grpcHandler) GetTenant(ctx context.Context, req *configpb.GetTenantReque return tenantConfig.CreateProtobuf(), nil } -func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*configpb.GetAllTenantResponse, error) { +func (h grpcHandler) GetAllAccounts(ctx context.Context, req *empty.Empty) (*accountpb.GetAllAccountResponse, error) { cfgs, err := h.service.GetAllTenants() if err != nil { return nil, err @@ -59,8 +63,8 @@ func (h grpcHandler) GetAllTenants(ctx context.Context, _ *empty.Empty) (*config return h.deriveAllTenantResponse(cfgs) } -func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData) (*configpb.TenantData, error) { - apiLog.Infof("Creating tenant config: %v", data) +func (h grpcHandler) CreateAccount(ctx context.Context, data *accountpb.AccountData) (*accountpb.AccountData, error) { + apiLog.Infof("Creating account: %v", data) tenantConfig := new(TenantConfig) tenantConfig.loadFromProtobuf(data) tc, err := h.service.CreateTenant(tenantConfig) @@ -70,8 +74,8 @@ func (h grpcHandler) CreateTenant(ctx context.Context, data *configpb.TenantData return tc.CreateProtobuf(), nil } -func (h grpcHandler) GenerateTenant(context.Context, *empty.Empty) (*configpb.TenantData, error) { - apiLog.Infof("Generating tenant config") +func (h grpcHandler) GenerateAccount(ctx context.Context, req *empty.Empty) (*accountpb.AccountData, error) { + apiLog.Infof("Generating account") tc, err := h.service.GenerateTenant() if err != nil { return nil, err @@ -79,8 +83,8 @@ func (h grpcHandler) GenerateTenant(context.Context, *empty.Empty) (*configpb.Te return tc.CreateProtobuf(), nil } -func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenantRequest) (*configpb.TenantData, error) { - apiLog.Infof("Updating tenant config: %v", req) +func (h grpcHandler) UpdateAccount(ctx context.Context, req *accountpb.UpdateAccountRequest) (*accountpb.AccountData, error) { + apiLog.Infof("Updating account: %v", req) tenantConfig := new(TenantConfig) tenantConfig.loadFromProtobuf(req.Data) tc, err := h.service.UpdateTenant(tenantConfig) @@ -89,12 +93,3 @@ func (h grpcHandler) UpdateTenant(ctx context.Context, req *configpb.UpdateTenan } return tc.CreateProtobuf(), nil } - -func (h grpcHandler) DeleteTenant(ctx context.Context, req *configpb.GetTenantRequest) (*empty.Empty, error) { - apiLog.Infof("Deleting tenant config: %v", req.Identifier) - id, err := hexutil.Decode(req.Identifier) - if err != nil { - return nil, err - } - return nil, h.service.DeleteTenant(id) -} diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 9d95ce520..d7194e3b9 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -6,9 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/testingutils/commons" - - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) @@ -40,14 +39,14 @@ func TestGrpcHandler_GetConfig(t *testing.T) { assert.NotNil(t, readCfg) } -func TestGrpcHandler_GetTenantNoConfig(t *testing.T) { +func TestGrpcHandler_GetAccountNotExist(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) - h := GRPCHandler(svc) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: "0x123456789"}) + h := GRPCAccountHandler(svc) + readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: "0x123456789"}) assert.NotNil(t, err) assert.Nil(t, readCfg) } @@ -58,14 +57,14 @@ func TestGrpcHandler_GetTenant(t *testing.T) { assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) - h := GRPCHandler(svc) + h := GRPCAccountHandler(svc) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), tenantCfg.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), tenantCfg.CreateProtobuf()) assert.Nil(t, err) tid, err := tenantCfg.GetIdentityID() assert.Nil(t, err) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) + readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) assert.NotNil(t, readCfg) } @@ -76,17 +75,17 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) - h := GRPCHandler(svc) + h := GRPCAccountHandler(svc) tenantCfg1, err := NewTenantConfig("main", cfg) tenantCfg2, err := NewTenantConfig("main", cfg) tc := tenantCfg2.(*TenantConfig) tc.IdentityID = []byte("0x123456789") - _, err = h.CreateTenant(context.Background(), tenantCfg1.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), tenantCfg1.CreateProtobuf()) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), tc.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), tc.CreateProtobuf()) assert.Nil(t, err) - resp, err := h.GetAllTenants(context.Background(), nil) + resp, err := h.GetAllAccounts(context.Background(), nil) assert.Nil(t, err) assert.Equal(t, 2, len(resp.Data)) } @@ -97,14 +96,14 @@ func TestGrpcHandler_CreateTenant(t *testing.T) { assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) - h := GRPCHandler(svc) + h := GRPCAccountHandler(svc) nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) // Already exists - _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) assert.NotNil(t, err) } @@ -112,8 +111,8 @@ func TestGrpcHandler_GenerateTenant(t *testing.T) { s := MockService{} t1, _ := NewTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) s.On("GenerateTenant").Return(t1, nil) - h := GRPCHandler(s) - tc, err := h.GenerateTenant(context.Background(), nil) + h := GRPCAccountHandler(s) + tc, err := h.GenerateAccount(context.Background(), nil) assert.NoError(t, err) assert.NotNil(t, tc) } @@ -124,7 +123,7 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { assert.Nil(t, err) repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) - h := GRPCHandler(svc) + h := GRPCAccountHandler(svc) nodeCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) @@ -134,42 +133,16 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { tc := nodeCfg.(*TenantConfig) // Config doesn't exist - _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(tid), Data: nodeCfg.CreateProtobuf()}) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: nodeCfg.CreateProtobuf()}) assert.NotNil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) + _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) assert.Nil(t, err) tc.EthereumDefaultAccountName = "other" - _, err = h.UpdateTenant(context.Background(), &configpb.UpdateTenantRequest{Identifier: hexutil.Encode(tid), Data: tc.CreateProtobuf()}) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tc.CreateProtobuf()}) assert.Nil(t, err) - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) + readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) assert.Equal(t, tc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) } - -func TestGrpcHandler_DeleteTenant(t *testing.T) { - idService := &testingcommons.MockIDService{} - repo, _, err := getRandomStorage() - assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) - svc := DefaultService(repo, idService) - h := GRPCHandler(svc) - - //No error when no config - _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: "0x12345678"}) - assert.Nil(t, err) - - nodeCfg, err := NewTenantConfig("main", cfg) - assert.Nil(t, err) - _, err = h.CreateTenant(context.Background(), nodeCfg.CreateProtobuf()) - assert.Nil(t, err) - tid, err := nodeCfg.GetIdentityID() - assert.Nil(t, err) - _, err = h.DeleteTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) - assert.Nil(t, err) - - readCfg, err := h.GetTenant(context.Background(), &configpb.GetTenantRequest{Identifier: hexutil.Encode(tid)}) - assert.NotNil(t, err) - assert.Nil(t, readCfg) -} diff --git a/config/configstore/model.go b/config/configstore/model.go index b7c97c5da..fcdfaa173 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -274,8 +275,8 @@ func (nc *NodeConfig) FromJSON(data []byte) error { // CreateProtobuf creates protobuf for config func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { return &configpb.ConfigData{ - MainIdentity: &configpb.TenantData{ - EthAccount: &configpb.EthereumAccount{ + MainIdentity: &accountpb.AccountData{ + EthAccount: &accountpb.EthereumAccount{ Address: nc.MainIdentity.EthereumAccount.Address, Key: nc.MainIdentity.EthereumAccount.Key, Password: nc.MainIdentity.EthereumAccount.Password, @@ -283,11 +284,11 @@ func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { EthDefaultAccountName: nc.MainIdentity.EthereumDefaultAccountName, IdentityId: hexutil.Encode(nc.MainIdentity.IdentityID), ReceiveEventNotificationEndpoint: nc.MainIdentity.ReceiveEventNotificationEndpoint, - EthauthKeyPair: &configpb.KeyPair{ + EthauthKeyPair: &accountpb.KeyPair{ Pub: nc.MainIdentity.EthAuthKeyPair.Pub, Pvt: nc.MainIdentity.EthAuthKeyPair.Priv, }, - SigningKeyPair: &configpb.KeyPair{ + SigningKeyPair: &accountpb.KeyPair{ Pub: nc.MainIdentity.SigningKeyPair.Pub, Pvt: nc.MainIdentity.SigningKeyPair.Priv, }, @@ -510,9 +511,9 @@ func (tc *TenantConfig) FromJSON(data []byte) error { } // CreateProtobuf creates protobuf for config -func (tc *TenantConfig) CreateProtobuf() *configpb.TenantData { - return &configpb.TenantData{ - EthAccount: &configpb.EthereumAccount{ +func (tc *TenantConfig) CreateProtobuf() *accountpb.AccountData { + return &accountpb.AccountData{ + EthAccount: &accountpb.EthereumAccount{ Address: tc.EthereumAccount.Address, Key: tc.EthereumAccount.Key, Password: tc.EthereumAccount.Password, @@ -520,18 +521,18 @@ func (tc *TenantConfig) CreateProtobuf() *configpb.TenantData { EthDefaultAccountName: tc.EthereumDefaultAccountName, ReceiveEventNotificationEndpoint: tc.ReceiveEventNotificationEndpoint, IdentityId: hexutil.Encode(tc.IdentityID), - SigningKeyPair: &configpb.KeyPair{ + SigningKeyPair: &accountpb.KeyPair{ Pub: tc.SigningKeyPair.Pub, Pvt: tc.SigningKeyPair.Priv, }, - EthauthKeyPair: &configpb.KeyPair{ + EthauthKeyPair: &accountpb.KeyPair{ Pub: tc.EthAuthKeyPair.Pub, Pvt: tc.EthAuthKeyPair.Priv, }, } } -func (tc *TenantConfig) loadFromProtobuf(data *configpb.TenantData) { +func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) { tc.EthereumAccount = &config.AccountConfig{ Address: data.EthAccount.Address, Key: data.EthAccount.Key, diff --git a/config/configuration.go b/config/configuration.go index e9fd2289d..2ff3a0436 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -18,6 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/resources" "github.com/centrifuge/go-centrifuge/storage" @@ -123,7 +124,7 @@ type TenantConfiguration interface { GetEthereumContextWaitTimeout() time.Duration // CreateProtobuf creates protobuf - CreateProtobuf() *configpb.TenantData + CreateProtobuf() *accountpb.AccountData } // Service exposes functions over the config objects diff --git a/protobufs/account/service.proto b/protobufs/account/service.proto new file mode 100644 index 000000000..85b3e53ad --- /dev/null +++ b/protobufs/account/service.proto @@ -0,0 +1,91 @@ +syntax = "proto3"; + +package account; + +option go_package = "accountpb"; +option java_multiple_files = true; +option java_outer_classname = "ServiceProto"; +option java_package = "com.account"; + +import "google/api/annotations.proto"; +import "google/protobuf/empty.proto"; +import "protoc-gen-swagger/options/annotations.proto"; + +// AccountService allows to manage accounts in the node +service AccountService { + rpc GetAccount(GetAccountRequest) returns (AccountData) { + option (google.api.http) = { + get: "/accounts/{identifier}" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get Account" + }; + } + rpc GetAllAccounts(google.protobuf.Empty) returns (GetAllAccountResponse) { + option (google.api.http) = { + get: "/accounts" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Get All Accounts" + }; + } + rpc CreateAccount(AccountData) returns (AccountData) { + option (google.api.http) = { + post: "/accounts" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Creates an Account" + }; + } + rpc GenerateAccount(google.protobuf.Empty) returns (AccountData) { + option (google.api.http) = { + post: "/accounts/generate" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Generates an Account taking defaults based on the main account" + }; + } + rpc UpdateAccount(UpdateAccountRequest) returns (AccountData) { + option (google.api.http) = { + put: "/accounts/{identifier}" + body: "*" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + description: "Updates an Account" + }; + } +} + +message GetAccountRequest { + string identifier = 1; +} + +message GetAllAccountResponse { + repeated AccountData data = 1; +} + +message UpdateAccountRequest { + string identifier = 1; + AccountData data = 2; +} + +message EthereumAccount { + string address = 1; + string key = 2; + string password = 3; +} + +message KeyPair { + string pub = 1; + string pvt = 2; +} + +message AccountData { + EthereumAccount eth_account = 1; + string eth_default_account_name = 2; + string receive_event_notification_endpoint = 3; + string identity_id = 4; + KeyPair signing_key_pair = 5; + KeyPair ethauth_key_pair = 6; +} diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index 80fbea6d8..7933133f0 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -7,104 +7,22 @@ option java_multiple_files = true; option java_outer_classname = "ServiceProto"; option java_package = "com.config"; +import "account/service.proto"; import "google/api/annotations.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/empty.proto"; import "protoc-gen-swagger/options/annotations.proto"; -// ConfigService allows to manage the node and tenant configuration of the node +// ConfigService allows to see the node configuration service ConfigService { rpc GetConfig(google.protobuf.Empty) returns (ConfigData) { option (google.api.http) = { - get: "/config/node" + get: "/config" }; option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { description: "Get Node Config" }; } - rpc GetTenant(GetTenantRequest) returns (TenantData) { - option (google.api.http) = { - get: "/config/tenants/{identifier}" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Get Tenant Config" - }; - } - rpc GetAllTenants(google.protobuf.Empty) returns (GetAllTenantResponse) { - option (google.api.http) = { - get: "/config/tenants" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Get All Tenant Configs" - }; - } - rpc CreateTenant(TenantData) returns (TenantData) { - option (google.api.http) = { - post: "/config/tenants" - body: "*" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Creates tenant config data" - }; - } - rpc GenerateTenant(google.protobuf.Empty) returns (TenantData) { - option (google.api.http) = { - post: "/config/tenants/generate" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Generates tenant config data taking defaults based on the main tenant" - }; - } - rpc UpdateTenant(UpdateTenantRequest) returns (TenantData) { - option (google.api.http) = { - put: "/config/tenants/{identifier}" - body: "*" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Updates tenant config" - }; - } - rpc DeleteTenant(GetTenantRequest) returns (google.protobuf.Empty) { - option (google.api.http) = { - delete: "/config/tenants/{identifier}" - }; - option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { - description: "Deletes tenant config" - }; - } -} - -message GetTenantRequest { - string identifier = 1; -} - -message GetAllTenantResponse { - repeated TenantData data = 1; -} - -message UpdateTenantRequest { - string identifier = 1; - TenantData data = 2; -} - -message EthereumAccount { - string address = 1; - string key = 2; - string password = 3; -} - -message KeyPair { - string pub = 1; - string pvt = 2; -} - -message TenantData { - EthereumAccount eth_account = 1; - string eth_default_account_name = 2; - string receive_event_notification_endpoint = 3; - string identity_id = 4; - KeyPair signing_key_pair = 5; - KeyPair ethauth_key_pair = 6; } message ConfigData { @@ -127,7 +45,7 @@ message ConfigData { string network = 17; repeated string bootstrap_peers = 18; uint32 network_id = 19; - TenantData main_identity = 20; + account.AccountData main_identity = 20; map smart_contract_addresses = 21; bool pprof_enabled = 22; } diff --git a/protobufs/gen/go/account/service.pb.go b/protobufs/gen/go/account/service.pb.go new file mode 100644 index 000000000..8fe29fcd3 --- /dev/null +++ b/protobufs/gen/go/account/service.pb.go @@ -0,0 +1,591 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: account/service.proto + +package accountpb + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import empty "github.com/golang/protobuf/ptypes/empty" +import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" +import _ "google.golang.org/genproto/googleapis/api/annotations" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type GetAccountRequest struct { + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAccountRequest) Reset() { *m = GetAccountRequest{} } +func (m *GetAccountRequest) String() string { return proto.CompactTextString(m) } +func (*GetAccountRequest) ProtoMessage() {} +func (*GetAccountRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{0} +} +func (m *GetAccountRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAccountRequest.Unmarshal(m, b) +} +func (m *GetAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAccountRequest.Marshal(b, m, deterministic) +} +func (dst *GetAccountRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAccountRequest.Merge(dst, src) +} +func (m *GetAccountRequest) XXX_Size() int { + return xxx_messageInfo_GetAccountRequest.Size(m) +} +func (m *GetAccountRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetAccountRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAccountRequest proto.InternalMessageInfo + +func (m *GetAccountRequest) GetIdentifier() string { + if m != nil { + return m.Identifier + } + return "" +} + +type GetAllAccountResponse struct { + Data []*AccountData `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetAllAccountResponse) Reset() { *m = GetAllAccountResponse{} } +func (m *GetAllAccountResponse) String() string { return proto.CompactTextString(m) } +func (*GetAllAccountResponse) ProtoMessage() {} +func (*GetAllAccountResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{1} +} +func (m *GetAllAccountResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetAllAccountResponse.Unmarshal(m, b) +} +func (m *GetAllAccountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetAllAccountResponse.Marshal(b, m, deterministic) +} +func (dst *GetAllAccountResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetAllAccountResponse.Merge(dst, src) +} +func (m *GetAllAccountResponse) XXX_Size() int { + return xxx_messageInfo_GetAllAccountResponse.Size(m) +} +func (m *GetAllAccountResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetAllAccountResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetAllAccountResponse proto.InternalMessageInfo + +func (m *GetAllAccountResponse) GetData() []*AccountData { + if m != nil { + return m.Data + } + return nil +} + +type UpdateAccountRequest struct { + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Data *AccountData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateAccountRequest) Reset() { *m = UpdateAccountRequest{} } +func (m *UpdateAccountRequest) String() string { return proto.CompactTextString(m) } +func (*UpdateAccountRequest) ProtoMessage() {} +func (*UpdateAccountRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{2} +} +func (m *UpdateAccountRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateAccountRequest.Unmarshal(m, b) +} +func (m *UpdateAccountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateAccountRequest.Marshal(b, m, deterministic) +} +func (dst *UpdateAccountRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateAccountRequest.Merge(dst, src) +} +func (m *UpdateAccountRequest) XXX_Size() int { + return xxx_messageInfo_UpdateAccountRequest.Size(m) +} +func (m *UpdateAccountRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateAccountRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateAccountRequest proto.InternalMessageInfo + +func (m *UpdateAccountRequest) GetIdentifier() string { + if m != nil { + return m.Identifier + } + return "" +} + +func (m *UpdateAccountRequest) GetData() *AccountData { + if m != nil { + return m.Data + } + return nil +} + +type EthereumAccount struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } +func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } +func (*EthereumAccount) ProtoMessage() {} +func (*EthereumAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{3} +} +func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) +} +func (m *EthereumAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EthereumAccount.Marshal(b, m, deterministic) +} +func (dst *EthereumAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_EthereumAccount.Merge(dst, src) +} +func (m *EthereumAccount) XXX_Size() int { + return xxx_messageInfo_EthereumAccount.Size(m) +} +func (m *EthereumAccount) XXX_DiscardUnknown() { + xxx_messageInfo_EthereumAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_EthereumAccount proto.InternalMessageInfo + +func (m *EthereumAccount) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *EthereumAccount) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *EthereumAccount) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +type KeyPair struct { + Pub string `protobuf:"bytes,1,opt,name=pub,proto3" json:"pub,omitempty"` + Pvt string `protobuf:"bytes,2,opt,name=pvt,proto3" json:"pvt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KeyPair) Reset() { *m = KeyPair{} } +func (m *KeyPair) String() string { return proto.CompactTextString(m) } +func (*KeyPair) ProtoMessage() {} +func (*KeyPair) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{4} +} +func (m *KeyPair) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KeyPair.Unmarshal(m, b) +} +func (m *KeyPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KeyPair.Marshal(b, m, deterministic) +} +func (dst *KeyPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyPair.Merge(dst, src) +} +func (m *KeyPair) XXX_Size() int { + return xxx_messageInfo_KeyPair.Size(m) +} +func (m *KeyPair) XXX_DiscardUnknown() { + xxx_messageInfo_KeyPair.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyPair proto.InternalMessageInfo + +func (m *KeyPair) GetPub() string { + if m != nil { + return m.Pub + } + return "" +} + +func (m *KeyPair) GetPvt() string { + if m != nil { + return m.Pvt + } + return "" +} + +type AccountData struct { + EthAccount *EthereumAccount `protobuf:"bytes,1,opt,name=eth_account,json=ethAccount,proto3" json:"eth_account,omitempty"` + EthDefaultAccountName string `protobuf:"bytes,2,opt,name=eth_default_account_name,json=ethDefaultAccountName,proto3" json:"eth_default_account_name,omitempty"` + ReceiveEventNotificationEndpoint string `protobuf:"bytes,3,opt,name=receive_event_notification_endpoint,json=receiveEventNotificationEndpoint,proto3" json:"receive_event_notification_endpoint,omitempty"` + IdentityId string `protobuf:"bytes,4,opt,name=identity_id,json=identityId,proto3" json:"identity_id,omitempty"` + SigningKeyPair *KeyPair `protobuf:"bytes,5,opt,name=signing_key_pair,json=signingKeyPair,proto3" json:"signing_key_pair,omitempty"` + EthauthKeyPair *KeyPair `protobuf:"bytes,6,opt,name=ethauth_key_pair,json=ethauthKeyPair,proto3" json:"ethauth_key_pair,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccountData) Reset() { *m = AccountData{} } +func (m *AccountData) String() string { return proto.CompactTextString(m) } +func (*AccountData) ProtoMessage() {} +func (*AccountData) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6af6824e0a923133, []int{5} +} +func (m *AccountData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AccountData.Unmarshal(m, b) +} +func (m *AccountData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AccountData.Marshal(b, m, deterministic) +} +func (dst *AccountData) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountData.Merge(dst, src) +} +func (m *AccountData) XXX_Size() int { + return xxx_messageInfo_AccountData.Size(m) +} +func (m *AccountData) XXX_DiscardUnknown() { + xxx_messageInfo_AccountData.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountData proto.InternalMessageInfo + +func (m *AccountData) GetEthAccount() *EthereumAccount { + if m != nil { + return m.EthAccount + } + return nil +} + +func (m *AccountData) GetEthDefaultAccountName() string { + if m != nil { + return m.EthDefaultAccountName + } + return "" +} + +func (m *AccountData) GetReceiveEventNotificationEndpoint() string { + if m != nil { + return m.ReceiveEventNotificationEndpoint + } + return "" +} + +func (m *AccountData) GetIdentityId() string { + if m != nil { + return m.IdentityId + } + return "" +} + +func (m *AccountData) GetSigningKeyPair() *KeyPair { + if m != nil { + return m.SigningKeyPair + } + return nil +} + +func (m *AccountData) GetEthauthKeyPair() *KeyPair { + if m != nil { + return m.EthauthKeyPair + } + return nil +} + +func init() { + proto.RegisterType((*GetAccountRequest)(nil), "account.GetAccountRequest") + proto.RegisterType((*GetAllAccountResponse)(nil), "account.GetAllAccountResponse") + proto.RegisterType((*UpdateAccountRequest)(nil), "account.UpdateAccountRequest") + proto.RegisterType((*EthereumAccount)(nil), "account.EthereumAccount") + proto.RegisterType((*KeyPair)(nil), "account.KeyPair") + proto.RegisterType((*AccountData)(nil), "account.AccountData") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// AccountServiceClient is the client API for AccountService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AccountServiceClient interface { + GetAccount(ctx context.Context, in *GetAccountRequest, opts ...grpc.CallOption) (*AccountData, error) + GetAllAccounts(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllAccountResponse, error) + CreateAccount(ctx context.Context, in *AccountData, opts ...grpc.CallOption) (*AccountData, error) + GenerateAccount(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*AccountData, error) + UpdateAccount(ctx context.Context, in *UpdateAccountRequest, opts ...grpc.CallOption) (*AccountData, error) +} + +type accountServiceClient struct { + cc *grpc.ClientConn +} + +func NewAccountServiceClient(cc *grpc.ClientConn) AccountServiceClient { + return &accountServiceClient{cc} +} + +func (c *accountServiceClient) GetAccount(ctx context.Context, in *GetAccountRequest, opts ...grpc.CallOption) (*AccountData, error) { + out := new(AccountData) + err := c.cc.Invoke(ctx, "/account.AccountService/GetAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *accountServiceClient) GetAllAccounts(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllAccountResponse, error) { + out := new(GetAllAccountResponse) + err := c.cc.Invoke(ctx, "/account.AccountService/GetAllAccounts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *accountServiceClient) CreateAccount(ctx context.Context, in *AccountData, opts ...grpc.CallOption) (*AccountData, error) { + out := new(AccountData) + err := c.cc.Invoke(ctx, "/account.AccountService/CreateAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *accountServiceClient) GenerateAccount(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*AccountData, error) { + out := new(AccountData) + err := c.cc.Invoke(ctx, "/account.AccountService/GenerateAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *accountServiceClient) UpdateAccount(ctx context.Context, in *UpdateAccountRequest, opts ...grpc.CallOption) (*AccountData, error) { + out := new(AccountData) + err := c.cc.Invoke(ctx, "/account.AccountService/UpdateAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AccountServiceServer is the server API for AccountService service. +type AccountServiceServer interface { + GetAccount(context.Context, *GetAccountRequest) (*AccountData, error) + GetAllAccounts(context.Context, *empty.Empty) (*GetAllAccountResponse, error) + CreateAccount(context.Context, *AccountData) (*AccountData, error) + GenerateAccount(context.Context, *empty.Empty) (*AccountData, error) + UpdateAccount(context.Context, *UpdateAccountRequest) (*AccountData, error) +} + +func RegisterAccountServiceServer(s *grpc.Server, srv AccountServiceServer) { + s.RegisterService(&_AccountService_serviceDesc, srv) +} + +func _AccountService_GetAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccountServiceServer).GetAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/account.AccountService/GetAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccountServiceServer).GetAccount(ctx, req.(*GetAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AccountService_GetAllAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccountServiceServer).GetAllAccounts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/account.AccountService/GetAllAccounts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccountServiceServer).GetAllAccounts(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AccountService_CreateAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AccountData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccountServiceServer).CreateAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/account.AccountService/CreateAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccountServiceServer).CreateAccount(ctx, req.(*AccountData)) + } + return interceptor(ctx, in, info, handler) +} + +func _AccountService_GenerateAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccountServiceServer).GenerateAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/account.AccountService/GenerateAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccountServiceServer).GenerateAccount(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AccountService_UpdateAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AccountServiceServer).UpdateAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/account.AccountService/UpdateAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AccountServiceServer).UpdateAccount(ctx, req.(*UpdateAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AccountService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "account.AccountService", + HandlerType: (*AccountServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAccount", + Handler: _AccountService_GetAccount_Handler, + }, + { + MethodName: "GetAllAccounts", + Handler: _AccountService_GetAllAccounts_Handler, + }, + { + MethodName: "CreateAccount", + Handler: _AccountService_CreateAccount_Handler, + }, + { + MethodName: "GenerateAccount", + Handler: _AccountService_GenerateAccount_Handler, + }, + { + MethodName: "UpdateAccount", + Handler: _AccountService_UpdateAccount_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "account/service.proto", +} + +func init() { proto.RegisterFile("account/service.proto", fileDescriptor_service_6af6824e0a923133) } + +var fileDescriptor_service_6af6824e0a923133 = []byte{ + // 710 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xd1, 0x6e, 0xd3, 0x4a, + 0x10, 0x95, 0xdb, 0xde, 0xf6, 0x66, 0x7c, 0x9b, 0xe6, 0xae, 0xd2, 0xca, 0x72, 0xef, 0x2d, 0x96, + 0x91, 0x50, 0x54, 0x68, 0x22, 0xb5, 0x0f, 0x40, 0x1e, 0x10, 0x29, 0x8d, 0x2a, 0x84, 0xa8, 0xaa, + 0x20, 0x1e, 0x40, 0x42, 0x61, 0x13, 0x4f, 0xed, 0x55, 0x93, 0xb5, 0xf1, 0x6e, 0x52, 0x45, 0x08, + 0x1e, 0xf8, 0x84, 0xf0, 0xce, 0x4f, 0xf1, 0x0b, 0xbc, 0xf0, 0x11, 0x48, 0xc8, 0xeb, 0xb5, 0xe3, + 0x90, 0x44, 0x88, 0xa7, 0x64, 0x77, 0xe6, 0x9c, 0x33, 0x67, 0x76, 0xc6, 0xb0, 0x4b, 0xfb, 0xfd, + 0x70, 0xc4, 0x65, 0x43, 0x60, 0x3c, 0x66, 0x7d, 0xac, 0x47, 0x71, 0x28, 0x43, 0xb2, 0xa5, 0xaf, + 0xed, 0xff, 0xfc, 0x30, 0xf4, 0x07, 0xd8, 0xa0, 0x11, 0x6b, 0x50, 0xce, 0x43, 0x49, 0x25, 0x0b, + 0xb9, 0x48, 0xd3, 0xec, 0x7d, 0x1d, 0x55, 0xa7, 0xde, 0xe8, 0xaa, 0x81, 0xc3, 0x48, 0x4e, 0x74, + 0xf0, 0x9e, 0xfa, 0xe9, 0x1f, 0xf9, 0xc8, 0x8f, 0xc4, 0x0d, 0xf5, 0x7d, 0x8c, 0x1b, 0x61, 0xa4, + 0xe0, 0x8b, 0x54, 0xee, 0x09, 0xfc, 0x7b, 0x8e, 0xb2, 0x95, 0xca, 0x76, 0xf0, 0xdd, 0x08, 0x85, + 0x24, 0x07, 0x00, 0xcc, 0x43, 0x2e, 0xd9, 0x15, 0xc3, 0xd8, 0x32, 0x1c, 0xa3, 0x56, 0xea, 0x14, + 0x6e, 0xdc, 0x16, 0xec, 0x26, 0xa0, 0xc1, 0x20, 0xc7, 0x89, 0x28, 0xe4, 0x02, 0x49, 0x0d, 0x36, + 0x3c, 0x2a, 0xa9, 0x65, 0x38, 0xeb, 0x35, 0xf3, 0xb8, 0x5a, 0xd7, 0x76, 0xea, 0x3a, 0xef, 0x8c, + 0x4a, 0xda, 0x51, 0x19, 0xee, 0x5b, 0xa8, 0xbe, 0x8c, 0x3c, 0x2a, 0xf1, 0xcf, 0xa4, 0x73, 0x85, + 0x35, 0xc7, 0xf8, 0x8d, 0xc2, 0x2b, 0xd8, 0x69, 0xcb, 0x00, 0x63, 0x1c, 0x0d, 0x75, 0x90, 0x58, + 0xb0, 0x45, 0x3d, 0x2f, 0x46, 0x21, 0x34, 0x73, 0x76, 0x24, 0x15, 0x58, 0xbf, 0xc6, 0x89, 0x62, + 0x2d, 0x75, 0x92, 0xbf, 0xc4, 0x86, 0xbf, 0x23, 0x2a, 0xc4, 0x4d, 0x18, 0x7b, 0xd6, 0xba, 0xba, + 0xce, 0xcf, 0xee, 0x11, 0x6c, 0x3d, 0xc3, 0xc9, 0x25, 0x65, 0x71, 0x02, 0x8c, 0x46, 0x3d, 0x4d, + 0x97, 0xfc, 0x55, 0x37, 0x63, 0x99, 0x51, 0x45, 0x63, 0xe9, 0x7e, 0x5f, 0x03, 0xb3, 0x50, 0x1f, + 0x79, 0x08, 0x26, 0xca, 0xa0, 0xab, 0x4b, 0x57, 0x58, 0xf3, 0xd8, 0xca, 0xad, 0xfc, 0x52, 0x75, + 0x07, 0x50, 0x06, 0x99, 0x83, 0xfb, 0x60, 0x25, 0x50, 0x0f, 0xaf, 0xe8, 0x68, 0x20, 0x33, 0x8a, + 0x2e, 0xa7, 0x43, 0xd4, 0x8a, 0xbb, 0x28, 0x83, 0xb3, 0x34, 0xac, 0x41, 0x17, 0x74, 0x88, 0xe4, + 0x39, 0xdc, 0x8e, 0xb1, 0x8f, 0x6c, 0x8c, 0x5d, 0x1c, 0x63, 0x02, 0x09, 0x93, 0x8e, 0xf6, 0xd5, + 0x30, 0x74, 0x91, 0x7b, 0x51, 0xc8, 0xb8, 0xd4, 0x4e, 0x1d, 0x9d, 0xda, 0x4e, 0x32, 0x2f, 0x0a, + 0x89, 0x6d, 0x9d, 0x47, 0x6e, 0x81, 0x99, 0x3e, 0x8a, 0x9c, 0x74, 0x99, 0x67, 0x6d, 0x14, 0xdf, + 0x49, 0x4e, 0x9e, 0x7a, 0xa4, 0x09, 0x15, 0xc1, 0x7c, 0xce, 0xb8, 0xdf, 0xbd, 0xc6, 0x49, 0x37, + 0xa2, 0x2c, 0xb6, 0xfe, 0x52, 0x46, 0x2b, 0xb9, 0x51, 0xdd, 0xc3, 0x4e, 0x59, 0x67, 0x66, 0x3d, + 0x6d, 0x42, 0x05, 0x65, 0x40, 0x47, 0x32, 0x98, 0x61, 0x37, 0x57, 0x61, 0x75, 0xa6, 0x3e, 0x1f, + 0xff, 0xd8, 0x80, 0xb2, 0xf6, 0xfd, 0x22, 0x5d, 0x2d, 0xc2, 0x01, 0x66, 0x23, 0x4e, 0xec, 0x9c, + 0x62, 0x61, 0xee, 0xed, 0xa5, 0xe3, 0xe4, 0xd6, 0xa7, 0xad, 0x6d, 0xdb, 0x3c, 0x47, 0xe9, 0xe8, + 0xdb, 0x4f, 0x5f, 0xbf, 0x7d, 0x5e, 0xb3, 0xc8, 0x5e, 0x43, 0x67, 0x8b, 0xc6, 0xfb, 0xd9, 0x84, + 0x7e, 0x20, 0x11, 0x94, 0xe7, 0xb6, 0x43, 0x90, 0xbd, 0x7a, 0xba, 0xb0, 0xf5, 0x6c, 0x61, 0xeb, + 0xed, 0x64, 0x61, 0xed, 0x83, 0xb9, 0x5a, 0x16, 0xd6, 0xc9, 0xbd, 0x33, 0x6d, 0x11, 0xbb, 0xa2, + 0x94, 0x07, 0x83, 0x4c, 0x5d, 0x28, 0x79, 0x93, 0x94, 0x72, 0x79, 0x12, 0xc0, 0xf6, 0x93, 0x18, + 0x67, 0xcb, 0x44, 0x96, 0x1a, 0x59, 0x61, 0xef, 0xee, 0xb4, 0x55, 0xb5, 0x49, 0x8a, 0x17, 0x0e, + 0xe5, 0x73, 0x2e, 0xcb, 0xee, 0x4c, 0xa6, 0x69, 0x1c, 0x92, 0x2f, 0x06, 0xec, 0x9c, 0x23, 0xc7, + 0xb8, 0x20, 0xb6, 0xca, 0xdd, 0x72, 0xb9, 0x37, 0xd3, 0xd6, 0x63, 0xfb, 0x51, 0xc6, 0x51, 0x14, + 0x74, 0x24, 0xbd, 0x66, 0xdc, 0x77, 0xf4, 0x70, 0x0b, 0xa7, 0x47, 0x05, 0x7a, 0x4e, 0xc8, 0x1d, + 0x19, 0xa0, 0x33, 0xa4, 0x8c, 0x3b, 0xb4, 0x50, 0x5a, 0xd5, 0x25, 0xb3, 0x07, 0xf0, 0x35, 0x1f, + 0xf9, 0x08, 0xdb, 0x73, 0xdf, 0x15, 0xf2, 0x7f, 0x5e, 0xc5, 0xb2, 0xef, 0xcd, 0x8a, 0x22, 0x1f, + 0xa8, 0x9e, 0xa4, 0x80, 0x85, 0x9e, 0xec, 0xdb, 0x2b, 0x5e, 0xbe, 0x69, 0x1c, 0x9e, 0xd6, 0xc0, + 0xec, 0x87, 0xc3, 0x8c, 0xf4, 0xf4, 0x1f, 0x3d, 0x84, 0x97, 0x49, 0x6b, 0x2e, 0x8d, 0xd7, 0x25, + 0x1d, 0x88, 0x7a, 0xbd, 0x4d, 0xd5, 0xae, 0x93, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xaa, + 0x95, 0x34, 0x0b, 0x06, 0x00, 0x00, +} diff --git a/protobufs/gen/go/account/service.pb.gw.go b/protobufs/gen/go/account/service.pb.gw.go new file mode 100644 index 000000000..878c505a6 --- /dev/null +++ b/protobufs/gen/go/account/service.pb.gw.go @@ -0,0 +1,329 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: account/service.proto + +/* +Package accountpb is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package accountpb + +import ( + "io" + "net/http" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray + +func request_AccountService_GetAccount_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAccountRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["identifier"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") + } + + protoReq.Identifier, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) + } + + msg, err := client.GetAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AccountService_GetAllAccounts_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GetAllAccounts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AccountService_CreateAccount_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AccountData + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AccountService_GenerateAccount_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GenerateAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AccountService_UpdateAccount_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateAccountRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["identifier"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") + } + + protoReq.Identifier, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) + } + + msg, err := client.UpdateAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +// RegisterAccountServiceHandlerFromEndpoint is same as RegisterAccountServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterAccountServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterAccountServiceHandler(ctx, mux, conn) +} + +// RegisterAccountServiceHandler registers the http handlers for service AccountService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterAccountServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterAccountServiceHandlerClient(ctx, mux, NewAccountServiceClient(conn)) +} + +// RegisterAccountServiceHandlerClient registers the http handlers for service AccountService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AccountServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AccountServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "AccountServiceClient" to call the correct interceptors. +func RegisterAccountServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AccountServiceClient) error { + + mux.Handle("GET", pattern_AccountService_GetAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AccountService_GetAccount_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AccountService_GetAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AccountService_GetAllAccounts_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AccountService_GetAllAccounts_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AccountService_GetAllAccounts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AccountService_CreateAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AccountService_CreateAccount_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AccountService_CreateAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AccountService_GenerateAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AccountService_GenerateAccount_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AccountService_GenerateAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_AccountService_UpdateAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AccountService_UpdateAccount_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AccountService_UpdateAccount_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_AccountService_GetAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"accounts", "identifier"}, "")) + + pattern_AccountService_GetAllAccounts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"accounts"}, "")) + + pattern_AccountService_CreateAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"accounts"}, "")) + + pattern_AccountService_GenerateAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"accounts", "generate"}, "")) + + pattern_AccountService_UpdateAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"accounts", "identifier"}, "")) +) + +var ( + forward_AccountService_GetAccount_0 = runtime.ForwardResponseMessage + + forward_AccountService_GetAllAccounts_0 = runtime.ForwardResponseMessage + + forward_AccountService_CreateAccount_0 = runtime.ForwardResponseMessage + + forward_AccountService_GenerateAccount_0 = runtime.ForwardResponseMessage + + forward_AccountService_UpdateAccount_0 = runtime.ForwardResponseMessage +) diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 753e8fe66..886971dff 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -6,6 +6,7 @@ package configpb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" +import account "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" import duration "github.com/golang/protobuf/ptypes/duration" import empty "github.com/golang/protobuf/ptypes/empty" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" @@ -27,339 +28,39 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package -type GetTenantRequest struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetTenantRequest) Reset() { *m = GetTenantRequest{} } -func (m *GetTenantRequest) String() string { return proto.CompactTextString(m) } -func (*GetTenantRequest) ProtoMessage() {} -func (*GetTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{0} -} -func (m *GetTenantRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetTenantRequest.Unmarshal(m, b) -} -func (m *GetTenantRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetTenantRequest.Marshal(b, m, deterministic) -} -func (dst *GetTenantRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetTenantRequest.Merge(dst, src) -} -func (m *GetTenantRequest) XXX_Size() int { - return xxx_messageInfo_GetTenantRequest.Size(m) -} -func (m *GetTenantRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetTenantRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetTenantRequest proto.InternalMessageInfo - -func (m *GetTenantRequest) GetIdentifier() string { - if m != nil { - return m.Identifier - } - return "" -} - -type GetAllTenantResponse struct { - Data []*TenantData `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetAllTenantResponse) Reset() { *m = GetAllTenantResponse{} } -func (m *GetAllTenantResponse) String() string { return proto.CompactTextString(m) } -func (*GetAllTenantResponse) ProtoMessage() {} -func (*GetAllTenantResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{1} -} -func (m *GetAllTenantResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetAllTenantResponse.Unmarshal(m, b) -} -func (m *GetAllTenantResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetAllTenantResponse.Marshal(b, m, deterministic) -} -func (dst *GetAllTenantResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetAllTenantResponse.Merge(dst, src) -} -func (m *GetAllTenantResponse) XXX_Size() int { - return xxx_messageInfo_GetAllTenantResponse.Size(m) -} -func (m *GetAllTenantResponse) XXX_DiscardUnknown() { - xxx_messageInfo_GetAllTenantResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_GetAllTenantResponse proto.InternalMessageInfo - -func (m *GetAllTenantResponse) GetData() []*TenantData { - if m != nil { - return m.Data - } - return nil -} - -type UpdateTenantRequest struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Data *TenantData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UpdateTenantRequest) Reset() { *m = UpdateTenantRequest{} } -func (m *UpdateTenantRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateTenantRequest) ProtoMessage() {} -func (*UpdateTenantRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{2} -} -func (m *UpdateTenantRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateTenantRequest.Unmarshal(m, b) -} -func (m *UpdateTenantRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateTenantRequest.Marshal(b, m, deterministic) -} -func (dst *UpdateTenantRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateTenantRequest.Merge(dst, src) -} -func (m *UpdateTenantRequest) XXX_Size() int { - return xxx_messageInfo_UpdateTenantRequest.Size(m) -} -func (m *UpdateTenantRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateTenantRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateTenantRequest proto.InternalMessageInfo - -func (m *UpdateTenantRequest) GetIdentifier() string { - if m != nil { - return m.Identifier - } - return "" -} - -func (m *UpdateTenantRequest) GetData() *TenantData { - if m != nil { - return m.Data - } - return nil -} - -type EthereumAccount struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` - Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } -func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } -func (*EthereumAccount) ProtoMessage() {} -func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{3} -} -func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) -} -func (m *EthereumAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumAccount.Marshal(b, m, deterministic) -} -func (dst *EthereumAccount) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumAccount.Merge(dst, src) -} -func (m *EthereumAccount) XXX_Size() int { - return xxx_messageInfo_EthereumAccount.Size(m) -} -func (m *EthereumAccount) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumAccount.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumAccount proto.InternalMessageInfo - -func (m *EthereumAccount) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -func (m *EthereumAccount) GetKey() string { - if m != nil { - return m.Key - } - return "" -} - -func (m *EthereumAccount) GetPassword() string { - if m != nil { - return m.Password - } - return "" -} - -type KeyPair struct { - Pub string `protobuf:"bytes,1,opt,name=pub,proto3" json:"pub,omitempty"` - Pvt string `protobuf:"bytes,2,opt,name=pvt,proto3" json:"pvt,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *KeyPair) Reset() { *m = KeyPair{} } -func (m *KeyPair) String() string { return proto.CompactTextString(m) } -func (*KeyPair) ProtoMessage() {} -func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{4} -} -func (m *KeyPair) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_KeyPair.Unmarshal(m, b) -} -func (m *KeyPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_KeyPair.Marshal(b, m, deterministic) -} -func (dst *KeyPair) XXX_Merge(src proto.Message) { - xxx_messageInfo_KeyPair.Merge(dst, src) -} -func (m *KeyPair) XXX_Size() int { - return xxx_messageInfo_KeyPair.Size(m) -} -func (m *KeyPair) XXX_DiscardUnknown() { - xxx_messageInfo_KeyPair.DiscardUnknown(m) -} - -var xxx_messageInfo_KeyPair proto.InternalMessageInfo - -func (m *KeyPair) GetPub() string { - if m != nil { - return m.Pub - } - return "" -} - -func (m *KeyPair) GetPvt() string { - if m != nil { - return m.Pvt - } - return "" -} - -type TenantData struct { - EthAccount *EthereumAccount `protobuf:"bytes,1,opt,name=eth_account,json=ethAccount,proto3" json:"eth_account,omitempty"` - EthDefaultAccountName string `protobuf:"bytes,2,opt,name=eth_default_account_name,json=ethDefaultAccountName,proto3" json:"eth_default_account_name,omitempty"` - ReceiveEventNotificationEndpoint string `protobuf:"bytes,3,opt,name=receive_event_notification_endpoint,json=receiveEventNotificationEndpoint,proto3" json:"receive_event_notification_endpoint,omitempty"` - IdentityId string `protobuf:"bytes,4,opt,name=identity_id,json=identityId,proto3" json:"identity_id,omitempty"` - SigningKeyPair *KeyPair `protobuf:"bytes,5,opt,name=signing_key_pair,json=signingKeyPair,proto3" json:"signing_key_pair,omitempty"` - EthauthKeyPair *KeyPair `protobuf:"bytes,6,opt,name=ethauth_key_pair,json=ethauthKeyPair,proto3" json:"ethauth_key_pair,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TenantData) Reset() { *m = TenantData{} } -func (m *TenantData) String() string { return proto.CompactTextString(m) } -func (*TenantData) ProtoMessage() {} -func (*TenantData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{5} -} -func (m *TenantData) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TenantData.Unmarshal(m, b) -} -func (m *TenantData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TenantData.Marshal(b, m, deterministic) -} -func (dst *TenantData) XXX_Merge(src proto.Message) { - xxx_messageInfo_TenantData.Merge(dst, src) -} -func (m *TenantData) XXX_Size() int { - return xxx_messageInfo_TenantData.Size(m) -} -func (m *TenantData) XXX_DiscardUnknown() { - xxx_messageInfo_TenantData.DiscardUnknown(m) -} - -var xxx_messageInfo_TenantData proto.InternalMessageInfo - -func (m *TenantData) GetEthAccount() *EthereumAccount { - if m != nil { - return m.EthAccount - } - return nil -} - -func (m *TenantData) GetEthDefaultAccountName() string { - if m != nil { - return m.EthDefaultAccountName - } - return "" -} - -func (m *TenantData) GetReceiveEventNotificationEndpoint() string { - if m != nil { - return m.ReceiveEventNotificationEndpoint - } - return "" -} - -func (m *TenantData) GetIdentityId() string { - if m != nil { - return m.IdentityId - } - return "" -} - -func (m *TenantData) GetSigningKeyPair() *KeyPair { - if m != nil { - return m.SigningKeyPair - } - return nil -} - -func (m *TenantData) GetEthauthKeyPair() *KeyPair { - if m != nil { - return m.EthauthKeyPair - } - return nil -} - type ConfigData struct { - StoragePath string `protobuf:"bytes,1,opt,name=storage_path,json=storagePath,proto3" json:"storage_path,omitempty"` - P2PPort int32 `protobuf:"varint,2,opt,name=p2p_port,json=p2pPort,proto3" json:"p2p_port,omitempty"` - P2PExternalIp string `protobuf:"bytes,3,opt,name=p2p_external_ip,json=p2pExternalIp,proto3" json:"p2p_external_ip,omitempty"` - P2PConnectionTimeout *duration.Duration `protobuf:"bytes,4,opt,name=p2p_connection_timeout,json=p2pConnectionTimeout,proto3" json:"p2p_connection_timeout,omitempty"` - ServerPort int32 `protobuf:"varint,5,opt,name=server_port,json=serverPort,proto3" json:"server_port,omitempty"` - ServerAddress string `protobuf:"bytes,6,opt,name=server_address,json=serverAddress,proto3" json:"server_address,omitempty"` - NumWorkers int32 `protobuf:"varint,7,opt,name=num_workers,json=numWorkers,proto3" json:"num_workers,omitempty"` - WorkerWaitTimeMs int32 `protobuf:"varint,8,opt,name=worker_wait_time_ms,json=workerWaitTimeMs,proto3" json:"worker_wait_time_ms,omitempty"` - EthNodeUrl string `protobuf:"bytes,9,opt,name=eth_node_url,json=ethNodeUrl,proto3" json:"eth_node_url,omitempty"` - EthContextReadWaitTimeout *duration.Duration `protobuf:"bytes,10,opt,name=eth_context_read_wait_timeout,json=ethContextReadWaitTimeout,proto3" json:"eth_context_read_wait_timeout,omitempty"` - EthContextWaitTimeout *duration.Duration `protobuf:"bytes,11,opt,name=eth_context_wait_timeout,json=ethContextWaitTimeout,proto3" json:"eth_context_wait_timeout,omitempty"` - EthIntervalRetry *duration.Duration `protobuf:"bytes,12,opt,name=eth_interval_retry,json=ethIntervalRetry,proto3" json:"eth_interval_retry,omitempty"` - EthMaxRetries uint32 `protobuf:"varint,13,opt,name=eth_max_retries,json=ethMaxRetries,proto3" json:"eth_max_retries,omitempty"` - EthGasPrice uint64 `protobuf:"varint,14,opt,name=eth_gas_price,json=ethGasPrice,proto3" json:"eth_gas_price,omitempty"` - EthGasLimit uint64 `protobuf:"varint,15,opt,name=eth_gas_limit,json=ethGasLimit,proto3" json:"eth_gas_limit,omitempty"` - TxPoolEnabled bool `protobuf:"varint,16,opt,name=tx_pool_enabled,json=txPoolEnabled,proto3" json:"tx_pool_enabled,omitempty"` - Network string `protobuf:"bytes,17,opt,name=network,proto3" json:"network,omitempty"` - BootstrapPeers []string `protobuf:"bytes,18,rep,name=bootstrap_peers,json=bootstrapPeers,proto3" json:"bootstrap_peers,omitempty"` - NetworkId uint32 `protobuf:"varint,19,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` - MainIdentity *TenantData `protobuf:"bytes,20,opt,name=main_identity,json=mainIdentity,proto3" json:"main_identity,omitempty"` - SmartContractAddresses map[string]string `protobuf:"bytes,21,rep,name=smart_contract_addresses,json=smartContractAddresses,proto3" json:"smart_contract_addresses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - PprofEnabled bool `protobuf:"varint,22,opt,name=pprof_enabled,json=pprofEnabled,proto3" json:"pprof_enabled,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + StoragePath string `protobuf:"bytes,1,opt,name=storage_path,json=storagePath,proto3" json:"storage_path,omitempty"` + P2PPort int32 `protobuf:"varint,2,opt,name=p2p_port,json=p2pPort,proto3" json:"p2p_port,omitempty"` + P2PExternalIp string `protobuf:"bytes,3,opt,name=p2p_external_ip,json=p2pExternalIp,proto3" json:"p2p_external_ip,omitempty"` + P2PConnectionTimeout *duration.Duration `protobuf:"bytes,4,opt,name=p2p_connection_timeout,json=p2pConnectionTimeout,proto3" json:"p2p_connection_timeout,omitempty"` + ServerPort int32 `protobuf:"varint,5,opt,name=server_port,json=serverPort,proto3" json:"server_port,omitempty"` + ServerAddress string `protobuf:"bytes,6,opt,name=server_address,json=serverAddress,proto3" json:"server_address,omitempty"` + NumWorkers int32 `protobuf:"varint,7,opt,name=num_workers,json=numWorkers,proto3" json:"num_workers,omitempty"` + WorkerWaitTimeMs int32 `protobuf:"varint,8,opt,name=worker_wait_time_ms,json=workerWaitTimeMs,proto3" json:"worker_wait_time_ms,omitempty"` + EthNodeUrl string `protobuf:"bytes,9,opt,name=eth_node_url,json=ethNodeUrl,proto3" json:"eth_node_url,omitempty"` + EthContextReadWaitTimeout *duration.Duration `protobuf:"bytes,10,opt,name=eth_context_read_wait_timeout,json=ethContextReadWaitTimeout,proto3" json:"eth_context_read_wait_timeout,omitempty"` + EthContextWaitTimeout *duration.Duration `protobuf:"bytes,11,opt,name=eth_context_wait_timeout,json=ethContextWaitTimeout,proto3" json:"eth_context_wait_timeout,omitempty"` + EthIntervalRetry *duration.Duration `protobuf:"bytes,12,opt,name=eth_interval_retry,json=ethIntervalRetry,proto3" json:"eth_interval_retry,omitempty"` + EthMaxRetries uint32 `protobuf:"varint,13,opt,name=eth_max_retries,json=ethMaxRetries,proto3" json:"eth_max_retries,omitempty"` + EthGasPrice uint64 `protobuf:"varint,14,opt,name=eth_gas_price,json=ethGasPrice,proto3" json:"eth_gas_price,omitempty"` + EthGasLimit uint64 `protobuf:"varint,15,opt,name=eth_gas_limit,json=ethGasLimit,proto3" json:"eth_gas_limit,omitempty"` + TxPoolEnabled bool `protobuf:"varint,16,opt,name=tx_pool_enabled,json=txPoolEnabled,proto3" json:"tx_pool_enabled,omitempty"` + Network string `protobuf:"bytes,17,opt,name=network,proto3" json:"network,omitempty"` + BootstrapPeers []string `protobuf:"bytes,18,rep,name=bootstrap_peers,json=bootstrapPeers,proto3" json:"bootstrap_peers,omitempty"` + NetworkId uint32 `protobuf:"varint,19,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` + MainIdentity *account.AccountData `protobuf:"bytes,20,opt,name=main_identity,json=mainIdentity,proto3" json:"main_identity,omitempty"` + SmartContractAddresses map[string]string `protobuf:"bytes,21,rep,name=smart_contract_addresses,json=smartContractAddresses,proto3" json:"smart_contract_addresses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + PprofEnabled bool `protobuf:"varint,22,opt,name=pprof_enabled,json=pprofEnabled,proto3" json:"pprof_enabled,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_21a2bc638067bc54, []int{6} + return fileDescriptor_service_347685df747205e5, []int{0} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -512,7 +213,7 @@ func (m *ConfigData) GetNetworkId() uint32 { return 0 } -func (m *ConfigData) GetMainIdentity() *TenantData { +func (m *ConfigData) GetMainIdentity() *account.AccountData { if m != nil { return m.MainIdentity } @@ -534,12 +235,6 @@ func (m *ConfigData) GetPprofEnabled() bool { } func init() { - proto.RegisterType((*GetTenantRequest)(nil), "config.GetTenantRequest") - proto.RegisterType((*GetAllTenantResponse)(nil), "config.GetAllTenantResponse") - proto.RegisterType((*UpdateTenantRequest)(nil), "config.UpdateTenantRequest") - proto.RegisterType((*EthereumAccount)(nil), "config.EthereumAccount") - proto.RegisterType((*KeyPair)(nil), "config.KeyPair") - proto.RegisterType((*TenantData)(nil), "config.TenantData") proto.RegisterType((*ConfigData)(nil), "config.ConfigData") proto.RegisterMapType((map[string]string)(nil), "config.ConfigData.SmartContractAddressesEntry") } @@ -557,12 +252,6 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type ConfigServiceClient interface { GetConfig(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ConfigData, error) - GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*TenantData, error) - GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) - CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) - GenerateTenant(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*TenantData, error) - UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) - DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) } type configServiceClient struct { @@ -582,69 +271,9 @@ func (c *configServiceClient) GetConfig(ctx context.Context, in *empty.Empty, op return out, nil } -func (c *configServiceClient) GetTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*TenantData, error) { - out := new(TenantData) - err := c.cc.Invoke(ctx, "/config.ConfigService/GetTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *configServiceClient) GetAllTenants(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*GetAllTenantResponse, error) { - out := new(GetAllTenantResponse) - err := c.cc.Invoke(ctx, "/config.ConfigService/GetAllTenants", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *configServiceClient) CreateTenant(ctx context.Context, in *TenantData, opts ...grpc.CallOption) (*TenantData, error) { - out := new(TenantData) - err := c.cc.Invoke(ctx, "/config.ConfigService/CreateTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *configServiceClient) GenerateTenant(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*TenantData, error) { - out := new(TenantData) - err := c.cc.Invoke(ctx, "/config.ConfigService/GenerateTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *configServiceClient) UpdateTenant(ctx context.Context, in *UpdateTenantRequest, opts ...grpc.CallOption) (*TenantData, error) { - out := new(TenantData) - err := c.cc.Invoke(ctx, "/config.ConfigService/UpdateTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *configServiceClient) DeleteTenant(ctx context.Context, in *GetTenantRequest, opts ...grpc.CallOption) (*empty.Empty, error) { - out := new(empty.Empty) - err := c.cc.Invoke(ctx, "/config.ConfigService/DeleteTenant", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // ConfigServiceServer is the server API for ConfigService service. type ConfigServiceServer interface { GetConfig(context.Context, *empty.Empty) (*ConfigData, error) - GetTenant(context.Context, *GetTenantRequest) (*TenantData, error) - GetAllTenants(context.Context, *empty.Empty) (*GetAllTenantResponse, error) - CreateTenant(context.Context, *TenantData) (*TenantData, error) - GenerateTenant(context.Context, *empty.Empty) (*TenantData, error) - UpdateTenant(context.Context, *UpdateTenantRequest) (*TenantData, error) - DeleteTenant(context.Context, *GetTenantRequest) (*empty.Empty, error) } func RegisterConfigServiceServer(s *grpc.Server, srv ConfigServiceServer) { @@ -669,114 +298,6 @@ func _ConfigService_GetConfig_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -func _ConfigService_GetTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetTenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).GetTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/GetTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).GetTenant(ctx, req.(*GetTenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ConfigService_GetAllTenants_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).GetAllTenants(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/GetAllTenants", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).GetAllTenants(ctx, req.(*empty.Empty)) - } - return interceptor(ctx, in, info, handler) -} - -func _ConfigService_CreateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TenantData) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).CreateTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/CreateTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).CreateTenant(ctx, req.(*TenantData)) - } - return interceptor(ctx, in, info, handler) -} - -func _ConfigService_GenerateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).GenerateTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/GenerateTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).GenerateTenant(ctx, req.(*empty.Empty)) - } - return interceptor(ctx, in, info, handler) -} - -func _ConfigService_UpdateTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UpdateTenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).UpdateTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/UpdateTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).UpdateTenant(ctx, req.(*UpdateTenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ConfigService_DeleteTenant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetTenantRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ConfigServiceServer).DeleteTenant(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/config.ConfigService/DeleteTenant", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ConfigServiceServer).DeleteTenant(ctx, req.(*GetTenantRequest)) - } - return interceptor(ctx, in, info, handler) -} - var _ConfigService_serviceDesc = grpc.ServiceDesc{ ServiceName: "config.ConfigService", HandlerType: (*ConfigServiceServer)(nil), @@ -785,120 +306,64 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetConfig", Handler: _ConfigService_GetConfig_Handler, }, - { - MethodName: "GetTenant", - Handler: _ConfigService_GetTenant_Handler, - }, - { - MethodName: "GetAllTenants", - Handler: _ConfigService_GetAllTenants_Handler, - }, - { - MethodName: "CreateTenant", - Handler: _ConfigService_CreateTenant_Handler, - }, - { - MethodName: "GenerateTenant", - Handler: _ConfigService_GenerateTenant_Handler, - }, - { - MethodName: "UpdateTenant", - Handler: _ConfigService_UpdateTenant_Handler, - }, - { - MethodName: "DeleteTenant", - Handler: _ConfigService_DeleteTenant_Handler, - }, }, Streams: []grpc.StreamDesc{}, Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_21a2bc638067bc54) } - -var fileDescriptor_service_21a2bc638067bc54 = []byte{ - // 1317 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xdb, 0x6e, 0x1b, 0x37, - 0x13, 0xc6, 0xda, 0xf1, 0x89, 0x92, 0x7c, 0xa0, 0x0f, 0xd9, 0x6c, 0x1c, 0x67, 0xa3, 0xe0, 0xcf, - 0x6f, 0x04, 0xbf, 0x65, 0x40, 0xff, 0x45, 0x0e, 0x17, 0x01, 0x14, 0x5b, 0x10, 0x8c, 0x36, 0xa9, - 0xb0, 0x49, 0x10, 0xb4, 0x45, 0xb1, 0xa0, 0xb5, 0x63, 0x69, 0xeb, 0x15, 0xc9, 0x90, 0x5c, 0xdb, - 0x42, 0x51, 0xa0, 0x08, 0x7a, 0xd5, 0x4b, 0xf7, 0x25, 0xfa, 0x3e, 0x7d, 0x85, 0xf6, 0x3d, 0x0a, - 0x1e, 0x56, 0x52, 0x64, 0xd9, 0x46, 0xaf, 0xa4, 0xfd, 0x66, 0xe6, 0x9b, 0x8f, 0xc3, 0x19, 0x92, - 0x68, 0xa3, 0xc3, 0xe8, 0x49, 0xda, 0xdd, 0x97, 0x20, 0xce, 0xd2, 0x0e, 0xd4, 0xb8, 0x60, 0x8a, - 0xe1, 0x79, 0x8b, 0x06, 0xdb, 0x5d, 0xc6, 0xba, 0x19, 0xec, 0x13, 0x9e, 0xee, 0x13, 0x4a, 0x99, - 0x22, 0x2a, 0x65, 0x54, 0x5a, 0xaf, 0x60, 0xc7, 0x59, 0xcd, 0xd7, 0x71, 0x7e, 0xb2, 0x9f, 0xe4, - 0xc2, 0x38, 0x38, 0xfb, 0xfd, 0x49, 0x3b, 0xf4, 0xb9, 0x1a, 0x38, 0xe3, 0xff, 0xcc, 0x4f, 0x67, - 0xaf, 0x0b, 0x74, 0x4f, 0x9e, 0x93, 0x6e, 0x17, 0xc4, 0x3e, 0xe3, 0x86, 0xfe, 0x6a, 0xaa, 0x6a, - 0x1d, 0xad, 0xb6, 0x40, 0xbd, 0x07, 0x4a, 0xa8, 0x8a, 0xe0, 0x53, 0x0e, 0x52, 0xe1, 0x1d, 0x84, - 0xd2, 0x04, 0xa8, 0x4a, 0x4f, 0x52, 0x10, 0xbe, 0x17, 0x7a, 0xbb, 0x4b, 0xd1, 0x18, 0x52, 0x7d, - 0x85, 0x36, 0x5a, 0xa0, 0x1a, 0x59, 0x56, 0x84, 0x49, 0xce, 0xa8, 0x04, 0xfc, 0x04, 0xdd, 0x49, - 0x88, 0x22, 0xbe, 0x17, 0xce, 0xee, 0x96, 0xea, 0xb8, 0x66, 0xd7, 0x5a, 0xb3, 0x5e, 0x87, 0x44, - 0x91, 0xc8, 0xd8, 0xab, 0x3f, 0xa0, 0xf5, 0x0f, 0x3c, 0x21, 0x0a, 0xfe, 0x55, 0xda, 0x21, 0xfd, - 0x4c, 0xe8, 0xdd, 0x48, 0xff, 0x2d, 0x5a, 0x69, 0xaa, 0x1e, 0x08, 0xc8, 0xfb, 0x8d, 0x4e, 0x87, - 0xe5, 0x54, 0x61, 0x1f, 0x2d, 0x90, 0x24, 0x11, 0x20, 0xa5, 0xe3, 0x2d, 0x3e, 0xf1, 0x2a, 0x9a, - 0x3d, 0x85, 0x81, 0xe1, 0x5c, 0x8a, 0xf4, 0x5f, 0x1c, 0xa0, 0x45, 0x4e, 0xa4, 0x3c, 0x67, 0x22, - 0xf1, 0x67, 0x0d, 0x3c, 0xfc, 0xae, 0xee, 0xa1, 0x85, 0xaf, 0x60, 0xd0, 0x26, 0xa9, 0xd0, 0x81, - 0x3c, 0x3f, 0x76, 0x74, 0xfa, 0xaf, 0x41, 0xce, 0x54, 0x41, 0xc5, 0xcf, 0x54, 0xf5, 0xef, 0x19, - 0x84, 0x46, 0xf2, 0xf0, 0x73, 0x54, 0x02, 0xd5, 0x8b, 0x89, 0x15, 0x65, 0x42, 0x4b, 0xf5, 0xbb, - 0xc5, 0x3a, 0x26, 0x34, 0x47, 0x08, 0x54, 0xaf, 0xd0, 0xff, 0x0c, 0xf9, 0x3a, 0x32, 0x81, 0x13, - 0x92, 0x67, 0xaa, 0x60, 0x88, 0x29, 0xe9, 0x83, 0xcb, 0xb7, 0x09, 0xaa, 0x77, 0x68, 0xcd, 0x2e, - 0xe8, 0x2d, 0xe9, 0x03, 0x7e, 0x83, 0x1e, 0x0b, 0xe8, 0x40, 0x7a, 0x06, 0x31, 0x9c, 0x81, 0x0e, - 0x61, 0xba, 0x9a, 0x1d, 0xd3, 0x03, 0x31, 0xd0, 0x84, 0xb3, 0x94, 0x2a, 0xb7, 0xce, 0xd0, 0xb9, - 0x36, 0xb5, 0xe7, 0xdb, 0x31, 0xc7, 0xa6, 0xf3, 0xc3, 0x0f, 0x51, 0xc9, 0x6e, 0x88, 0x1a, 0xc4, - 0x69, 0xe2, 0xdf, 0x19, 0xdf, 0x23, 0x35, 0x38, 0x4a, 0xf0, 0x0b, 0xb4, 0x2a, 0xd3, 0x2e, 0x4d, - 0x69, 0x37, 0x3e, 0x85, 0x41, 0xcc, 0x49, 0x2a, 0xfc, 0x39, 0xb3, 0xce, 0x95, 0x62, 0x9d, 0xae, - 0x80, 0xd1, 0xb2, 0x73, 0x2c, 0x0a, 0xfa, 0x02, 0xad, 0x82, 0xea, 0x91, 0x5c, 0xf5, 0x46, 0xa1, - 0xf3, 0xd7, 0x84, 0x3a, 0x47, 0xf7, 0x5d, 0xfd, 0x75, 0x09, 0xa1, 0x03, 0xe3, 0x62, 0xea, 0xfc, - 0x08, 0x95, 0xa5, 0x62, 0x82, 0x74, 0x21, 0xe6, 0x44, 0xf5, 0xdc, 0x1e, 0x95, 0x1c, 0xd6, 0x26, - 0xaa, 0x87, 0xef, 0xa1, 0x45, 0x5e, 0xe7, 0x31, 0x67, 0xc2, 0x6e, 0xd8, 0x5c, 0xb4, 0xc0, 0xeb, - 0xbc, 0xcd, 0x84, 0xc2, 0x4f, 0xd0, 0x8a, 0x36, 0xc1, 0x85, 0x02, 0x41, 0x49, 0x16, 0xa7, 0xdc, - 0x95, 0xa7, 0xc2, 0xeb, 0xbc, 0xe9, 0xd0, 0x23, 0x8e, 0xbf, 0x41, 0x5b, 0xda, 0xaf, 0xc3, 0x28, - 0x85, 0x8e, 0x29, 0xa7, 0x4a, 0xfb, 0xc0, 0x72, 0x65, 0xca, 0x52, 0xaa, 0xdf, 0xab, 0xd9, 0x29, - 0xad, 0x15, 0x53, 0x5a, 0x3b, 0x74, 0x53, 0x1c, 0x6d, 0xf0, 0x3a, 0x3f, 0x18, 0xc6, 0xbd, 0xb7, - 0x61, 0xba, 0xb8, 0xfa, 0xb0, 0x00, 0x61, 0x65, 0xcd, 0x19, 0x59, 0xc8, 0x42, 0x46, 0xd9, 0x7f, - 0xd0, 0xb2, 0x73, 0x28, 0x9a, 0x79, 0xde, 0x0a, 0xb3, 0x68, 0xc3, 0xb5, 0xf4, 0x43, 0x54, 0xa2, - 0x79, 0x3f, 0x3e, 0x67, 0xe2, 0x14, 0x84, 0xf4, 0x17, 0x2c, 0x0f, 0xcd, 0xfb, 0x1f, 0x2d, 0x82, - 0xf7, 0xd0, 0xba, 0x35, 0xc6, 0xe7, 0x24, 0x55, 0x46, 0x76, 0xdc, 0x97, 0xfe, 0xa2, 0x71, 0x5c, - 0xb5, 0xa6, 0x8f, 0x24, 0x55, 0x5a, 0xd8, 0x1b, 0x89, 0x43, 0x54, 0xd6, 0xcd, 0x47, 0x59, 0x02, - 0x71, 0x2e, 0x32, 0x7f, 0xc9, 0xee, 0x3a, 0xa8, 0xde, 0x5b, 0x96, 0xc0, 0x07, 0x91, 0xe1, 0xef, - 0xd1, 0x03, 0xed, 0xd1, 0x61, 0x54, 0xc1, 0x85, 0x8a, 0x05, 0x90, 0x64, 0x44, 0xad, 0x2b, 0x82, - 0x6e, 0xab, 0xc8, 0x3d, 0x50, 0xbd, 0x03, 0x1b, 0x1e, 0x01, 0x49, 0x8a, 0xec, 0xba, 0x2c, 0x91, - 0xed, 0xfd, 0x82, 0xfc, 0x0b, 0xde, 0xd2, 0x6d, 0xbc, 0x9b, 0x23, 0xde, 0x71, 0xce, 0x16, 0xc2, - 0x9a, 0x33, 0xa5, 0x0a, 0xc4, 0x19, 0xc9, 0x62, 0x01, 0x4a, 0x0c, 0xfc, 0xf2, 0x6d, 0x6c, 0xba, - 0x41, 0x8f, 0x5c, 0x4c, 0xa4, 0x43, 0x74, 0xb3, 0x68, 0xa2, 0x3e, 0xb9, 0x30, 0x1c, 0x29, 0x48, - 0xbf, 0x12, 0x7a, 0xbb, 0x95, 0xa8, 0x02, 0xaa, 0xf7, 0x86, 0x5c, 0x44, 0x16, 0xc4, 0x55, 0xa4, - 0x81, 0xb8, 0x4b, 0x64, 0xcc, 0x45, 0xda, 0x01, 0x7f, 0x39, 0xf4, 0x76, 0xef, 0x44, 0xfa, 0x3c, - 0x68, 0x11, 0xd9, 0xd6, 0xd0, 0xb8, 0x4f, 0x96, 0xf6, 0x53, 0xe5, 0xaf, 0x8c, 0xfb, 0x7c, 0xad, - 0x21, 0x9d, 0x4f, 0x5d, 0xc4, 0x9c, 0xb1, 0x2c, 0x06, 0x4a, 0x8e, 0x33, 0x48, 0xfc, 0xd5, 0xd0, - 0xdb, 0x5d, 0x8c, 0x2a, 0xea, 0xa2, 0xcd, 0x58, 0xd6, 0xb4, 0xa0, 0x3e, 0xf0, 0x28, 0x28, 0xbd, - 0x95, 0xfe, 0x9a, 0x3d, 0xf0, 0xdc, 0x27, 0xfe, 0x2f, 0x5a, 0x39, 0x66, 0x4c, 0x49, 0x25, 0x08, - 0x8f, 0x39, 0xe8, 0x0e, 0xc1, 0xe1, 0xec, 0xee, 0x52, 0xb4, 0x3c, 0x84, 0xdb, 0x1a, 0xc5, 0x0f, - 0x10, 0x72, 0x31, 0x7a, 0xd4, 0xd7, 0xcd, 0xaa, 0x96, 0x1c, 0x72, 0x94, 0xe0, 0x67, 0xa8, 0xd2, - 0x27, 0x29, 0x8d, 0x8b, 0xe1, 0xf7, 0x37, 0xae, 0x3d, 0x96, 0xcb, 0xda, 0xf1, 0xc8, 0xf9, 0xe1, - 0x1e, 0xf2, 0x65, 0x9f, 0x08, 0x65, 0x76, 0x54, 0x90, 0x8e, 0x2a, 0xba, 0x19, 0xa4, 0xbf, 0x69, - 0x6e, 0x8e, 0x5a, 0xc1, 0x31, 0x9a, 0xe9, 0xda, 0x3b, 0x1d, 0x72, 0xe0, 0x22, 0x1a, 0x45, 0x40, - 0x93, 0x2a, 0x31, 0x88, 0xb6, 0xe4, 0x54, 0x23, 0x7e, 0x8c, 0x2a, 0x9c, 0x0b, 0x76, 0x32, 0x2c, - 0xd5, 0x96, 0x29, 0x55, 0xd9, 0x80, 0xae, 0x52, 0xc1, 0x11, 0xba, 0x7f, 0x03, 0x77, 0x71, 0x3f, - 0x78, 0xa3, 0xfb, 0x61, 0x03, 0xcd, 0x9d, 0x91, 0x2c, 0x2f, 0x0e, 0x5e, 0xfb, 0xf1, 0x72, 0xe6, - 0xb9, 0x57, 0xff, 0x6d, 0x01, 0x55, 0xac, 0xe4, 0x77, 0xf6, 0xd2, 0xc7, 0x04, 0x2d, 0xb5, 0x40, - 0x59, 0x0c, 0x6f, 0x5d, 0x69, 0xac, 0xa6, 0xbe, 0xb6, 0x03, 0x7c, 0x75, 0xb9, 0xd5, 0xdd, 0xcb, - 0xc6, 0x5a, 0xb0, 0xd2, 0x02, 0x15, 0xea, 0x19, 0x0b, 0xad, 0xe5, 0xf3, 0x9f, 0x7f, 0xfd, 0x3e, - 0xb3, 0x8c, 0xcb, 0xfb, 0xee, 0x69, 0xa1, 0x27, 0x12, 0xe7, 0x26, 0x85, 0xad, 0x36, 0xf6, 0x0b, - 0xaa, 0xc9, 0x3b, 0x3d, 0x98, 0xb2, 0x2f, 0xd5, 0x97, 0x97, 0x8d, 0xf5, 0x60, 0x4d, 0x27, 0xb1, - 0xe0, 0x78, 0x9a, 0x1d, 0xbc, 0x5d, 0xa4, 0x51, 0xc6, 0x28, 0xf7, 0x7f, 0x1a, 0xdd, 0xc5, 0x3f, - 0xe3, 0x01, 0xaa, 0x8c, 0xbf, 0x01, 0xe4, 0xb5, 0xab, 0xdb, 0x1e, 0x93, 0x74, 0xe5, 0xc9, 0x50, - 0xad, 0x5f, 0x36, 0xfc, 0x60, 0x4b, 0x4b, 0x68, 0x64, 0xd9, 0x97, 0x32, 0xa4, 0xd1, 0xb1, 0x86, - 0x57, 0x26, 0x74, 0xe0, 0x4f, 0xa8, 0x7c, 0x20, 0x60, 0xf8, 0x7c, 0xc0, 0x53, 0x96, 0x36, 0x75, - 0xb9, 0x2f, 0x2e, 0x1b, 0xdb, 0x41, 0x60, 0x43, 0x65, 0x68, 0xd9, 0x42, 0xeb, 0x16, 0xea, 0x87, - 0x83, 0xc9, 0xb7, 0x51, 0x9d, 0xcc, 0xf7, 0xd2, 0x7b, 0x8a, 0xff, 0xf0, 0xd0, 0x72, 0x0b, 0x28, - 0x88, 0x51, 0xd6, 0x5b, 0x77, 0x73, 0x2c, 0xf3, 0x8f, 0x97, 0x8d, 0x56, 0xd0, 0x2c, 0x08, 0xa6, - 0xe5, 0x0e, 0x15, 0x39, 0x4d, 0x69, 0x37, 0x74, 0x37, 0xbc, 0x0c, 0x8f, 0x89, 0x84, 0x24, 0x64, - 0x34, 0x54, 0x3d, 0x08, 0xf5, 0xfc, 0xb8, 0x20, 0x23, 0x32, 0xa8, 0xfa, 0x93, 0x9b, 0xd3, 0x75, - 0xe4, 0xf8, 0xb3, 0x87, 0xca, 0xe3, 0xaf, 0x2b, 0x7c, 0xbf, 0x10, 0x34, 0xe5, 0xcd, 0x35, 0x55, - 0x6d, 0xe3, 0xb2, 0x71, 0x37, 0xd8, 0xb4, 0xde, 0x13, 0x5a, 0x4d, 0xf6, 0x47, 0xc1, 0x8d, 0xad, - 0xa1, 0xeb, 0xf5, 0x8b, 0x87, 0xca, 0x87, 0x90, 0xc1, 0x50, 0xc4, 0xf5, 0x8d, 0x79, 0x4d, 0x1d, - 0xab, 0xaf, 0x8c, 0x0a, 0x4b, 0x32, 0x4d, 0xc5, 0xce, 0xd3, 0x1b, 0x55, 0xbc, 0x7e, 0x82, 0x50, - 0x87, 0xf5, 0x5d, 0xda, 0xd7, 0x65, 0x37, 0x91, 0x6d, 0x9d, 0xa4, 0xed, 0x7d, 0xb7, 0x68, 0x71, - 0x7e, 0x7c, 0x3c, 0x6f, 0xf2, 0xfe, 0xff, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x40, 0x4e, - 0x42, 0xb0, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_347685df747205e5) } + +var fileDescriptor_service_347685df747205e5 = []byte{ + // 801 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xdd, 0x6e, 0x23, 0x35, + 0x14, 0xd6, 0xb4, 0xdb, 0x9f, 0x38, 0x49, 0xdb, 0xf5, 0xa6, 0x95, 0x9b, 0x65, 0x61, 0xe8, 0x8a, + 0x25, 0x17, 0x74, 0x22, 0x85, 0x1b, 0xe0, 0xae, 0xdb, 0xad, 0xaa, 0x48, 0x2c, 0x44, 0xb3, 0xa0, + 0x95, 0x00, 0xc9, 0x72, 0x66, 0x4e, 0x33, 0xa3, 0x9d, 0xb1, 0x2d, 0xcf, 0x49, 0x9b, 0xdc, 0x72, + 0xc1, 0x03, 0xc0, 0xa3, 0xf1, 0x0a, 0x3c, 0x08, 0xf2, 0x4f, 0xda, 0x94, 0xa2, 0xed, 0xd5, 0x8c, + 0xbf, 0xef, 0x7c, 0xdf, 0x39, 0x3e, 0xb6, 0x0f, 0xe9, 0x65, 0x4a, 0x5e, 0x95, 0xb3, 0x61, 0x03, + 0xe6, 0xba, 0xcc, 0x20, 0xd1, 0x46, 0xa1, 0xa2, 0xdb, 0x1e, 0xed, 0x1f, 0x8a, 0x2c, 0x53, 0x73, + 0x89, 0xf7, 0xe9, 0xfe, 0x27, 0x33, 0xa5, 0x66, 0x15, 0x0c, 0x85, 0x2e, 0x87, 0x42, 0x4a, 0x85, + 0x02, 0x4b, 0x25, 0x9b, 0xc0, 0x7e, 0x1a, 0x58, 0xb7, 0x9a, 0xce, 0xaf, 0x86, 0xf9, 0xdc, 0xb8, + 0x80, 0xc0, 0x3f, 0xff, 0x2f, 0x0f, 0xb5, 0xc6, 0x65, 0x20, 0xbf, 0x72, 0x9f, 0xec, 0x74, 0x06, + 0xf2, 0xb4, 0xb9, 0x11, 0xb3, 0x19, 0x98, 0xa1, 0xd2, 0xce, 0xfe, 0x61, 0xaa, 0x93, 0x3f, 0x5a, + 0x84, 0x9c, 0xbb, 0x52, 0xdf, 0x08, 0x14, 0xf4, 0x73, 0xd2, 0x69, 0x50, 0x19, 0x31, 0x03, 0xae, + 0x05, 0x16, 0x2c, 0x8a, 0xa3, 0x41, 0x2b, 0x6d, 0x07, 0x6c, 0x22, 0xb0, 0xa0, 0xc7, 0x64, 0x57, + 0x8f, 0x34, 0xd7, 0xca, 0x20, 0xdb, 0x88, 0xa3, 0xc1, 0x56, 0xba, 0xa3, 0x47, 0x7a, 0xa2, 0x0c, + 0xd2, 0x57, 0x64, 0xdf, 0x52, 0xb0, 0x40, 0x30, 0x52, 0x54, 0xbc, 0xd4, 0x6c, 0xd3, 0x19, 0x74, + 0xf5, 0x48, 0x5f, 0x04, 0x74, 0xac, 0xe9, 0x8f, 0xe4, 0xc8, 0xc6, 0x65, 0x4a, 0x4a, 0xc8, 0x6c, + 0x35, 0x1c, 0xcb, 0x1a, 0xd4, 0x1c, 0xd9, 0x93, 0x38, 0x1a, 0xb4, 0x47, 0xc7, 0x89, 0xdf, 0x60, + 0xb2, 0xda, 0x60, 0xf2, 0x26, 0x34, 0x20, 0xed, 0xe9, 0x91, 0x3e, 0xbf, 0xd5, 0xfd, 0xe4, 0x65, + 0xf4, 0x33, 0xd2, 0xb6, 0xfd, 0x05, 0xe3, 0xcb, 0xda, 0x72, 0x65, 0x11, 0x0f, 0xb9, 0xca, 0xbe, + 0x20, 0x7b, 0x21, 0x40, 0xe4, 0xb9, 0x81, 0xa6, 0x61, 0xdb, 0xbe, 0x30, 0x8f, 0x9e, 0x79, 0xd0, + 0xfa, 0xc8, 0x79, 0xcd, 0x6f, 0x94, 0xf9, 0x00, 0xa6, 0x61, 0x3b, 0xde, 0x47, 0xce, 0xeb, 0xf7, + 0x1e, 0xa1, 0xa7, 0xe4, 0x99, 0x27, 0xf9, 0x8d, 0x28, 0xd1, 0x95, 0xcd, 0xeb, 0x86, 0xed, 0xba, + 0xc0, 0x03, 0x4f, 0xbd, 0x17, 0x25, 0xda, 0xc2, 0xde, 0x36, 0x34, 0x26, 0x1d, 0xc0, 0x82, 0x4b, + 0x95, 0x03, 0x9f, 0x9b, 0x8a, 0xb5, 0x5c, 0x52, 0x02, 0x58, 0xfc, 0xa0, 0x72, 0xf8, 0xd9, 0x54, + 0xf4, 0x57, 0xf2, 0xc2, 0x46, 0x64, 0x4a, 0x22, 0x2c, 0x90, 0x1b, 0x10, 0xf9, 0x9d, 0xb5, 0xed, + 0x08, 0x79, 0xac, 0x23, 0xc7, 0x80, 0xc5, 0xb9, 0x97, 0xa7, 0x20, 0xf2, 0x55, 0x76, 0xdb, 0x96, + 0x94, 0xb0, 0x75, 0xf3, 0x7b, 0xbe, 0xed, 0xc7, 0x7c, 0x0f, 0xef, 0x7c, 0xd7, 0x3d, 0x2f, 0x09, + 0xb5, 0x9e, 0xa5, 0x44, 0x30, 0xd7, 0xa2, 0xe2, 0x06, 0xd0, 0x2c, 0x59, 0xe7, 0x31, 0xb7, 0x03, + 0xc0, 0x62, 0x1c, 0x34, 0xa9, 0x95, 0xd8, 0xcb, 0x62, 0x8d, 0x6a, 0xb1, 0x70, 0x1e, 0x25, 0x34, + 0xac, 0x1b, 0x47, 0x83, 0x6e, 0xda, 0x05, 0x2c, 0xde, 0x8a, 0x45, 0xea, 0x41, 0x7a, 0x42, 0x2c, + 0xc0, 0x67, 0xa2, 0xe1, 0xda, 0x94, 0x19, 0xb0, 0xbd, 0x38, 0x1a, 0x3c, 0x49, 0xdb, 0x80, 0xc5, + 0xa5, 0x68, 0x26, 0x16, 0x5a, 0x8f, 0xa9, 0xca, 0xba, 0x44, 0xb6, 0xbf, 0x1e, 0xf3, 0xbd, 0x85, + 0x6c, 0x3e, 0x5c, 0x70, 0xad, 0x54, 0xc5, 0x41, 0x8a, 0x69, 0x05, 0x39, 0x3b, 0x88, 0xa3, 0xc1, + 0x6e, 0xda, 0xc5, 0xc5, 0x44, 0xa9, 0xea, 0xc2, 0x83, 0x94, 0x91, 0x1d, 0x09, 0x68, 0x8f, 0x92, + 0x3d, 0x75, 0xc7, 0xb5, 0x5a, 0xd2, 0x2f, 0xc9, 0xfe, 0x54, 0x29, 0x6c, 0xd0, 0x08, 0xcd, 0x35, + 0xd8, 0x1b, 0x42, 0xe3, 0xcd, 0x41, 0x2b, 0xdd, 0xbb, 0x85, 0x27, 0x16, 0xa5, 0x2f, 0x08, 0x09, + 0x1a, 0x5e, 0xe6, 0xec, 0x99, 0xdb, 0x55, 0x2b, 0x20, 0xe3, 0x9c, 0x7e, 0x4b, 0xba, 0xb5, 0x28, + 0x25, 0x2f, 0x73, 0x90, 0x58, 0xe2, 0x92, 0xf5, 0x5c, 0xf7, 0x7a, 0x49, 0x98, 0x15, 0xc9, 0x99, + 0xff, 0xda, 0x17, 0x99, 0x76, 0x6c, 0xe8, 0x38, 0x44, 0xd2, 0x82, 0xb0, 0xa6, 0x16, 0x06, 0xdd, + 0x99, 0x1a, 0x91, 0xe1, 0xea, 0x3e, 0x43, 0xc3, 0x0e, 0xe3, 0xcd, 0x41, 0x7b, 0x94, 0x24, 0x7e, + 0xf2, 0x24, 0x77, 0xaf, 0x3a, 0x79, 0x67, 0x25, 0xe7, 0x41, 0x71, 0xb6, 0x12, 0x5c, 0x48, 0x34, + 0xcb, 0xf4, 0xa8, 0xf9, 0x5f, 0x92, 0xbe, 0x24, 0x5d, 0xad, 0x8d, 0xba, 0xba, 0x6d, 0xd6, 0x91, + 0x6b, 0x56, 0xc7, 0x81, 0xa1, 0x57, 0xfd, 0x31, 0x79, 0xfe, 0x11, 0x6f, 0x7a, 0x40, 0x36, 0x3f, + 0xc0, 0x32, 0x0c, 0x11, 0xfb, 0x4b, 0x7b, 0x64, 0xeb, 0x5a, 0x54, 0x73, 0x70, 0x93, 0xa3, 0x95, + 0xfa, 0xc5, 0x77, 0x1b, 0xdf, 0x44, 0xa3, 0x9a, 0x74, 0x7d, 0xc5, 0xef, 0xfc, 0xa0, 0xa4, 0xbf, + 0x91, 0xd6, 0x25, 0xa0, 0xc7, 0xe8, 0xd1, 0x83, 0x9b, 0x75, 0x61, 0x47, 0x5e, 0x9f, 0x3e, 0xdc, + 0xed, 0xc9, 0xcb, 0x3f, 0xcf, 0x9e, 0xf6, 0xf7, 0x2f, 0x01, 0x63, 0xfb, 0xc8, 0x62, 0xcf, 0xfc, + 0xfe, 0xf7, 0x3f, 0x7f, 0x6d, 0xb4, 0xe8, 0xce, 0xd0, 0xc7, 0xbf, 0x7e, 0x45, 0x48, 0xa6, 0xea, + 0xa0, 0x7e, 0xdd, 0x09, 0x49, 0x27, 0xd6, 0x7d, 0x12, 0xfd, 0xb2, 0xeb, 0x71, 0x3d, 0x9d, 0x6e, + 0xbb, 0x84, 0x5f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x43, 0x76, 0xcf, 0xec, 0xe6, 0x05, 0x00, + 0x00, } diff --git a/protobufs/gen/go/config/service.pb.gw.go b/protobufs/gen/go/config/service.pb.gw.go index 3c4ff61af..e39706062 100644 --- a/protobufs/gen/go/config/service.pb.gw.go +++ b/protobufs/gen/go/config/service.pb.gw.go @@ -38,122 +38,6 @@ func request_ConfigService_GetConfig_0(ctx context.Context, marshaler runtime.Ma } -func request_ConfigService_GetTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetTenantRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["identifier"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") - } - - protoReq.Identifier, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) - } - - msg, err := client.GetTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func request_ConfigService_GetAllTenants_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.GetAllTenants(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func request_ConfigService_CreateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq TenantData - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.CreateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func request_ConfigService_GenerateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.GenerateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func request_ConfigService_UpdateTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateTenantRequest - var metadata runtime.ServerMetadata - - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["identifier"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") - } - - protoReq.Identifier, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) - } - - msg, err := client.UpdateTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func request_ConfigService_DeleteTenant_0(ctx context.Context, marshaler runtime.Marshaler, client ConfigServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetTenantRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["identifier"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "identifier") - } - - protoReq.Identifier, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "identifier", err) - } - - msg, err := client.DeleteTenant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - // RegisterConfigServiceHandlerFromEndpoint is same as RegisterConfigServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterConfigServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -221,211 +105,13 @@ func RegisterConfigServiceHandlerClient(ctx context.Context, mux *runtime.ServeM }) - mux.Handle("GET", pattern_ConfigService_GetTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_GetTenant_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_GetTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_ConfigService_GetAllTenants_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_GetAllTenants_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_GetAllTenants_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_ConfigService_CreateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_CreateTenant_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_CreateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_ConfigService_GenerateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_GenerateTenant_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_GenerateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_ConfigService_UpdateTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_UpdateTenant_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_UpdateTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("DELETE", pattern_ConfigService_DeleteTenant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_ConfigService_DeleteTenant_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_ConfigService_DeleteTenant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } var ( - pattern_ConfigService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "node"}, "")) - - pattern_ConfigService_GetTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) - - pattern_ConfigService_GetAllTenants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) - - pattern_ConfigService_CreateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"config", "tenants"}, "")) - - pattern_ConfigService_GenerateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"config", "tenants", "generate"}, "")) - - pattern_ConfigService_UpdateTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) - - pattern_ConfigService_DeleteTenant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"config", "tenants", "identifier"}, "")) + pattern_ConfigService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"config"}, "")) ) var ( forward_ConfigService_GetConfig_0 = runtime.ForwardResponseMessage - - forward_ConfigService_GetTenant_0 = runtime.ForwardResponseMessage - - forward_ConfigService_GetAllTenants_0 = runtime.ForwardResponseMessage - - forward_ConfigService_CreateTenant_0 = runtime.ForwardResponseMessage - - forward_ConfigService_GenerateTenant_0 = runtime.ForwardResponseMessage - - forward_ConfigService_UpdateTenant_0 = runtime.ForwardResponseMessage - - forward_ConfigService_DeleteTenant_0 = runtime.ForwardResponseMessage ) diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 6b44f7814..7832a33e4 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/configTenantData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"configEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"configGetAllTenantResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/configTenantData"}}}},"configKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"configTenantData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/configEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/configKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/configKeyPair"}}},"configUpdateTenantRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/configTenantData"}}},"protobufEmpty":{"type":"object","description":"service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.","title":"A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:"},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/config/node":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/config/tenants":{"get":{"description":"Get All Tenant Configs","operationId":"GetAllTenants","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configGetAllTenantResponse"}}},"tags":["ConfigService"]},"post":{"description":"Creates tenant config data","operationId":"CreateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configTenantData"}}],"tags":["ConfigService"]}},"/config/tenants/generate":{"post":{"description":"Generates tenant config data taking defaults based on the main tenant","operationId":"GenerateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"tags":["ConfigService"]}},"/config/tenants/{identifier}":{"get":{"description":"Get Tenant Config","operationId":"GetTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"delete":{"description":"Deletes tenant config","operationId":"DeleteTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/protobufEmpty"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["ConfigService"]},"put":{"description":"Updates tenant config","operationId":"UpdateTenant","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configTenantData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/configUpdateTenantRequest"}}],"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/account/service.swagger.json b/protobufs/gen/swagger/account/service.swagger.json new file mode 100644 index 000000000..92399f5c6 --- /dev/null +++ b/protobufs/gen/swagger/account/service.swagger.json @@ -0,0 +1,206 @@ +{ + "swagger": "2.0", + "info": { + "title": "account/service.proto", + "version": "version not set" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/accounts": { + "get": { + "description": "Get All Accounts", + "operationId": "GetAllAccounts", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/accountGetAllAccountResponse" + } + } + }, + "tags": [ + "AccountService" + ] + }, + "post": { + "description": "Creates an Account", + "operationId": "CreateAccount", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/accountAccountData" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/accountAccountData" + } + } + ], + "tags": [ + "AccountService" + ] + } + }, + "/accounts/generate": { + "post": { + "description": "Generates an Account taking defaults based on the main account", + "operationId": "GenerateAccount", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/accountAccountData" + } + } + }, + "tags": [ + "AccountService" + ] + } + }, + "/accounts/{identifier}": { + "get": { + "description": "Get Account", + "operationId": "GetAccount", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/accountAccountData" + } + } + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "AccountService" + ] + }, + "put": { + "description": "Updates an Account", + "operationId": "UpdateAccount", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/accountAccountData" + } + } + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/accountUpdateAccountRequest" + } + } + ], + "tags": [ + "AccountService" + ] + } + } + }, + "definitions": { + "accountAccountData": { + "type": "object", + "properties": { + "eth_account": { + "$ref": "#/definitions/accountEthereumAccount" + }, + "eth_default_account_name": { + "type": "string" + }, + "receive_event_notification_endpoint": { + "type": "string" + }, + "identity_id": { + "type": "string" + }, + "signing_key_pair": { + "$ref": "#/definitions/accountKeyPair" + }, + "ethauth_key_pair": { + "$ref": "#/definitions/accountKeyPair" + } + } + }, + "accountEthereumAccount": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "key": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "accountGetAllAccountResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/accountAccountData" + } + } + } + }, + "accountKeyPair": { + "type": "object", + "properties": { + "pub": { + "type": "string" + }, + "pvt": { + "type": "string" + } + } + }, + "accountUpdateAccountRequest": { + "type": "object", + "properties": { + "identifier": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/accountAccountData" + } + } + } + } +} diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 2168b7a6e..ebbdf78a8 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -15,7 +15,7 @@ "application/json" ], "paths": { - "/config/node": { + "/config": { "get": { "description": "Get Node Config", "operationId": "GetConfig", @@ -31,147 +31,57 @@ "ConfigService" ] } - }, - "/config/tenants": { - "get": { - "description": "Get All Tenant Configs", - "operationId": "GetAllTenants", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configGetAllTenantResponse" - } - } + } + }, + "definitions": { + "accountAccountData": { + "type": "object", + "properties": { + "eth_account": { + "$ref": "#/definitions/accountEthereumAccount" }, - "tags": [ - "ConfigService" - ] - }, - "post": { - "description": "Creates tenant config data", - "operationId": "CreateTenant", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configTenantData" - } - } + "eth_default_account_name": { + "type": "string" }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/configTenantData" - } - } - ], - "tags": [ - "ConfigService" - ] - } - }, - "/config/tenants/generate": { - "post": { - "description": "Generates tenant config data taking defaults based on the main tenant", - "operationId": "GenerateTenant", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configTenantData" - } - } + "receive_event_notification_endpoint": { + "type": "string" }, - "tags": [ - "ConfigService" - ] + "identity_id": { + "type": "string" + }, + "signing_key_pair": { + "$ref": "#/definitions/accountKeyPair" + }, + "ethauth_key_pair": { + "$ref": "#/definitions/accountKeyPair" + } } }, - "/config/tenants/{identifier}": { - "get": { - "description": "Get Tenant Config", - "operationId": "GetTenant", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configTenantData" - } - } + "accountEthereumAccount": { + "type": "object", + "properties": { + "address": { + "type": "string" }, - "parameters": [ - { - "name": "identifier", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ConfigService" - ] - }, - "delete": { - "description": "Deletes tenant config", - "operationId": "DeleteTenant", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/protobufEmpty" - } - } + "key": { + "type": "string" }, - "parameters": [ - { - "name": "identifier", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ConfigService" - ] - }, - "put": { - "description": "Updates tenant config", - "operationId": "UpdateTenant", - "responses": { - "200": { - "description": "", - "schema": { - "$ref": "#/definitions/configTenantData" - } - } + "password": { + "type": "string" + } + } + }, + "accountKeyPair": { + "type": "object", + "properties": { + "pub": { + "type": "string" }, - "parameters": [ - { - "name": "identifier", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/configUpdateTenantRequest" - } - } - ], - "tags": [ - "ConfigService" - ] + "pvt": { + "type": "string" + } } - } - }, - "definitions": { + }, "configConfigData": { "type": "object", "properties": { @@ -245,7 +155,7 @@ "format": "int64" }, "main_identity": { - "$ref": "#/definitions/configTenantData" + "$ref": "#/definitions/accountAccountData" }, "smart_contract_addresses": { "type": "object", @@ -258,81 +168,6 @@ "format": "boolean" } } - }, - "configEthereumAccount": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "key": { - "type": "string" - }, - "password": { - "type": "string" - } - } - }, - "configGetAllTenantResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/configTenantData" - } - } - } - }, - "configKeyPair": { - "type": "object", - "properties": { - "pub": { - "type": "string" - }, - "pvt": { - "type": "string" - } - } - }, - "configTenantData": { - "type": "object", - "properties": { - "eth_account": { - "$ref": "#/definitions/configEthereumAccount" - }, - "eth_default_account_name": { - "type": "string" - }, - "receive_event_notification_endpoint": { - "type": "string" - }, - "identity_id": { - "type": "string" - }, - "signing_key_pair": { - "$ref": "#/definitions/configKeyPair" - }, - "ethauth_key_pair": { - "$ref": "#/definitions/configKeyPair" - } - } - }, - "configUpdateTenantRequest": { - "type": "object", - "properties": { - "identifier": { - "type": "string" - }, - "data": { - "$ref": "#/definitions/configTenantData" - } - } - }, - "protobufEmpty": { - "type": "object", - "description": "service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.", - "title": "A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:" } } } diff --git a/protobufs/prototool.yaml b/protobufs/prototool.yaml index a935a9622..5c83bf770 100644 --- a/protobufs/prototool.yaml +++ b/protobufs/prototool.yaml @@ -84,7 +84,7 @@ gen: go_options: # The base import path. This should be the go path of the prototool.yaml file. # This is required if you have any go plugins. - import_path: github.com/centrifuge/go-centrifuge/centrifuge/protobufs + import_path: github.com/centrifuge/go-centrifuge/protobufs # Do not include default modifiers with Mfile=package. # By default, modifiers are included for the Well-Known Types if diff --git a/resources/data.go b/resources/data.go index 707878d59..e4c7ca72c 100644 --- a/resources/data.go +++ b/resources/data.go @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4724, mode: os.FileMode(420), modTime: time.Unix(1547413673, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4724, mode: os.FileMode(420), modTime: time.Unix(1547483298, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1021, mode: os.FileMode(420), modTime: time.Unix(1547419676, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1021, mode: os.FileMode(420), modTime: time.Unix(1547483298, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testworld/httputils.go b/testworld/httputils.go index c7d451705..dde0db94b 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -92,25 +92,25 @@ func getProof(e *httpexpect.Expect, auth string, httpStatus int, documentID stri } func getNodeConfig(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { - resp := addCommonHeaders(e.GET("/config/node"), auth). + resp := addCommonHeaders(e.GET("/config"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } func getAccount(e *httpexpect.Expect, auth string, httpStatus int, identifier string) *httpexpect.Object { - resp := addCommonHeaders(e.GET("/config/tenants/"+identifier), auth). + resp := addCommonHeaders(e.GET("/accounts/"+identifier), auth). Expect().Status(httpStatus) return resp.JSON().Object() } func getAllAccounts(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { - resp := addCommonHeaders(e.GET("/config/tenants"), auth). + resp := addCommonHeaders(e.GET("/accounts"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } func generateAccount(e *httpexpect.Expect, auth string, httpStatus int) *httpexpect.Object { - resp := addCommonHeaders(e.POST("/config/tenants/generate"), auth). + resp := addCommonHeaders(e.POST("/accounts/generate"), auth). Expect().Status(httpStatus) return resp.JSON().Object() } From a32e227094142f6b6a3354cf399081f809b51069 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 16 Jan 2019 18:02:56 +0100 Subject: [PATCH 139/220] added tests for transactionStatusTask (#645) * added testworld tests for proofs * added transaction status task * added protobuf header transaction. * removed nft confirm task * implemented getTransactionStatus * formatting * formatting * removed testoutput * formatting * added swagger * added integration tests for transaction task * formatting * formatting * removed mock eth client from identity package * simplified integration tests * changed nft register transactionTask * fixed broken unit test in api package --- api/server_test.go | 1 + ethereum/geth_client.go | 16 +++++ ethereum/geth_client_integration_test.go | 61 ++++++++++++++++- ethereum/transaction_status_task.go | 23 +++++-- ...ransaction_status_task_integration_test.go | 62 +++++++++++++++++ ethereum/transaction_status_task_test.go | 68 +++++++++++++++++++ identity/ethid/ethereum_identity_test.go | 59 ++++------------ nft/bootstrapper.go | 4 +- testingutils/commons/mock_ethclient.go | 12 ++++ 9 files changed, 250 insertions(+), 56 deletions(-) create mode 100644 ethereum/transaction_status_task_integration_test.go create mode 100644 ethereum/transaction_status_task_test.go diff --git a/api/server_test.go b/api/server_test.go index bba671c66..291cbf232 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -59,6 +59,7 @@ func TestMain(m *testing.M) { &genericdoc.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, + ðereum.Bootstrapper{}, &nft.Bootstrapper{}, &queue.Starter{}, } diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index ffa7dbf70..b4cb507ed 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -71,6 +71,12 @@ type Client interface { // GetGethCallOpts returns the Call options with default GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) + + // TransactionByHash returns a Ethereum transaction + TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) + + // TransactionReceipt return receipt of a transaction + TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) } // gethClient implements Client for Ethereum @@ -159,6 +165,16 @@ func (gc *gethClient) GetNodeURL() *url.URL { return gc.host } +// TransactionByHash returns a Ethereum transaction +func (gc *gethClient) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { + return gc.client.TransactionByHash(ctx, hash) +} + +// TransactionReceipt return receipt of a transaction +func (gc *gethClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + return gc.client.TransactionReceipt(ctx, txHash) +} + // getGethTxOpts retrieves the geth transaction options for the given account name. The account name influences which configuration // is used. func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, error) { diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 8bc7e03f1..d27c22606 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -5,21 +5,76 @@ package ethereum_test import ( "os" "testing" + "time" + + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/mock" + + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/bootstrap" - cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/stretchr/testify/assert" ) var cfg config.Configuration +var ctx = map[string]interface{}{} + +func registerMockedTransactionTask() { + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + txService := ctx[transactions.BootstrappedService].(transactions.Service) + + mockClient := &testingcommons.MockEthClient{} + + // txHash: 0x1 -> successful + mockClient.On("TransactionByHash", mock.Anything, common.HexToHash("0x1")).Return(&types.Transaction{}, false, nil).Once() + mockClient.On("TransactionReceipt", mock.Anything, common.HexToHash("0x1")).Return(&types.Receipt{Status: 1}, nil).Once() + + // txHash: 0x2 -> fail + mockClient.On("TransactionByHash", mock.Anything, common.HexToHash("0x2")).Return(&types.Transaction{}, false, nil).Once() + mockClient.On("TransactionReceipt", mock.Anything, common.HexToHash("0x2")).Return(&types.Receipt{Status: 0}, nil).Once() + + // txHash: 0x3 -> pending + mockClient.On("TransactionByHash", mock.Anything, common.HexToHash("0x3")).Return(&types.Transaction{}, true, nil).Maybe() + + ethTransTask := ethereum.NewTransactionStatusTask(1000*time.Millisecond, txService, mockClient.TransactionByHash, mockClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) + queueSrv.RegisterTaskType(ethereum.TransactionStatusTaskName, ethTransTask) + +} func TestMain(m *testing.M) { - ctx := cc.TestFunctionalEthereumBootstrap() + var bootstappers = []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + transactions.Bootstrapper{}, + ethereum.Bootstrapper{}, + &queue.Bootstrapper{}, + ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + } + + bootstrap.RunTestBootstrappers(bootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + + queueStartBootstrap := &queue.Starter{} + bootstappers = append(bootstappers, queueStartBootstrap) + // register queue task + registerMockedTransactionTask() + //start queue + queueStartBootstrap.TestBootstrap(ctx) + result := m.Run() - cc.TestFunctionalEthereumTearDown() + bootstrap.RunTestTeardown(bootstappers) os.Exit(result) } diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 65de86467..78ec3d526 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/ethereum/go-ethereum/core/types" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -28,8 +30,10 @@ type TransactionStatusTask struct { timeout time.Duration //state ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) + transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) + transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - //task parameter + //txHash is the id of an Ethereum transaction txHash string tenantID identity.CentID } @@ -38,6 +42,8 @@ type TransactionStatusTask struct { func NewTransactionStatusTask( timeout time.Duration, txService transactions.Service, + transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error), + transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error), ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), ) *TransactionStatusTask { @@ -45,6 +51,8 @@ func NewTransactionStatusTask( timeout: timeout, BaseTask: transactions.BaseTask{TxService: txService}, ethContextInitializer: ethContextInitializer, + transactionByHash: transactionByHash, + transactionReceipt: transactionReceipt, } } @@ -59,6 +67,8 @@ func (nftc *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { timeout: nftc.timeout, txHash: nftc.txHash, tenantID: nftc.tenantID, + transactionByHash: nftc.transactionByHash, + transactionReceipt: nftc.transactionReceipt, ethContextInitializer: nftc.ethContextInitializer, BaseTask: transactions.BaseTask{TxService: nftc.TxService}, }, nil @@ -104,8 +114,8 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e return nil } -func getTransactionStatus(ctx context.Context, client Client, txHash string) (bool, error) { - receipt, err := client.GetEthClient().TransactionReceipt(ctx, common.HexToHash(txHash)) +func (nftc *TransactionStatusTask) getTransactionStatus(ctx context.Context, txHash string) (bool, error) { + receipt, err := nftc.transactionReceipt(ctx, common.HexToHash(txHash)) if err != nil { return false, err @@ -123,6 +133,7 @@ func getTransactionStatus(ctx context.Context, client Client, txHash string) (bo func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { ctx, cancelF := nftc.ethContextInitializer(nftc.timeout) defer cancelF() + defer func() { if err != nil { log.Infof("Transaction failed: %v\n", nftc.txHash) @@ -134,22 +145,20 @@ func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { }() isPending := true - client := GetClient() for isPending { - _, isPending, err = client.GetEthClient().TransactionByHash(ctx, common.HexToHash(nftc.txHash)) + _, isPending, err = nftc.transactionByHash(ctx, common.HexToHash(nftc.txHash)) if err != nil { return nil, err } if isPending == false { - successful, err := getTransactionStatus(ctx, GetClient(), nftc.txHash) + successful, err := nftc.getTransactionStatus(ctx, nftc.txHash) if err != nil { return nil, err } if successful { return nil, nil - } } time.Sleep(100 * time.Millisecond) diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go new file mode 100644 index 000000000..cafea6018 --- /dev/null +++ b/ethereum/transaction_status_task_integration_test.go @@ -0,0 +1,62 @@ +// +build integration + +package ethereum_test + +import ( + "testing" + "time" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/stretchr/testify/assert" +) + +func enqueueJob(t *testing.T, txHash string) (transactions.Service, identity.CentID, *transactions.Transaction) { + queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + txService := ctx[transactions.BootstrappedService].(transactions.Service) + + cid := identity.RandomCentID() + tx, err := txService.CreateTransaction(cid, "Mint NFT") + + assert.Nil(t, err, "toCentID shouldn't throw an error") + + _, err = queueSrv.EnqueueJob(ethereum.TransactionStatusTaskName, map[string]interface{}{ + transactions.TxIDParam: tx.ID.String(), + ethereum.TransactionAccountParam: cid.String(), + ethereum.TransactionTxHashParam: txHash, + }) + + time.Sleep(100 * time.Millisecond) + return txService, cid, tx + +} + +func TestTransactionStatusTask_successful(t *testing.T) { + txService, cid, tx := enqueueJob(t, "0x1") + + trans, err := txService.GetTransaction(cid, tx.ID) + assert.Nil(t, err, "a transaction should be returned") + assert.Equal(t, string(transactions.Success), string(trans.Status), "transaction should be successful") + +} + +func TestTransactionStatusTask_failed(t *testing.T) { + txService, cid, tx := enqueueJob(t, "0x2") + + trans, err := txService.GetTransaction(cid, tx.ID) + assert.Nil(t, err, "a centrifuge transaction should be returned") + assert.Equal(t, string(transactions.Failed), string(trans.Status), "transaction should fail") + +} + +func TestTransactionStatusTask_timeout_failed(t *testing.T) { + txService, cid, tx := enqueueJob(t, "0x3") + + trans, err := txService.GetTransaction(cid, tx.ID) + assert.Nil(t, err, "a centrifuge transaction should be returned") + assert.Equal(t, string(transactions.Pending), string(trans.Status), "transaction should fail") + +} diff --git a/ethereum/transaction_status_task_test.go b/ethereum/transaction_status_task_test.go new file mode 100644 index 000000000..6e7b6c1a2 --- /dev/null +++ b/ethereum/transaction_status_task_test.go @@ -0,0 +1,68 @@ +// +build unit + +package ethereum + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/assert" +) + +func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { + task := TransactionStatusTask{} + txHash := "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515" + txID := uuid.Must(uuid.NewV4()).String() + cid := identity.RandomCentID() + + kwargs := map[string]interface{}{ + transactions.TxIDParam: txID, + TransactionAccountParam: cid.String(), + TransactionTxHashParam: txHash, + } + + decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) + assert.Nil(t, err, "json decode should not thrown an error") + err = task.ParseKwargs(decoded) + assert.Nil(t, err, "parsing should be successful") + + assert.Equal(t, cid, task.tenantID, "tenantID should be parsed correctly") + assert.Equal(t, txID, task.TxID.String(), "txID should be parsed correctly") + assert.Equal(t, txHash, task.txHash, "txHash should be parsed correctly") + +} + +func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { + task := TransactionStatusTask{} + tests := []map[string]interface{}{ + { + transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + TransactionAccountParam: identity.RandomCentID().String(), + }, + { + TransactionAccountParam: identity.RandomCentID().String(), + TransactionTxHashParam: "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515", + }, + { + transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + TransactionTxHashParam: "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515", + }, + { + //empty map + + }, + { + "dummy": "dummy", + }, + } + + for i, test := range tests { + decoded, err := utils.SimulateJSONDecodeForGocelery(test) + assert.Nil(t, err, "json decode should not thrown an error") + err = task.ParseKwargs(decoded) + assert.Error(t, err, "test case %v: parsing should fail", i) + } +} diff --git a/identity/ethid/ethereum_identity_test.go b/identity/ethid/ethereum_identity_test.go index f23dc378a..9399ebaa7 100644 --- a/identity/ethid/ethereum_identity_test.go +++ b/identity/ethid/ethereum_identity_test.go @@ -3,11 +3,11 @@ package ethid import ( - "context" "math/big" - "net/url" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/errors" @@ -42,35 +42,6 @@ func (r MockIDRegistry) GetIdentityByCentrifugeId(opts *bind.CallOpts, bigInt *b return id, args.Error(1) } -type MockGethClient struct { - mock.Mock -} - -func (gc MockGethClient) GetEthClient() *ethclient.Client { - args := gc.Called() - return args.Get(0).(*ethclient.Client) -} - -func (gc MockGethClient) GetNodeURL() *url.URL { - args := gc.Called() - return args.Get(0).(*url.URL) -} - -func (gc MockGethClient) GetTxOpts(accountName string) (*bind.TransactOpts, error) { - args := gc.Called(accountName) - return args.Get(0).(*bind.TransactOpts), args.Error(1) -} - -func (gc MockGethClient) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) { - args := gc.Called(contractMethod, opts, params) - return args.Get(0).(*types.Transaction), args.Error(1) -} - -func (gc MockGethClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { - args := gc.Called() - return args.Get(0).(*bind.CallOpts), args.Get(1).(func()) -} - type MockIDContract struct { mock.Mock } @@ -105,7 +76,7 @@ func (mic MockIDContract) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, func TestGetClientP2PURL_happy(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -125,7 +96,7 @@ func TestGetClientP2PURL_happy(t *testing.T) { func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) @@ -145,7 +116,7 @@ func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -167,7 +138,7 @@ func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { func TestGetIdentityKey_fail_lookup(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { @@ -187,7 +158,7 @@ func TestGetIdentityKey_fail_lookup(t *testing.T) { func TestGetIdentityKey_fail_FetchKey(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -217,7 +188,7 @@ func TestGetIdentityKey_fail_FetchKey(t *testing.T) { func TestGetIdentityKey_fail_empty(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -247,7 +218,7 @@ func TestGetIdentityKey_fail_empty(t *testing.T) { func TestGetIdentityKey_Success(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -278,7 +249,7 @@ func TestValidateKey_success(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -308,7 +279,7 @@ func TestValidateKey_fail_getId(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -336,7 +307,7 @@ func TestValidateKey_fail_getId(t *testing.T) { func TestValidateKey_fail_mismatch_key(t *testing.T) { centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -366,7 +337,7 @@ func TestValidateKey_fail_missing_purpose(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -396,7 +367,7 @@ func TestValidateKey_fail_wrong_purpose(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) @@ -426,7 +397,7 @@ func TestValidateKey_fail_revocation(t *testing.T) { pubKey := utils.RandomSlice(32) var key [32]byte copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &MockGethClient{}, &MockIDContract{} + c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) g.On("GetEthClient").Return(ðclient.Client{}) r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 35ea735a1..e4c4ccc25 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -76,8 +76,8 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { }) // queue task - - ethTransTask := ethereum.NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, ethereum.DefaultWaitForTransactionMiningContext) + ethereumClient := ethereum.GetClient() + ethTransTask := ethereum.NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, ethereumClient.TransactionByHash, ethereumClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) return nil diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index 7e3b1fdee..84302c14d 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -5,6 +5,8 @@ package testingcommons import ( "net/url" + "github.com/ethereum/go-ethereum/common" + "context" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -43,3 +45,13 @@ func (m *MockEthClient) SubmitTransactionWithRetries(contractMethod interface{}, args := m.Called(contractMethod, opts, params) return args.Get(0).(*types.Transaction), args.Error(1) } + +func (m *MockEthClient) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) { + args := m.Called(ctx, txHash) + return args.Get(0).(*types.Transaction), args.Get(1).(bool), args.Error(2) +} + +func (m *MockEthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + args := m.Called(ctx, txHash) + return args.Get(0).(*types.Receipt), args.Error(1) +} From a06ad540fab9106bd08f7a09c35764c5ac059688 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 16 Jan 2019 18:46:31 +0100 Subject: [PATCH 140/220] Add Auth Header to Swagger UI (#655) * add account fields to notification * comments + proto-gen * Add custom swagger auth header * comments --- Makefile | 2 +- build/package.json | 2 +- build/scripts/build_swagger.js | 27 +++++++++++++++++++++++++++ build/scripts/run_swagger.sh | 5 +++-- build/swagger_config.js | 2 +- protobufs/gen/swagger.json | 2 +- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b9b02c23f..8eb7be846 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ proto-all: ## runs prototool all $(PROTOTOOL_BIN) all gen-swagger: ## generates the swagger documentation - npm --prefix ./build run build_swagger + npm --prefix ./build run build_swagger generate: ## autogenerate go files for config go generate ./config/configuration.go diff --git a/build/package.json b/build/package.json index cd221df70..bd883e30a 100644 --- a/build/package.json +++ b/build/package.json @@ -1,6 +1,6 @@ { "name": "go-centrifuge", - "version": "0.0.2", + "version": "0.0.3", "description": "Protobuf files & go bindings for go-centrifuge", "main": "index.js", "scripts": { diff --git a/build/scripts/build_swagger.js b/build/scripts/build_swagger.js index 0d867bed1..162a9fc58 100644 --- a/build/scripts/build_swagger.js +++ b/build/scripts/build_swagger.js @@ -6,6 +6,14 @@ const swaggerFilesPath = path.resolve(__dirname, '../../protobufs/gen/swagger'); const swaggerJsonPath = path.resolve(__dirname, '../../protobufs/gen/swagger.json'); const swaggerConfig = require(path.resolve(__dirname, '../swagger_config')); +let authHeader = { + "name": "authorization", + "in": "header", + "description": "Hex encoded centrifuge ID of the account for the intended API action", + "required": true, + "type": "string" +}; + /* # build_swagger.js * * This script recursively searches the swaggerFilesPath for any file ending in .swagger.json @@ -34,6 +42,15 @@ let getSwaggerFiles = function(dir, filelist) { return filelist; }; +// Append auth header function +let addAuthHeader = function(obj) { + if (!obj.hasOwnProperty("parameters")) { + obj.parameters = [] + } + + obj.parameters.push(authHeader); +}; + let files = getSwaggerFiles(swaggerFilesPath); // There is a default swagger definition in swaggerConfig.defaultSwagger which we add first swaggerModules = [swaggerConfig.defaultSwagger,]; @@ -51,6 +68,16 @@ swaggermerge.on('err', function (msg) { }); let merged = swaggermerge.merge(swaggerModules, swaggerConfig.info, swaggerConfig.pathPrefix, swaggerConfig.host, swaggerConfig.schemes); + +let keys = Object.keys(merged.paths); + +keys.forEach(function (item) { + let itemKeys = Object.keys(merged.paths[item]); + itemKeys.forEach(function (valueItem) { + addAuthHeader(merged.paths[item][valueItem]) + }) +}); + let json = JSON.stringify(merged); console.log("Merged swagger.json, writing to:", swaggerJsonPath); fs.writeFileSync(swaggerJsonPath, json); diff --git a/build/scripts/run_swagger.sh b/build/scripts/run_swagger.sh index d8974a7dd..62b780c9c 100755 --- a/build/scripts/run_swagger.sh +++ b/build/scripts/run_swagger.sh @@ -1,8 +1,9 @@ #!/bin/sh -SWAGGER_PATH=$GOPATH/src/github.com/centrifuge/go-centrifuge/centrifuge/invoice + +SWAGGER_PATH=$GOPATH/src/github.com/centrifuge/go-centrifuge/protobufs/gen echo "Launching swagger-ui docker container..." echo "Loading swagger.json from: $SWAGGER_PATH" echo "Go to http://localhost:8085/ to access it once it's done starting." -docker run --rm -p 8085:8080 -e SWAGGER_JSON=/data/invoice.swagger.json -v $SWAGGER_PATH:/data swaggerapi/swagger-ui +docker run --rm -p 8085:8080 -e SWAGGER_JSON=/data/swagger.json -v $SWAGGER_PATH:/data swaggerapi/swagger-ui diff --git a/build/swagger_config.js b/build/swagger_config.js index 3d4747053..aebaf844e 100644 --- a/build/swagger_config.js +++ b/build/swagger_config.js @@ -1,6 +1,6 @@ module.exports = { info: { - version: "0.0.2", + version: "0.0.3", title: "Centrifuge OS Node API", description: "\n", contact: { diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 7832a33e4..55aac60c7 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.2","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file From 73de66626babe54e6a29259494e318efa3f39c33 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 16 Jan 2019 20:19:01 +0100 Subject: [PATCH 141/220] use latest gocelery for retry and delay (#643) Remove the for loop with retryable tasks --- Gopkg.lock | 12 +---- Gopkg.toml | 4 +- documents/anchor_task.go | 16 ++---- ethereum/geth_client_integration_test.go | 2 +- ethereum/transaction_status_task.go | 53 ++++++++----------- ...ransaction_status_task_integration_test.go | 11 ---- nft/ethereum_payment_obligation.go | 2 +- nft/ethereum_payment_obligation_test.go | 2 +- nft/minting_confirmation_task.go | 6 --- queue/server.go | 25 ++++++++- testingutils/utils.go | 6 +++ testworld/document_consensus_test.go | 8 --- testworld/nft_test.go | 4 -- testworld/proof_test.go | 4 -- transactions/base_task.go | 14 +++++ 15 files changed, 75 insertions(+), 94 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 88dfe5839..b7b6a116f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -79,11 +79,11 @@ revision = "f93686ceaf40283c7dc496c62fcc69b1c1a272e3" [[projects]] - digest = "1:c925cd40d25fe72f5916e010b79b5d9f6e0e97ec9b190fa658c6c67b913229ea" + digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" name = "github.com/centrifuge/gocelery" packages = ["."] pruneopts = "UT" - revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" + revision = "fb11151a227ae41660e15f6c10e2e22eb1556531" [[projects]] digest = "1:a145dca8eb072174d0bce9c21771ec19885bdaa04fe2f9026de4664811b1caf7" @@ -1112,14 +1112,6 @@ revision = "8fb642006536c8d3760c99d4fa2389f5e2205631" version = "v1.2.0" -[[projects]] - branch = "master" - digest = "1:0c088044c1c1ee83e723692442df4fec9b3f2e57f7a99773485c97adfbc31695" - name = "github.com/streadway/amqp" - packages = ["."] - pruneopts = "UT" - revision = "70e15c650864f4fc47f5d3c82ea117285480895d" - [[projects]] digest = "1:ac83cf90d08b63ad5f7e020ef480d319ae890c208f8524622a2f3136e2686b02" name = "github.com/stretchr/objx" diff --git a/Gopkg.toml b/Gopkg.toml index 84ba1b9ad..57d7d1346 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -44,7 +44,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/gocelery" - revision = "80f35a18b9a0c632d7843e7e536873b0536f0040" + revision = "fb11151a227ae41660e15f6c10e2e22eb1556531" [[override]] name = "github.com/xsleonard/go-merkle" @@ -226,7 +226,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/stretchr/testify" version = "1.2.2" -[[constraint]] +[[override]] name = "github.com/syndtr/goleveldb" revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd" diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 0bfe52802..d9ec909a0 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" @@ -12,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common/hexutil" @@ -90,12 +91,6 @@ func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { func (d *documentAnchorTask) RunTask() (res interface{}, err error) { log.Infof("starting anchor task: %v\n", d.TxID.String()) defer func() { - if err == nil { - log.Infof("anchor task successful: %v\n", d.TxID.String()) - } else { - log.Infof("anchor task failed: %v\n", err) - } - err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) }() @@ -123,13 +118,8 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { return true, nil } -// taskQueuer can be implemented by any queueing system -type taskQueuer interface { - EnqueueJob(taskTypeName string, params map[string]interface{}) (queue.TaskResult, error) -} - // InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. -func InitDocumentAnchorTask(tq taskQueuer, txService transactions.Service, tenantID identity.CentID, modelID []byte) (uuid.UUID, error) { +func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Service, tenantID identity.CentID, modelID []byte) (uuid.UUID, error) { tx, err := txService.CreateTransaction(tenantID, documentAnchorTaskName) if err != nil { return uuid.Nil, err diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index d27c22606..0ce695429 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -46,7 +46,7 @@ func registerMockedTransactionTask() { // txHash: 0x3 -> pending mockClient.On("TransactionByHash", mock.Anything, common.HexToHash("0x3")).Return(&types.Transaction{}, true, nil).Maybe() - ethTransTask := ethereum.NewTransactionStatusTask(1000*time.Millisecond, txService, mockClient.TransactionByHash, mockClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) + ethTransTask := ethereum.NewTransactionStatusTask(200*time.Millisecond, txService, mockClient.TransactionByHash, mockClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) queueSrv.RegisterTaskType(ethereum.TransactionStatusTaskName, ethTransTask) } diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 78ec3d526..f8f8e26f7 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -22,6 +22,9 @@ const ( // TransactionAccountParam contains the name of the account TransactionAccountParam string = "Account ID" transactionStatusSuccess uint64 = 1 + + // ErrTransactionFailed error when transaction failed + ErrTransactionFailed = errors.Error("Transaction failed") ) // TransactionStatusTask is struct for the task to check an Ethereum transaction @@ -114,56 +117,44 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e return nil } -func (nftc *TransactionStatusTask) getTransactionStatus(ctx context.Context, txHash string) (bool, error) { +func (nftc *TransactionStatusTask) isTransactionSuccessful(ctx context.Context, txHash string) error { receipt, err := nftc.transactionReceipt(ctx, common.HexToHash(txHash)) - if err != nil { - return false, err + return err } - if receipt.Status == transactionStatusSuccess { - return true, nil + if receipt.Status != transactionStatusSuccess { + return ErrTransactionFailed } - return false, errors.New("Transaction failed") - + return nil } // RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { ctx, cancelF := nftc.ethContextInitializer(nftc.timeout) defer cancelF() - defer func() { - if err != nil { - log.Infof("Transaction failed: %v\n", nftc.txHash) - } else { - log.Infof("Transaction successful:%v\n", nftc.txHash) - } - err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) }() - isPending := true - for isPending { - _, isPending, err = nftc.transactionByHash(ctx, common.HexToHash(nftc.txHash)) - if err != nil { - return nil, err - } + _, isPending, err := nftc.transactionByHash(ctx, common.HexToHash(nftc.txHash)) + if err != nil { + return nil, err + } - if isPending == false { - successful, err := nftc.getTransactionStatus(ctx, nftc.txHash) - if err != nil { - return nil, err - } + if isPending { + return nil, gocelery.ErrTaskRetryable + } - if successful { - return nil, nil - } - } - time.Sleep(100 * time.Millisecond) + err = nftc.isTransactionSuccessful(ctx, nftc.txHash) + if err == nil { + return nil, nil } - return nil, nil + if err != ErrTransactionFailed { + return nil, gocelery.ErrTaskRetryable + } + return nil, err } diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go index cafea6018..0c2b6d072 100644 --- a/ethereum/transaction_status_task_integration_test.go +++ b/ethereum/transaction_status_task_integration_test.go @@ -40,7 +40,6 @@ func TestTransactionStatusTask_successful(t *testing.T) { trans, err := txService.GetTransaction(cid, tx.ID) assert.Nil(t, err, "a transaction should be returned") assert.Equal(t, string(transactions.Success), string(trans.Status), "transaction should be successful") - } func TestTransactionStatusTask_failed(t *testing.T) { @@ -49,14 +48,4 @@ func TestTransactionStatusTask_failed(t *testing.T) { trans, err := txService.GetTransaction(cid, tx.ID) assert.Nil(t, err, "a centrifuge transaction should be returned") assert.Equal(t, string(transactions.Failed), string(trans.Status), "transaction should fail") - -} - -func TestTransactionStatusTask_timeout_failed(t *testing.T) { - txService, cid, tx := enqueueJob(t, "0x3") - - trans, err := txService.GetTransaction(cid, tx.ID) - assert.Nil(t, err, "a centrifuge transaction should be returned") - assert.Equal(t, string(transactions.Pending), string(trans.Status), "transaction should fail") - } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index f1da11d15..b3e0ac174 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -158,7 +158,7 @@ func (s *ethereumPaymentObligation) queueTaskTransaction(tenantID identity.CentI if err != nil { return txID, err } - _, err = s.queue.EnqueueJob(ethereum.TransactionStatusTaskName, map[string]interface{}{ + _, err = s.queue.EnqueueJobWithMaxTries(ethereum.TransactionStatusTaskName, map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), ethereum.TransactionAccountParam: tenantID.String(), ethereum.TransactionTxHashParam: txHash, diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index d697c5aa0..93d8ff2ff 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -175,7 +175,7 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) - queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) + queueSrv.On("EnqueueJobWithMaxTries", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv }, &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go index 8f927c5cf..21e868232 100644 --- a/nft/minting_confirmation_task.go +++ b/nft/minting_confirmation_task.go @@ -141,12 +141,6 @@ func (nftc *mintingConfirmationTask) RunTask() (resp interface{}, err error) { } defer func() { - if err != nil { - log.Infof("failed to mint NFT: %v\n", err) - } else { - log.Infof("NFT minted successfully: %v\n", nftc.tokenID) - } - err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) }() diff --git a/queue/server.go b/queue/server.go index 231fac327..9edf7b94d 100644 --- a/queue/server.go +++ b/queue/server.go @@ -92,13 +92,33 @@ func (qs *Server) RegisterTaskType(name string, task interface{}) { } // EnqueueJob enqueues a job on the queue server for the given taskTypeName -func (qs *Server) EnqueueJob(taskTypeName string, params map[string]interface{}) (TaskResult, error) { +func (qs *Server) EnqueueJob(taskName string, params map[string]interface{}) (TaskResult, error) { qs.lock.RLock() defer qs.lock.RUnlock() + + return qs.enqueueJob(taskName, params, gocelery.DefaultSettings()) +} + +func (qs *Server) enqueueJob(name string, params map[string]interface{}, settings *gocelery.TaskSettings) (TaskResult, error) { if qs.queue == nil { return nil, errors.New("queue hasn't been initialised") } - return qs.queue.DelayKwargs(taskTypeName, params) + + return qs.queue.Delay(gocelery.Task{ + Name: name, + Kwargs: params, + Settings: settings, + }) +} + +// EnqueueJobWithMaxTries enqueues a job on the queue server for the given taskTypeName with maximum tries +func (qs *Server) EnqueueJobWithMaxTries(taskName string, params map[string]interface{}) (TaskResult, error) { + qs.lock.RLock() + defer qs.lock.RUnlock() + + return qs.enqueueJob(taskName, params, &gocelery.TaskSettings{ + MaxTries: gocelery.MaxRetries, + }) } // GetDuration parses key parameter to time.Duration type @@ -124,4 +144,5 @@ func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { // TaskQueuer can be implemented by any queueing system type TaskQueuer interface { EnqueueJob(taskTypeName string, params map[string]interface{}) (TaskResult, error) + EnqueueJobWithMaxTries(taskName string, params map[string]interface{}) (TaskResult, error) } diff --git a/testingutils/utils.go b/testingutils/utils.go index ae5d2fd13..de1646d2f 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -35,3 +35,9 @@ func (m *MockQueue) EnqueueJob(taskTypeName string, params map[string]interface{ res, _ := args.Get(0).(queue.TaskResult) return res, args.Error(1) } + +func (m *MockQueue) EnqueueJobWithMaxTries(taskTypeName string, params map[string]interface{}) (queue.TaskResult, error) { + args := m.Called(taskTypeName, params) + res, _ := args.Get(0).(queue.TaskResult) + return res, args.Error(1) +} diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 9b9ea239a..6aa850c64 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -3,10 +3,8 @@ package testworld import ( - "math/rand" "net/http" "testing" - "time" ) func TestHost_AddExternalCollaborator(t *testing.T) { @@ -53,8 +51,6 @@ func TestHost_AddExternalCollaborator(t *testing.T) { } func addExternalCollaborator_withinHost(t *testing.T, documentType string) { - // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(10)) * time.Second) bob := doctorFord.getHostTestSuite(t, "Bob") accounts := doctorFord.getHost("Bob").accounts a := accounts[0] @@ -95,8 +91,6 @@ func addExternalCollaborator_withinHost(t *testing.T, documentType string) { } func addExternalCollaborator_multiHostMultiAccount(t *testing.T, documentType string) { - // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(10)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") accounts := doctorFord.getHost("Bob").accounts @@ -149,8 +143,6 @@ func addExternalCollaborator_multiHostMultiAccount(t *testing.T, documentType st } func addExternalCollaborator(t *testing.T, documentType string) { - // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(10)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") charlie := doctorFord.getHostTestSuite(t, "Charlie") diff --git a/testworld/nft_test.go b/testworld/nft_test.go index fc60722a5..6fb8803ea 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -3,10 +3,8 @@ package testworld import ( - "math/rand" "net/http" "testing" - "time" "github.com/stretchr/testify/assert" ) @@ -24,8 +22,6 @@ func TestPaymentObligationMint_po_successful(t *testing.T) { */ func paymentObligationMint(t *testing.T, documentType string) { - // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(5)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 191f6dbc1..8a3d2a0cf 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -3,10 +3,8 @@ package testworld import ( - "math/rand" "net/http" "testing" - "time" "github.com/gavv/httpexpect" ) @@ -24,8 +22,6 @@ func TestProofWithMultipleFields_po_successful(t *testing.T) { } func proofWithMultipleFields_successful(t *testing.T, documentType string) { - // TODO remove this when we have retry for tasks - time.Sleep(time.Duration(rand.Intn(5)) * time.Second) alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") diff --git a/transactions/base_task.go b/transactions/base_task.go index cdfb71e00..371889e76 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -3,9 +3,13 @@ package transactions import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/gocelery" + logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) +var log = logging.Logger("transaction") + const ( // TxIDParam maps transaction ID in the kwargs. TxIDParam = "transactionID" @@ -36,6 +40,16 @@ func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { // UpdateTransaction add a new log and updates the status of the transaction based on the error. func (b *BaseTask) UpdateTransaction(tenantID identity.CentID, name string, err error) error { + if err == gocelery.ErrTaskRetryable { + return err + } + + if err != nil { + log.Infof("Transaction failed: %v\n", b.TxID.String()) + } else { + log.Infof("Transaction successful:%v\n", b.TxID.String()) + } + tx, erri := b.TxService.GetTransaction(tenantID, b.TxID) if erri != nil { return errors.AppendError(err, erri) From 02b6ba7d2038abceb144654abf7bc39ca90df1c7 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 17 Jan 2019 14:01:07 +0100 Subject: [PATCH 142/220] Add nil safe config (#636) * add nil safe config * add error checks account config * error type * error type --- config/configstore/handler.go | 35 ++++++++++++---- config/configstore/handler_test.go | 60 +++++++++++++++++++++------ config/configstore/model.go | 25 +++++++++-- config/configstore/model_test.go | 66 ++++++++++++++++++++++++++++-- config/configuration.go | 2 +- 5 files changed, 161 insertions(+), 27 deletions(-) diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 18b72e877..85a3b0f1b 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -3,6 +3,8 @@ package configstore import ( "context" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" @@ -11,6 +13,9 @@ import ( logging "github.com/ipfs/go-log" ) +// ErrDerivingAccount used as generic account deriver type +const ErrDerivingAccount = errors.Error("error deriving account") + var apiLog = logging.Logger("account-api") type grpcHandler struct { @@ -27,10 +32,20 @@ func GRPCAccountHandler(svc config.Service) accountpb.AccountServiceServer { return &grpcHandler{service: svc} } +// deriveAllTenantResponse derives all valid accounts, will not return accounts that fail at load time func (h grpcHandler) deriveAllTenantResponse(cfgs []config.TenantConfiguration) (*accountpb.GetAllAccountResponse, error) { response := new(accountpb.GetAllAccountResponse) for _, t := range cfgs { - response.Data = append(response.Data, t.CreateProtobuf()) + tpb, err := t.CreateProtobuf() + if err != nil { + bID, err := t.GetIdentityID() + if err != nil { + apiLog.Errorf("%v", errors.NewTypedError(ErrDerivingAccount, errors.New("error getting ID: %v", err))) + } + apiLog.Errorf("%v", errors.NewTypedError(ErrDerivingAccount, errors.New("account [%s]: %v", hexutil.Encode(bID), err))) + continue + } + response.Data = append(response.Data, tpb) } return response, nil } @@ -52,7 +67,7 @@ func (h grpcHandler) GetAccount(ctx context.Context, req *accountpb.GetAccountRe if err != nil { return nil, err } - return tenantConfig.CreateProtobuf(), nil + return tenantConfig.CreateProtobuf() } func (h grpcHandler) GetAllAccounts(ctx context.Context, req *empty.Empty) (*accountpb.GetAllAccountResponse, error) { @@ -66,12 +81,15 @@ func (h grpcHandler) GetAllAccounts(ctx context.Context, req *empty.Empty) (*acc func (h grpcHandler) CreateAccount(ctx context.Context, data *accountpb.AccountData) (*accountpb.AccountData, error) { apiLog.Infof("Creating account: %v", data) tenantConfig := new(TenantConfig) - tenantConfig.loadFromProtobuf(data) + err := tenantConfig.loadFromProtobuf(data) + if err != nil { + return nil, err + } tc, err := h.service.CreateTenant(tenantConfig) if err != nil { return nil, err } - return tc.CreateProtobuf(), nil + return tc.CreateProtobuf() } func (h grpcHandler) GenerateAccount(ctx context.Context, req *empty.Empty) (*accountpb.AccountData, error) { @@ -80,16 +98,19 @@ func (h grpcHandler) GenerateAccount(ctx context.Context, req *empty.Empty) (*ac if err != nil { return nil, err } - return tc.CreateProtobuf(), nil + return tc.CreateProtobuf() } func (h grpcHandler) UpdateAccount(ctx context.Context, req *accountpb.UpdateAccountRequest) (*accountpb.AccountData, error) { apiLog.Infof("Updating account: %v", req) tenantConfig := new(TenantConfig) - tenantConfig.loadFromProtobuf(req.Data) + err := tenantConfig.loadFromProtobuf(req.Data) + if err != nil { + return nil, err + } tc, err := h.service.UpdateTenant(tenantConfig) if err != nil { return nil, err } - return tc.CreateProtobuf(), nil + return tc.CreateProtobuf() } diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index d7194e3b9..50619e088 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/ethereum/go-ethereum/common/hexutil" @@ -60,7 +62,9 @@ func TestGrpcHandler_GetTenant(t *testing.T) { h := GRPCAccountHandler(svc) tenantCfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateAccount(context.Background(), tenantCfg.CreateProtobuf()) + tcpb, err := tenantCfg.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tcpb) assert.Nil(t, err) tid, err := tenantCfg.GetIdentityID() assert.Nil(t, err) @@ -69,6 +73,24 @@ func TestGrpcHandler_GetTenant(t *testing.T) { assert.NotNil(t, readCfg) } +func TestGrpcHandler_deriveAllTenantResponseFailure(t *testing.T) { + idService := &testingcommons.MockIDService{} + repo, _, err := getRandomStorage() + assert.Nil(t, err) + repo.RegisterTenant(&TenantConfig{}) + svc := DefaultService(repo, idService) + h := GRPCAccountHandler(svc) + tenantCfg1, err := NewTenantConfig("main", cfg) + tenantCfg2, err := NewTenantConfig("main", cfg) + tco := tenantCfg1.(*TenantConfig) + tco.EthereumAccount = nil + tcs := []config.TenantConfiguration{tco, tenantCfg2} + hc := h.(*grpcHandler) + resp, err := hc.deriveAllTenantResponse(tcs) + assert.NoError(t, err) + assert.Equal(t, 1, len(resp.Data)) +} + func TestGrpcHandler_GetAllTenants(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() @@ -80,9 +102,13 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { tenantCfg2, err := NewTenantConfig("main", cfg) tc := tenantCfg2.(*TenantConfig) tc.IdentityID = []byte("0x123456789") - _, err = h.CreateAccount(context.Background(), tenantCfg1.CreateProtobuf()) + tc1pb, err := tenantCfg1.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tc1pb) assert.Nil(t, err) - _, err = h.CreateAccount(context.Background(), tc.CreateProtobuf()) + tcpb, err := tc.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tcpb) assert.Nil(t, err) resp, err := h.GetAllAccounts(context.Background(), nil) @@ -97,13 +123,17 @@ func TestGrpcHandler_CreateTenant(t *testing.T) { repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - nodeCfg, err := NewTenantConfig("main", cfg) + tc, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) + tcpb, err := tc.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tcpb) assert.Nil(t, err) // Already exists - _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) + tcpb, err = tc.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tcpb) assert.NotNil(t, err) } @@ -124,22 +154,28 @@ func TestGrpcHandler_UpdateTenant(t *testing.T) { repo.RegisterTenant(&TenantConfig{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - nodeCfg, err := NewTenantConfig("main", cfg) + tcfg, err := NewTenantConfig("main", cfg) assert.Nil(t, err) - tid, err := nodeCfg.GetIdentityID() + tid, err := tcfg.GetIdentityID() assert.Nil(t, err) - tc := nodeCfg.(*TenantConfig) + tc := tcfg.(*TenantConfig) // Config doesn't exist - _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: nodeCfg.CreateProtobuf()}) + tcpb, err := tcfg.CreateProtobuf() + assert.NoError(t, err) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tcpb}) assert.NotNil(t, err) - _, err = h.CreateAccount(context.Background(), nodeCfg.CreateProtobuf()) + tcpb, err = tcfg.CreateProtobuf() + assert.NoError(t, err) + _, err = h.CreateAccount(context.Background(), tcpb) assert.Nil(t, err) tc.EthereumDefaultAccountName = "other" - _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tc.CreateProtobuf()}) + tccpb, err := tc.CreateProtobuf() + assert.NoError(t, err) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tccpb}) assert.Nil(t, err) readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) diff --git a/config/configstore/model.go b/config/configstore/model.go index fcdfaa173..5fded7597 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -15,6 +15,9 @@ import ( "github.com/golang/protobuf/ptypes/duration" ) +// ErrNilParameter used as nil parameter type +const ErrNilParameter = errors.Error("nil parameter") + // KeyPair represents a key pair config type KeyPair struct { Pub, Priv string @@ -511,7 +514,10 @@ func (tc *TenantConfig) FromJSON(data []byte) error { } // CreateProtobuf creates protobuf for config -func (tc *TenantConfig) CreateProtobuf() *accountpb.AccountData { +func (tc *TenantConfig) CreateProtobuf() (*accountpb.AccountData, error) { + if tc.EthereumAccount == nil { + return nil, errors.New("nil EthereumAccount field") + } return &accountpb.AccountData{ EthAccount: &accountpb.EthereumAccount{ Address: tc.EthereumAccount.Address, @@ -529,10 +535,22 @@ func (tc *TenantConfig) CreateProtobuf() *accountpb.AccountData { Pub: tc.EthAuthKeyPair.Pub, Pvt: tc.EthAuthKeyPair.Priv, }, - } + }, nil } -func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) { +func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) error { + if data == nil { + return errors.NewTypedError(ErrNilParameter, errors.New("nil data")) + } + if data.EthAccount == nil { + return errors.NewTypedError(ErrNilParameter, errors.New("nil EthAccount field")) + } + if data.SigningKeyPair == nil { + return errors.NewTypedError(ErrNilParameter, errors.New("nil SigningKeyPair field")) + } + if data.EthauthKeyPair == nil { + return errors.NewTypedError(ErrNilParameter, errors.New("nil EthauthKeyPair field")) + } tc.EthereumAccount = &config.AccountConfig{ Address: data.EthAccount.Address, Key: data.EthAccount.Key, @@ -549,6 +567,7 @@ func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) { Pub: data.EthauthKeyPair.Pub, Priv: data.EthauthKeyPair.Pvt, } + return nil } // NewTenantConfig creates a new TenantConfig instance with configs diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 21a567aaa..7a3abe1a8 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -6,6 +6,9 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/config" @@ -258,7 +261,8 @@ func TestNewTenantConfig(t *testing.T) { c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() - NewTenantConfig("name", c) + _, err := NewTenantConfig("name", c) + assert.NoError(t, err) c.AssertExpectations(t) } @@ -275,12 +279,64 @@ func TestNodeConfigProtobuf(t *testing.T) { assert.Equal(t, hexutil.Encode(i), ncpb.MainIdentity.IdentityId) ncCopy := new(NodeConfig) - ncCopy.loadFromProtobuf(ncpb) + err = ncCopy.loadFromProtobuf(ncpb) + assert.NoError(t, err) assert.Equal(t, ncpb.StoragePath, ncCopy.StoragePath) assert.Equal(t, int(ncpb.ServerPort), ncCopy.ServerPort) assert.Equal(t, ncpb.MainIdentity.IdentityId, hexutil.Encode(ncCopy.MainIdentity.IdentityID)) } +func TestTenantConfigProtobuf_validationFailures(t *testing.T) { + c := &mockConfig{} + c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil) + c.On("GetEthereumDefaultAccountName").Return("dummyAcc") + c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier") + c.On("GetIdentityID").Return(utils.RandomSlice(6), nil) + c.On("GetSigningKeyPair").Return("pub", "priv") + c.On("GetEthAuthKeyPair").Return("pub", "priv") + c.On("GetEthereumContextWaitTimeout").Return(time.Second) + tc, err := NewTenantConfig("name", c) + assert.Nil(t, err) + c.AssertExpectations(t) + + // Nil EthAccount + tco := tc.(*TenantConfig) + tco.EthereumAccount = nil + tcpb, err := tco.CreateProtobuf() + assert.Error(t, err) + assert.Nil(t, tcpb) + + // Nil payload + tc, err = NewTenantConfig("name", c) + assert.Nil(t, err) + tcpb, err = tc.CreateProtobuf() + assert.NoError(t, err) + tco = tc.(*TenantConfig) + err = tco.loadFromProtobuf(nil) + assert.Error(t, err) + + // Nil EthAccount + ethacc := proto.Clone(tcpb.EthAccount) + tcpb.EthAccount = nil + err = tco.loadFromProtobuf(tcpb) + assert.Error(t, err) + tcpb.EthAccount = ethacc.(*accountpb.EthereumAccount) + + // Nil SigningKeyPair + signKey := proto.Clone(tcpb.SigningKeyPair) + tcpb.SigningKeyPair = nil + err = tco.loadFromProtobuf(tcpb) + assert.Error(t, err) + tcpb.SigningKeyPair = signKey.(*accountpb.KeyPair) + + // Nil EthauthKeyPair + ethAuthKey := proto.Clone(tcpb.EthauthKeyPair) + tcpb.EthauthKeyPair = nil + err = tco.loadFromProtobuf(tcpb) + assert.Error(t, err) + tcpb.EthauthKeyPair = ethAuthKey.(*accountpb.KeyPair) +} + func TestTenantConfigProtobuf(t *testing.T) { c := &mockConfig{} c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() @@ -294,7 +350,8 @@ func TestTenantConfigProtobuf(t *testing.T) { assert.Nil(t, err) c.AssertExpectations(t) - tcpb := tc.CreateProtobuf() + tcpb, err := tc.CreateProtobuf() + assert.NoError(t, err) assert.Equal(t, tc.GetReceiveEventNotificationEndpoint(), tcpb.ReceiveEventNotificationEndpoint) i, err := tc.GetIdentityID() assert.Nil(t, err) @@ -303,7 +360,8 @@ func TestTenantConfigProtobuf(t *testing.T) { assert.Equal(t, priv, tcpb.SigningKeyPair.Pvt) tcCopy := new(TenantConfig) - tcCopy.loadFromProtobuf(tcpb) + err = tcCopy.loadFromProtobuf(tcpb) + assert.NoError(t, err) assert.Equal(t, tcpb.ReceiveEventNotificationEndpoint, tcCopy.ReceiveEventNotificationEndpoint) assert.Equal(t, tcpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) assert.Equal(t, tcpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) diff --git a/config/configuration.go b/config/configuration.go index 2ff3a0436..957e038fc 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -124,7 +124,7 @@ type TenantConfiguration interface { GetEthereumContextWaitTimeout() time.Duration // CreateProtobuf creates protobuf - CreateProtobuf() *accountpb.AccountData + CreateProtobuf() (*accountpb.AccountData, error) } // Service exposes functions over the config objects From 77538376f5c5f21d1d9a5166d6d68c9353ea3d4d Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 17 Jan 2019 14:51:57 +0100 Subject: [PATCH 143/220] Account rename 2: refs in config and configstore packages (#659) * move API /config/tenants => /accounts * move API /config/tenants => /accounts * Review comments * Account rename 2: refs in config and configstore packages * merge * Review comments * More refs --- anchors/ethereum_anchor_repository.go | 4 +- api/server.go | 4 +- api/server_test.go | 13 +- build/configs/default_config.yaml | 6 +- build/configs/testing_config.yaml | 6 +- cmd/centrifuge/manage_identities.go | 2 +- cmd/common.go | 2 +- config/configstore/bootstrapper.go | 10 +- config/configstore/bootstrapper_test.go | 2 +- config/configstore/handler.go | 26 ++-- config/configstore/handler_test.go | 88 +++++++------- config/configstore/mock_service.go | 22 ++-- config/configstore/model.go | 114 +++++++++--------- config/configstore/model_test.go | 85 ++++++------- config/configstore/repository.go | 86 ++++++------- config/configstore/repository_test.go | 74 ++++++------ config/configstore/service.go | 60 ++++----- .../configstore/service_integration_test.go | 6 +- config/configstore/service_test.go | 74 ++++++------ config/configuration.go | 30 ++--- contextutil/context.go | 18 +-- documents/anchor_task.go | 2 +- identity/ethid/ethereum_identity.go | 2 +- nft/ethereum_payment_obligation.go | 2 +- nft/handler_test.go | 6 +- notification/notification.go | 2 +- p2p/client.go | 4 +- p2p/client_integration_test.go | 8 +- p2p/common/protocol_test.go | 2 +- p2p/receiver/handler.go | 2 +- p2p/receiver/handler_integration_test.go | 4 +- p2p/server.go | 2 +- p2p/server_test.go | 2 +- resources/data.go | 8 +- testingutils/config/config.go | 6 +- testingutils/identity/identity.go | 2 +- transactions/handler.go | 2 +- transactions/handler_test.go | 2 +- 38 files changed, 391 insertions(+), 399 deletions(-) diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 958e60b70..709c826d8 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -50,7 +50,7 @@ func (ethRepository *ethereumAnchorRepository) GetDocumentRootOf(anchorID Anchor // PreCommitAnchor will call the transaction PreCommit on the smart contract func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { - tc, err := contextutil.Tenant(ctx) + tc, err := contextutil.Account(ctx) if err != nil { return nil, err } @@ -79,7 +79,7 @@ func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(ctx context.Conte // CommitAnchor will send a commit transaction to Ethereum. func (ethRepository *ethereumAnchorRepository) CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { - tc, err := contextutil.Tenant(ctx) + tc, err := contextutil.Account(ctx) if err != nil { return nil, err } diff --git a/api/server.go b/api/server.go index bfee456d6..571e18b99 100644 --- a/api/server.go +++ b/api/server.go @@ -193,7 +193,7 @@ func grpcInterceptor() grpc.ServerOption { // at this point we are going with one interceptor. Once we have more than one interceptor, // we can write a wrapper interceptor that will call the chain of interceptor // -// Note: each handler can access tenantID from the context: ctx.Value(api.TenantKey) +// Note: each handler can access tenantID from the context: ctx.Value(api.AccountHeaderKey) func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { // if this request is for ping if utils.ContainsString(noAuthPaths[:], info.FullMethod) { @@ -211,7 +211,7 @@ func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, hand return nil, err } - ctx = context.WithValue(ctx, config.TenantKey, auth[0]) + ctx = context.WithValue(ctx, config.AccountHeaderKey, auth[0]) return handler(ctx, req) } diff --git a/api/server_test.go b/api/server_test.go index 291cbf232..b05cb1b50 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,26 +9,23 @@ import ( "sync" "testing" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/identity/ethid" - - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" @@ -125,7 +122,7 @@ func TestCentAPIServer_FailedToGetRegistry(t *testing.T) { func Test_auth(t *testing.T) { handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return ctx.Value(config.TenantKey), nil + return ctx.Value(config.AccountHeaderKey), nil } // send ping path diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 676a7e758..ea8af48ca 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -65,9 +65,9 @@ configStorage: # Path for levelDB file path: /tmp/centrifuge_config_data.leveldb -# Tenant key storage -tenants: - keystore: /tmp/tenants +# Accounts key storage +accounts: + keystore: /tmp/accounts # Interface where the API and P2P Server listens to nodeHostname: 0.0.0.0 diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index 20676d4dc..fc27f29c3 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -8,9 +8,9 @@ ethereum: identityId: "0x010101010101" -# Tenant key storage -tenants: - keystore: /tmp/tenants +# Accounts key storage +accounts: + keystore: /tmp/accounts queue: numWorkers: 2 diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index d0c4785e7..f7192cca6 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -37,7 +37,7 @@ var createIdentityCmd = &cobra.Command{ } } cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - tc, err := configstore.TempTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) + tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) if err != nil { panic(err) } diff --git a/cmd/common.go b/cmd/common.go index 9486ea584..164030133 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -89,7 +89,7 @@ func CreateConfig( cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) generateKeys(cfg) - tc, err := configstore.TempTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) + tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) if err != nil { return err } diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 81f52aed3..2763181d6 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -39,7 +39,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } - tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), cfg) + tc, err := NewAccount(nc.GetEthereumDefaultAccountName(), cfg) if err != nil { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } @@ -48,11 +48,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } - _, err = service.GetTenant(i) - // if main tenant config doesn't exist in the db, add it - // Another additional check we can do is check if there are more than 0 tenant configs in the db but main tenant is not, then it might indicate a problem + _, err = service.GetAccount(i) + // if main account doesn't exist in the db, add it + // Another additional check we can do is check if there are more than 0 accouns in the db but main account is not, then it might indicate a problem if err != nil { - _, err = service.CreateTenant(tc) + _, err = service.CreateAccount(tc) if err != nil { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("%v", err)) } diff --git a/config/configstore/bootstrapper_test.go b/config/configstore/bootstrapper_test.go index 3492546bd..55292edc3 100644 --- a/config/configstore/bootstrapper_test.go +++ b/config/configstore/bootstrapper_test.go @@ -23,6 +23,6 @@ func TestBootstrapper_BootstrapHappy(t *testing.T) { nc := NewNodeConfig(cfg) i, err := nc.GetIdentityID() assert.NoError(t, err) - _, err = configService.GetTenant(i) + _, err = configService.GetAccount(i) assert.NoError(t, err) } diff --git a/config/configstore/handler.go b/config/configstore/handler.go index 85a3b0f1b..612c7f0bf 100644 --- a/config/configstore/handler.go +++ b/config/configstore/handler.go @@ -32,8 +32,8 @@ func GRPCAccountHandler(svc config.Service) accountpb.AccountServiceServer { return &grpcHandler{service: svc} } -// deriveAllTenantResponse derives all valid accounts, will not return accounts that fail at load time -func (h grpcHandler) deriveAllTenantResponse(cfgs []config.TenantConfiguration) (*accountpb.GetAllAccountResponse, error) { +// deriveAllAccountResponse derives all valid accounts, will not return accounts that fail at load time +func (h grpcHandler) deriveAllAccountResponse(cfgs []config.Account) (*accountpb.GetAllAccountResponse, error) { response := new(accountpb.GetAllAccountResponse) for _, t := range cfgs { tpb, err := t.CreateProtobuf() @@ -63,29 +63,29 @@ func (h grpcHandler) GetAccount(ctx context.Context, req *accountpb.GetAccountRe if err != nil { return nil, err } - tenantConfig, err := h.service.GetTenant(id) + accountConfig, err := h.service.GetAccount(id) if err != nil { return nil, err } - return tenantConfig.CreateProtobuf() + return accountConfig.CreateProtobuf() } func (h grpcHandler) GetAllAccounts(ctx context.Context, req *empty.Empty) (*accountpb.GetAllAccountResponse, error) { - cfgs, err := h.service.GetAllTenants() + cfgs, err := h.service.GetAllAccounts() if err != nil { return nil, err } - return h.deriveAllTenantResponse(cfgs) + return h.deriveAllAccountResponse(cfgs) } func (h grpcHandler) CreateAccount(ctx context.Context, data *accountpb.AccountData) (*accountpb.AccountData, error) { apiLog.Infof("Creating account: %v", data) - tenantConfig := new(TenantConfig) - err := tenantConfig.loadFromProtobuf(data) + accountConfig := new(Account) + err := accountConfig.loadFromProtobuf(data) if err != nil { return nil, err } - tc, err := h.service.CreateTenant(tenantConfig) + tc, err := h.service.CreateAccount(accountConfig) if err != nil { return nil, err } @@ -94,7 +94,7 @@ func (h grpcHandler) CreateAccount(ctx context.Context, data *accountpb.AccountD func (h grpcHandler) GenerateAccount(ctx context.Context, req *empty.Empty) (*accountpb.AccountData, error) { apiLog.Infof("Generating account") - tc, err := h.service.GenerateTenant() + tc, err := h.service.GenerateAccount() if err != nil { return nil, err } @@ -103,12 +103,12 @@ func (h grpcHandler) GenerateAccount(ctx context.Context, req *empty.Empty) (*ac func (h grpcHandler) UpdateAccount(ctx context.Context, req *accountpb.UpdateAccountRequest) (*accountpb.AccountData, error) { apiLog.Infof("Updating account: %v", req) - tenantConfig := new(TenantConfig) - err := tenantConfig.loadFromProtobuf(req.Data) + accountConfig := new(Account) + err := accountConfig.loadFromProtobuf(req.Data) if err != nil { return nil, err } - tc, err := h.service.UpdateTenant(tenantConfig) + tc, err := h.service.UpdateAccount(accountConfig) if err != nil { return nil, err } diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 50619e088..13ff32a6e 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -45,7 +45,7 @@ func TestGrpcHandler_GetAccountNotExist(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: "0x123456789"}) @@ -53,62 +53,62 @@ func TestGrpcHandler_GetAccountNotExist(t *testing.T) { assert.Nil(t, readCfg) } -func TestGrpcHandler_GetTenant(t *testing.T) { +func TestGrpcHandler_GetAccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - tenantCfg, err := NewTenantConfig("main", cfg) + accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tcpb, err := tenantCfg.CreateProtobuf() + accpb, err := accountCfg.CreateProtobuf() assert.NoError(t, err) - _, err = h.CreateAccount(context.Background(), tcpb) + _, err = h.CreateAccount(context.Background(), accpb) assert.Nil(t, err) - tid, err := tenantCfg.GetIdentityID() + tid, err := accountCfg.GetIdentityID() assert.Nil(t, err) readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) assert.NotNil(t, readCfg) } -func TestGrpcHandler_deriveAllTenantResponseFailure(t *testing.T) { +func TestGrpcHandler_deriveAllAccountResponseFailure(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - tenantCfg1, err := NewTenantConfig("main", cfg) - tenantCfg2, err := NewTenantConfig("main", cfg) - tco := tenantCfg1.(*TenantConfig) + accountCfg1, err := NewAccount("main", cfg) + accountCfg2, err := NewAccount("main", cfg) + tco := accountCfg1.(*Account) tco.EthereumAccount = nil - tcs := []config.TenantConfiguration{tco, tenantCfg2} + tcs := []config.Account{tco, accountCfg2} hc := h.(*grpcHandler) - resp, err := hc.deriveAllTenantResponse(tcs) + resp, err := hc.deriveAllAccountResponse(tcs) assert.NoError(t, err) assert.Equal(t, 1, len(resp.Data)) } -func TestGrpcHandler_GetAllTenants(t *testing.T) { +func TestGrpcHandler_GetAllAccounts(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - tenantCfg1, err := NewTenantConfig("main", cfg) - tenantCfg2, err := NewTenantConfig("main", cfg) - tc := tenantCfg2.(*TenantConfig) - tc.IdentityID = []byte("0x123456789") - tc1pb, err := tenantCfg1.CreateProtobuf() + accountCfg1, err := NewAccount("main", cfg) + accountCfg2, err := NewAccount("main", cfg) + acc := accountCfg2.(*Account) + acc.IdentityID = []byte("0x123456789") + tc1pb, err := accountCfg1.CreateProtobuf() assert.NoError(t, err) _, err = h.CreateAccount(context.Background(), tc1pb) assert.Nil(t, err) - tcpb, err := tc.CreateProtobuf() + accpb, err := acc.CreateProtobuf() assert.NoError(t, err) - _, err = h.CreateAccount(context.Background(), tcpb) + _, err = h.CreateAccount(context.Background(), accpb) assert.Nil(t, err) resp, err := h.GetAllAccounts(context.Background(), nil) @@ -116,69 +116,69 @@ func TestGrpcHandler_GetAllTenants(t *testing.T) { assert.Equal(t, 2, len(resp.Data)) } -func TestGrpcHandler_CreateTenant(t *testing.T) { +func TestGrpcHandler_CreateAccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - tc, err := NewTenantConfig("main", cfg) + tc, err := NewAccount("main", cfg) assert.Nil(t, err) - tcpb, err := tc.CreateProtobuf() + accpb, err := tc.CreateProtobuf() assert.NoError(t, err) - _, err = h.CreateAccount(context.Background(), tcpb) + _, err = h.CreateAccount(context.Background(), accpb) assert.Nil(t, err) // Already exists - tcpb, err = tc.CreateProtobuf() + accpb, err = tc.CreateProtobuf() assert.NoError(t, err) - _, err = h.CreateAccount(context.Background(), tcpb) + _, err = h.CreateAccount(context.Background(), accpb) assert.NotNil(t, err) } -func TestGrpcHandler_GenerateTenant(t *testing.T) { +func TestGrpcHandler_GenerateAccount(t *testing.T) { s := MockService{} - t1, _ := NewTenantConfig(cfg.GetEthereumDefaultAccountName(), cfg) - s.On("GenerateTenant").Return(t1, nil) + t1, _ := NewAccount(cfg.GetEthereumDefaultAccountName(), cfg) + s.On("GenerateAccount").Return(t1, nil) h := GRPCAccountHandler(s) tc, err := h.GenerateAccount(context.Background(), nil) assert.NoError(t, err) assert.NotNil(t, tc) } -func TestGrpcHandler_UpdateTenant(t *testing.T) { +func TestGrpcHandler_UpdateAccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) h := GRPCAccountHandler(svc) - tcfg, err := NewTenantConfig("main", cfg) + tcfg, err := NewAccount("main", cfg) assert.Nil(t, err) tid, err := tcfg.GetIdentityID() assert.Nil(t, err) - tc := tcfg.(*TenantConfig) + acc := tcfg.(*Account) // Config doesn't exist - tcpb, err := tcfg.CreateProtobuf() + accpb, err := tcfg.CreateProtobuf() assert.NoError(t, err) - _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tcpb}) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: accpb}) assert.NotNil(t, err) - tcpb, err = tcfg.CreateProtobuf() + accpb, err = tcfg.CreateProtobuf() assert.NoError(t, err) - _, err = h.CreateAccount(context.Background(), tcpb) + _, err = h.CreateAccount(context.Background(), accpb) assert.Nil(t, err) - tc.EthereumDefaultAccountName = "other" - tccpb, err := tc.CreateProtobuf() + acc.EthereumDefaultAccountName = "other" + tccpb, err := acc.CreateProtobuf() assert.NoError(t, err) _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tccpb}) assert.Nil(t, err) readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) assert.Nil(t, err) - assert.Equal(t, tc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) + assert.Equal(t, acc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) } diff --git a/config/configstore/mock_service.go b/config/configstore/mock_service.go index 3284eb99b..69cc123cc 100644 --- a/config/configstore/mock_service.go +++ b/config/configstore/mock_service.go @@ -11,9 +11,9 @@ type MockService struct { mock.Mock } -func (m MockService) GenerateTenant() (config.TenantConfiguration, error) { +func (m MockService) GenerateAccount() (config.Account, error) { args := m.Called() - return args.Get(0).(config.TenantConfiguration), args.Error(1) + return args.Get(0).(config.Account), args.Error(1) } func (m MockService) GetConfig() (config.Configuration, error) { @@ -21,14 +21,14 @@ func (m MockService) GetConfig() (config.Configuration, error) { return args.Get(0).(*NodeConfig), args.Error(1) } -func (m MockService) GetTenant(identifier []byte) (config.TenantConfiguration, error) { +func (m MockService) GetAccount(identifier []byte) (config.Account, error) { args := m.Called(identifier) - return args.Get(0).(config.TenantConfiguration), args.Error(1) + return args.Get(0).(config.Account), args.Error(1) } -func (m MockService) GetAllTenants() ([]config.TenantConfiguration, error) { +func (m MockService) GetAllAccounts() ([]config.Account, error) { args := m.Called() - v, _ := args.Get(0).([]config.TenantConfiguration) + v, _ := args.Get(0).([]config.Account) return v, nil } @@ -37,17 +37,17 @@ func (m MockService) CreateConfig(data config.Configuration) (config.Configurati return args.Get(0).(*NodeConfig), args.Error(0) } -func (m MockService) CreateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { +func (m MockService) CreateAccount(data config.Account) (config.Account, error) { args := m.Called(data) - return args.Get(0).(*TenantConfig), args.Error(0) + return args.Get(0).(*Account), args.Error(0) } -func (m MockService) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { +func (m MockService) UpdateAccount(data config.Account) (config.Account, error) { args := m.Called(data) - return args.Get(0).(*TenantConfig), args.Error(0) + return args.Get(0).(*Account), args.Error(0) } -func (m MockService) DeleteTenant(identifier []byte) error { +func (m MockService) DeleteAccount(identifier []byte) error { args := m.Called(identifier) return args.Error(0) } diff --git a/config/configstore/model.go b/config/configstore/model.go index 5fded7597..da425506e 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -30,9 +30,9 @@ func NewKeyPair(pub, priv string) KeyPair { // NodeConfig exposes configs specific to the node type NodeConfig struct { - MainIdentity TenantConfig + MainIdentity Account StoragePath string - TenantsKeystore string + AccountsKeystore string P2PPort int P2PExternalIP string P2PConnectionTimeout time.Duration @@ -110,9 +110,9 @@ func (nc *NodeConfig) GetConfigStoragePath() string { panic("irrelevant, NodeConfig#GetConfigStoragePath must not be used") } -// GetTenantsKeystore returns the tenant keystore path. -func (nc *NodeConfig) GetTenantsKeystore() string { - return nc.TenantsKeystore +// GetAccountsKeystore returns the accounts keystore path. +func (nc *NodeConfig) GetAccountsKeystore() string { + return nc.AccountsKeystore } // GetP2PPort refer the interface @@ -328,7 +328,7 @@ func convertAddressesToStringMap(addresses map[config.ContractName]common.Addres func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) error { identityID, _ := hexutil.Decode(data.MainIdentity.IdentityId) - nc.MainIdentity = TenantConfig{ + nc.MainIdentity = Account{ EthereumAccount: &config.AccountConfig{ Address: data.MainIdentity.EthAccount.Address, Key: data.MainIdentity.EthAccount.Key, @@ -394,7 +394,7 @@ func NewNodeConfig(c config.Configuration) config.Configuration { ethAuthPub, ethAuthPriv := c.GetEthAuthKeyPair() return &NodeConfig{ - MainIdentity: TenantConfig{ + MainIdentity: Account{ EthereumAccount: &config.AccountConfig{ Address: mainAccount.Address, Key: mainAccount.Key, @@ -413,7 +413,7 @@ func NewNodeConfig(c config.Configuration) config.Configuration { }, }, StoragePath: c.GetStoragePath(), - TenantsKeystore: c.GetTenantsKeystore(), + AccountsKeystore: c.GetAccountsKeystore(), P2PPort: c.GetP2PPort(), P2PExternalIP: c.GetP2PExternalIP(), P2PConnectionTimeout: c.GetP2PConnectionTimeout(), @@ -446,8 +446,8 @@ func extractSmartContractAddresses(c config.Configuration) map[config.ContractNa return sms } -// TenantConfig exposes configs specific to a tenant in the node -type TenantConfig struct { +// Account exposes options specific to an account in the node +type Account struct { EthereumAccount *config.AccountConfig EthereumDefaultAccountName string EthereumContextWaitTimeout time.Duration @@ -459,86 +459,86 @@ type TenantConfig struct { } // GetEthereumAccount gets EthereumAccount -func (tc *TenantConfig) GetEthereumAccount() *config.AccountConfig { - return tc.EthereumAccount +func (acc *Account) GetEthereumAccount() *config.AccountConfig { + return acc.EthereumAccount } // GetEthereumDefaultAccountName gets EthereumDefaultAccountName -func (tc *TenantConfig) GetEthereumDefaultAccountName() string { - return tc.EthereumDefaultAccountName +func (acc *Account) GetEthereumDefaultAccountName() string { + return acc.EthereumDefaultAccountName } // GetReceiveEventNotificationEndpoint gets ReceiveEventNotificationEndpoint -func (tc *TenantConfig) GetReceiveEventNotificationEndpoint() string { - return tc.ReceiveEventNotificationEndpoint +func (acc *Account) GetReceiveEventNotificationEndpoint() string { + return acc.ReceiveEventNotificationEndpoint } // GetIdentityID gets IdentityID -func (tc *TenantConfig) GetIdentityID() ([]byte, error) { - return tc.IdentityID, nil +func (acc *Account) GetIdentityID() ([]byte, error) { + return acc.IdentityID, nil } // GetSigningKeyPair gets SigningKeyPair -func (tc *TenantConfig) GetSigningKeyPair() (pub, priv string) { - return tc.SigningKeyPair.Pub, tc.SigningKeyPair.Priv +func (acc *Account) GetSigningKeyPair() (pub, priv string) { + return acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv } // GetEthAuthKeyPair gets EthAuthKeyPair -func (tc *TenantConfig) GetEthAuthKeyPair() (pub, priv string) { - return tc.EthAuthKeyPair.Pub, tc.EthAuthKeyPair.Priv +func (acc *Account) GetEthAuthKeyPair() (pub, priv string) { + return acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv } // GetEthereumContextWaitTimeout gets EthereumContextWaitTimeout -func (tc *TenantConfig) GetEthereumContextWaitTimeout() time.Duration { - return tc.EthereumContextWaitTimeout +func (acc *Account) GetEthereumContextWaitTimeout() time.Duration { + return acc.EthereumContextWaitTimeout } // ID Get the ID of the document represented by this model -func (tc *TenantConfig) ID() []byte { - return tc.IdentityID +func (acc *Account) ID() []byte { + return acc.IdentityID } // Type Returns the underlying type of the Model -func (tc *TenantConfig) Type() reflect.Type { - return reflect.TypeOf(tc) +func (acc *Account) Type() reflect.Type { + return reflect.TypeOf(acc) } // JSON return the json representation of the model -func (tc *TenantConfig) JSON() ([]byte, error) { - return json.Marshal(tc) +func (acc *Account) JSON() ([]byte, error) { + return json.Marshal(acc) } // FromJSON initialize the model with a json -func (tc *TenantConfig) FromJSON(data []byte) error { - return json.Unmarshal(data, tc) +func (acc *Account) FromJSON(data []byte) error { + return json.Unmarshal(data, acc) } // CreateProtobuf creates protobuf for config -func (tc *TenantConfig) CreateProtobuf() (*accountpb.AccountData, error) { - if tc.EthereumAccount == nil { +func (acc *Account) CreateProtobuf() (*accountpb.AccountData, error) { + if acc.EthereumAccount == nil { return nil, errors.New("nil EthereumAccount field") } return &accountpb.AccountData{ EthAccount: &accountpb.EthereumAccount{ - Address: tc.EthereumAccount.Address, - Key: tc.EthereumAccount.Key, - Password: tc.EthereumAccount.Password, + Address: acc.EthereumAccount.Address, + Key: acc.EthereumAccount.Key, + Password: acc.EthereumAccount.Password, }, - EthDefaultAccountName: tc.EthereumDefaultAccountName, - ReceiveEventNotificationEndpoint: tc.ReceiveEventNotificationEndpoint, - IdentityId: hexutil.Encode(tc.IdentityID), + EthDefaultAccountName: acc.EthereumDefaultAccountName, + ReceiveEventNotificationEndpoint: acc.ReceiveEventNotificationEndpoint, + IdentityId: hexutil.Encode(acc.IdentityID), SigningKeyPair: &accountpb.KeyPair{ - Pub: tc.SigningKeyPair.Pub, - Pvt: tc.SigningKeyPair.Priv, + Pub: acc.SigningKeyPair.Pub, + Pvt: acc.SigningKeyPair.Priv, }, EthauthKeyPair: &accountpb.KeyPair{ - Pub: tc.EthAuthKeyPair.Pub, - Pvt: tc.EthAuthKeyPair.Priv, + Pub: acc.EthAuthKeyPair.Pub, + Pvt: acc.EthAuthKeyPair.Priv, }, }, nil } -func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) error { +func (acc *Account) loadFromProtobuf(data *accountpb.AccountData) error { if data == nil { return errors.NewTypedError(ErrNilParameter, errors.New("nil data")) } @@ -551,27 +551,27 @@ func (tc *TenantConfig) loadFromProtobuf(data *accountpb.AccountData) error { if data.EthauthKeyPair == nil { return errors.NewTypedError(ErrNilParameter, errors.New("nil EthauthKeyPair field")) } - tc.EthereumAccount = &config.AccountConfig{ + acc.EthereumAccount = &config.AccountConfig{ Address: data.EthAccount.Address, Key: data.EthAccount.Key, Password: data.EthAccount.Password, } - tc.EthereumDefaultAccountName = data.EthDefaultAccountName - tc.IdentityID, _ = hexutil.Decode(data.IdentityId) - tc.ReceiveEventNotificationEndpoint = data.ReceiveEventNotificationEndpoint - tc.SigningKeyPair = KeyPair{ + acc.EthereumDefaultAccountName = data.EthDefaultAccountName + acc.IdentityID, _ = hexutil.Decode(data.IdentityId) + acc.ReceiveEventNotificationEndpoint = data.ReceiveEventNotificationEndpoint + acc.SigningKeyPair = KeyPair{ Pub: data.SigningKeyPair.Pub, Priv: data.SigningKeyPair.Pvt, } - tc.EthAuthKeyPair = KeyPair{ + acc.EthAuthKeyPair = KeyPair{ Pub: data.EthauthKeyPair.Pub, Priv: data.EthauthKeyPair.Pvt, } return nil } -// NewTenantConfig creates a new TenantConfig instance with configs -func NewTenantConfig(ethAccountName string, c config.Configuration) (config.TenantConfiguration, error) { +// NewAccount creates a new Account instance with configs +func NewAccount(ethAccountName string, c config.Configuration) (config.Account, error) { id, err := c.GetIdentityID() if err != nil { return nil, err @@ -580,7 +580,7 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (config.Tena if err != nil && ethAccountName != "" { return nil, err } - return &TenantConfig{ + return &Account{ EthereumAccount: acc, EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), EthereumContextWaitTimeout: c.GetEthereumContextWaitTimeout(), @@ -591,13 +591,13 @@ func NewTenantConfig(ethAccountName string, c config.Configuration) (config.Tena }, nil } -// TempTenantConfig creates a new TenantConfig without id validation, Must only be used for tenant creation. -func TempTenantConfig(ethAccountName string, c config.Configuration) (config.TenantConfiguration, error) { +// TempAccount creates a new Account without id validation, Must only be used for account creation. +func TempAccount(ethAccountName string, c config.Configuration) (config.Account, error) { acc, err := c.GetEthereumAccount(ethAccountName) if err != nil && ethAccountName != "" { return nil, err } - return &TenantConfig{ + return &Account{ EthereumAccount: acc, EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), IdentityID: []byte{}, diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 7a3abe1a8..6a8b42d66 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -3,23 +3,18 @@ package configstore import ( + "math/big" "reflect" "testing" + "time" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" - "github.com/golang/protobuf/proto" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" - - "github.com/centrifuge/go-centrifuge/config" - - "github.com/ethereum/go-ethereum/common/hexutil" - - "math/big" - "time" - "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -105,7 +100,7 @@ func (m *mockConfig) GetConfigStoragePath() string { return args.Get(0).(string) } -func (m *mockConfig) GetTenantsKeystore() string { +func (m *mockConfig) GetAccountsKeystore() string { args := m.Called() return args.Get(0).(string) } @@ -252,7 +247,7 @@ func TestNewNodeConfig(t *testing.T) { c.AssertExpectations(t) } -func TestNewTenantConfig(t *testing.T) { +func TestNewAccountConfig(t *testing.T) { c := &mockConfig{} c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() @@ -261,7 +256,7 @@ func TestNewTenantConfig(t *testing.T) { c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() - _, err := NewTenantConfig("name", c) + _, err := NewAccount("name", c) assert.NoError(t, err) c.AssertExpectations(t) } @@ -286,7 +281,7 @@ func TestNodeConfigProtobuf(t *testing.T) { assert.Equal(t, ncpb.MainIdentity.IdentityId, hexutil.Encode(ncCopy.MainIdentity.IdentityID)) } -func TestTenantConfigProtobuf_validationFailures(t *testing.T) { +func TestAccountProtobuf_validationFailures(t *testing.T) { c := &mockConfig{} c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil) c.On("GetEthereumDefaultAccountName").Return("dummyAcc") @@ -295,49 +290,49 @@ func TestTenantConfigProtobuf_validationFailures(t *testing.T) { c.On("GetSigningKeyPair").Return("pub", "priv") c.On("GetEthAuthKeyPair").Return("pub", "priv") c.On("GetEthereumContextWaitTimeout").Return(time.Second) - tc, err := NewTenantConfig("name", c) + tc, err := NewAccount("name", c) assert.Nil(t, err) c.AssertExpectations(t) // Nil EthAccount - tco := tc.(*TenantConfig) + tco := tc.(*Account) tco.EthereumAccount = nil - tcpb, err := tco.CreateProtobuf() + accpb, err := tco.CreateProtobuf() assert.Error(t, err) - assert.Nil(t, tcpb) + assert.Nil(t, accpb) // Nil payload - tc, err = NewTenantConfig("name", c) + tc, err = NewAccount("name", c) assert.Nil(t, err) - tcpb, err = tc.CreateProtobuf() + accpb, err = tc.CreateProtobuf() assert.NoError(t, err) - tco = tc.(*TenantConfig) + tco = tc.(*Account) err = tco.loadFromProtobuf(nil) assert.Error(t, err) // Nil EthAccount - ethacc := proto.Clone(tcpb.EthAccount) - tcpb.EthAccount = nil - err = tco.loadFromProtobuf(tcpb) + ethacc := proto.Clone(accpb.EthAccount) + accpb.EthAccount = nil + err = tco.loadFromProtobuf(accpb) assert.Error(t, err) - tcpb.EthAccount = ethacc.(*accountpb.EthereumAccount) + accpb.EthAccount = ethacc.(*accountpb.EthereumAccount) // Nil SigningKeyPair - signKey := proto.Clone(tcpb.SigningKeyPair) - tcpb.SigningKeyPair = nil - err = tco.loadFromProtobuf(tcpb) + signKey := proto.Clone(accpb.SigningKeyPair) + accpb.SigningKeyPair = nil + err = tco.loadFromProtobuf(accpb) assert.Error(t, err) - tcpb.SigningKeyPair = signKey.(*accountpb.KeyPair) + accpb.SigningKeyPair = signKey.(*accountpb.KeyPair) // Nil EthauthKeyPair - ethAuthKey := proto.Clone(tcpb.EthauthKeyPair) - tcpb.EthauthKeyPair = nil - err = tco.loadFromProtobuf(tcpb) + ethAuthKey := proto.Clone(accpb.EthauthKeyPair) + accpb.EthauthKeyPair = nil + err = tco.loadFromProtobuf(accpb) assert.Error(t, err) - tcpb.EthauthKeyPair = ethAuthKey.(*accountpb.KeyPair) + accpb.EthauthKeyPair = ethAuthKey.(*accountpb.KeyPair) } -func TestTenantConfigProtobuf(t *testing.T) { +func TestAccountConfigProtobuf(t *testing.T) { c := &mockConfig{} c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() @@ -346,31 +341,31 @@ func TestTenantConfigProtobuf(t *testing.T) { c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() - tc, err := NewTenantConfig("name", c) + tc, err := NewAccount("name", c) assert.Nil(t, err) c.AssertExpectations(t) - tcpb, err := tc.CreateProtobuf() + accpb, err := tc.CreateProtobuf() assert.NoError(t, err) - assert.Equal(t, tc.GetReceiveEventNotificationEndpoint(), tcpb.ReceiveEventNotificationEndpoint) + assert.Equal(t, tc.GetReceiveEventNotificationEndpoint(), accpb.ReceiveEventNotificationEndpoint) i, err := tc.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, hexutil.Encode(i), tcpb.IdentityId) + assert.Equal(t, hexutil.Encode(i), accpb.IdentityId) _, priv := tc.GetSigningKeyPair() - assert.Equal(t, priv, tcpb.SigningKeyPair.Pvt) + assert.Equal(t, priv, accpb.SigningKeyPair.Pvt) - tcCopy := new(TenantConfig) - err = tcCopy.loadFromProtobuf(tcpb) + tcCopy := new(Account) + err = tcCopy.loadFromProtobuf(accpb) assert.NoError(t, err) - assert.Equal(t, tcpb.ReceiveEventNotificationEndpoint, tcCopy.ReceiveEventNotificationEndpoint) - assert.Equal(t, tcpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) - assert.Equal(t, tcpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) + assert.Equal(t, accpb.ReceiveEventNotificationEndpoint, tcCopy.ReceiveEventNotificationEndpoint) + assert.Equal(t, accpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) + assert.Equal(t, accpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) } func createMockConfig() *mockConfig { c := &mockConfig{} c.On("GetStoragePath").Return("dummyStorage").Once() - c.On("GetTenantsKeystore").Return("dummyKeyStorage").Once() + c.On("GetAccountsKeystore").Return("dummyKeyStorage").Once() c.On("GetP2PPort").Return(30000).Once() c.On("GetP2PExternalIP").Return("ip").Once() c.On("GetP2PConnectionTimeout").Return(time.Second).Once() diff --git a/config/configstore/repository.go b/config/configstore/repository.go index 23b81e41e..96f5a49d4 100644 --- a/config/configstore/repository.go +++ b/config/configstore/repository.go @@ -6,46 +6,46 @@ import ( ) const ( - configPrefix string = "config" - tenantPrefix string = "tenant-" + configPrefix string = "config" + accountPrefix string = "account-" ) // repository defines the required methods for the config repository. type repository interface { - // RegisterTenant registers tenant config in DB - RegisterTenant(config config.TenantConfiguration) + // RegisterAccount registers account in DB + RegisterAccount(config config.Account) // RegisterConfig registers node config in DB RegisterConfig(config config.Configuration) - // GetTenant returns the tenant config Model associated with tenant ID - GetTenant(id []byte) (config.TenantConfiguration, error) + // GetAccount returns the acocunt Model associated with account ID + GetAccount(id []byte) (config.Account, error) // GetConfig returns the node config model GetConfig() (config.Configuration, error) - // GetAllTenants returns a list of all tenant models in the config DB - GetAllTenants() ([]config.TenantConfiguration, error) + // GetAllAccounts returns a list of all account models in the config DB + GetAllAccounts() ([]config.Account, error) - // Create creates the tenant config model if not present in the DB. + // Create creates the account model if not present in the DB. // should error out if the config exists. - CreateTenant(id []byte, tenant config.TenantConfiguration) error + CreateAccount(id []byte, account config.Account) error // Create creates the node config model if not present in the DB. // should error out if the config exists. CreateConfig(config config.Configuration) error - // Update strictly updates the tenant config model. - // Will error out when the config model doesn't exist in the DB. - UpdateTenant(id []byte, tenant config.TenantConfiguration) error + // Update strictly updates the account model. + // Will error out when the account model doesn't exist in the DB. + UpdateAccount(id []byte, account config.Account) error // Update strictly updates the node config model. // Will error out when the config model doesn't exist in the DB. UpdateConfig(nodeConfig config.Configuration) error - // Delete deletes tenant config - // Will not error out when config model doesn't exists in DB - DeleteTenant(id []byte) error + // Delete deletes account config + // Will not error out when account model doesn't exists in DB + DeleteAccount(id []byte) error // Delete deletes node config // Will not error out when config model doesn't exists in DB @@ -56,8 +56,8 @@ type repo struct { db storage.Repository } -func getTenantKey(id []byte) []byte { - return append([]byte(tenantPrefix), id...) +func getAccountKey(id []byte) []byte { + return append([]byte(accountPrefix), id...) } func getConfigKey() []byte { @@ -69,8 +69,8 @@ func newDBRepository(db storage.Repository) repository { return &repo{db: db} } -// RegisterTenant registers tenant config in DB -func (r *repo) RegisterTenant(config config.TenantConfiguration) { +// RegisterAccount registers account in DB +func (r *repo) RegisterAccount(config config.Account) { r.db.Register(config) } @@ -79,14 +79,14 @@ func (r *repo) RegisterConfig(config config.Configuration) { r.db.Register(config) } -// GetTenant returns the tenant config Model associated with tenant ID -func (r *repo) GetTenant(id []byte) (config.TenantConfiguration, error) { - key := getTenantKey(id) +// GetAccount returns the account Model associated with account ID +func (r *repo) GetAccount(id []byte) (config.Account, error) { + key := getAccountKey(id) model, err := r.db.Get(key) if err != nil { return nil, err } - return model.(*TenantConfig), nil + return model.(*Account), nil } // GetConfig returns the node config model @@ -99,25 +99,25 @@ func (r *repo) GetConfig() (config.Configuration, error) { return model.(*NodeConfig), nil } -// GetAllTenants iterates over all tenant entries in DB and returns a list of Models -// If an error occur reading a tenant, throws a warning and continue -func (r *repo) GetAllTenants() ([]config.TenantConfiguration, error) { - var tenantConfigs []config.TenantConfiguration - models, err := r.db.GetAllByPrefix(tenantPrefix) +// GetAllAccounts iterates over all account entries in DB and returns a list of Models +// If an error occur reading a account, throws a warning and continue +func (r *repo) GetAllAccounts() ([]config.Account, error) { + var accountConfigs []config.Account + models, err := r.db.GetAllByPrefix(accountPrefix) if err != nil { return nil, err } - for _, tc := range models { - tenantConfigs = append(tenantConfigs, tc.(*TenantConfig)) + for _, acc := range models { + accountConfigs = append(accountConfigs, acc.(*Account)) } - return tenantConfigs, nil + return accountConfigs, nil } -// Create creates the tenant config model if not present in the DB. +// Create creates the account model if not present in the DB. // should error out if the config exists. -func (r *repo) CreateTenant(id []byte, tenant config.TenantConfiguration) error { - key := getTenantKey(id) - return r.db.Create(key, tenant) +func (r *repo) CreateAccount(id []byte, account config.Account) error { + key := getAccountKey(id) + return r.db.Create(key, account) } // Create creates the node config model if not present in the DB. @@ -127,11 +127,11 @@ func (r *repo) CreateConfig(config config.Configuration) error { return r.db.Create(key, config) } -// Update strictly updates the tenant config model. +// Update strictly updates the account model. // Will error out when the config model doesn't exist in the DB. -func (r *repo) UpdateTenant(id []byte, tenant config.TenantConfiguration) error { - key := getTenantKey(id) - return r.db.Update(key, tenant) +func (r *repo) UpdateAccount(id []byte, account config.Account) error { + key := getAccountKey(id) + return r.db.Update(key, account) } // Update strictly updates the node config model. @@ -141,10 +141,10 @@ func (r *repo) UpdateConfig(nodeConfig config.Configuration) error { return r.db.Update(key, nodeConfig) } -// Delete deletes tenant config +// Delete deletes account // Will not error out when config model doesn't exists in DB -func (r *repo) DeleteTenant(id []byte) error { - key := getTenantKey(id) +func (r *repo) DeleteAccount(id []byte) error { + key := getAccountKey(id) return r.db.Delete(key) } diff --git a/config/configstore/repository_test.go b/config/configstore/repository_test.go index 5bdd5834e..f5164b0d5 100644 --- a/config/configstore/repository_test.go +++ b/config/configstore/repository_test.go @@ -40,7 +40,7 @@ func TestMain(m *testing.M) { // clean db _ = configdb.Delete(getConfigKey()) i, _ := nc.GetIdentityID() - _ = configdb.Delete(getTenantKey(i)) + _ = configdb.Delete(getAccountKey(i)) result := m.Run() cleanupDBFiles() os.Exit(result) @@ -55,60 +55,60 @@ func TestUnregisteredModel(t *testing.T) { repo, _, _ := getRandomStorage() assert.NotNil(t, repo) id := utils.RandomSlice(32) - newTenant := &TenantConfig{ + newaccount := &Account{ IdentityID: id, EthereumDefaultAccountName: "main", } - err := repo.CreateTenant(id, newTenant) + err := repo.CreateAccount(id, newaccount) assert.Nil(t, err) // Error on non registered model - _, err = repo.GetTenant(id) + _, err = repo.GetAccount(id) assert.NotNil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) - _, err = repo.GetTenant(id) + _, err = repo.GetAccount(id) assert.Nil(t, err) } -func TestTenantOperations(t *testing.T) { +func TestaccountOperations(t *testing.T) { repo, _, _ := getRandomStorage() assert.NotNil(t, repo) id := utils.RandomSlice(32) - newTenant := &TenantConfig{ + newaccount := &Account{ IdentityID: id, EthereumDefaultAccountName: "main", } - repo.RegisterTenant(&TenantConfig{}) - err := repo.CreateTenant(id, newTenant) + repo.RegisterAccount(&Account{}) + err := repo.CreateAccount(id, newaccount) assert.Nil(t, err) - // Create tenant already exist - err = repo.CreateTenant(id, newTenant) + // Create account already exist + err = repo.CreateAccount(id, newaccount) assert.NotNil(t, err) - readTenant, err := repo.GetTenant(id) + readaccount, err := repo.GetAccount(id) assert.Nil(t, err) - assert.Equal(t, reflect.TypeOf(newTenant), readTenant.Type()) - i, err := readTenant.GetIdentityID() + assert.Equal(t, reflect.TypeOf(newaccount), readaccount.Type()) + i, err := readaccount.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, newTenant.IdentityID, i) + assert.Equal(t, newaccount.IdentityID, i) - // Update tenant - newTenant.EthereumDefaultAccountName = "secondary" - err = repo.UpdateTenant(id, newTenant) + // Update account + newaccount.EthereumDefaultAccountName = "secondary" + err = repo.UpdateAccount(id, newaccount) assert.Nil(t, err) - // Update tenant does not exist + // Update account does not exist newId := utils.RandomSlice(32) - err = repo.UpdateTenant(newId, newTenant) + err = repo.UpdateAccount(newId, newaccount) assert.NotNil(t, err) - // Delete tenant - err = repo.DeleteTenant(id) + // Delete account + err = repo.DeleteAccount(id) assert.Nil(t, err) - _, err = repo.GetTenant(id) + _, err = repo.GetAccount(id) assert.NotNil(t, err) } @@ -147,37 +147,37 @@ func TestConfigOperations(t *testing.T) { assert.NotNil(t, err) } -func TestLevelDBRepo_GetAllTenants(t *testing.T) { +func TestLevelDBRepo_GetAllAccounts(t *testing.T) { repo, _, _ := getRandomStorage() assert.NotNil(t, repo) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) ids := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32), utils.RandomSlice(32)} - ten1 := &TenantConfig{ + ten1 := &Account{ IdentityID: ids[0], EthereumDefaultAccountName: "main", } - ten2 := &TenantConfig{ + ten2 := &Account{ IdentityID: ids[1], EthereumDefaultAccountName: "main", } - ten3 := &TenantConfig{ + ten3 := &Account{ IdentityID: ids[2], EthereumDefaultAccountName: "main", } - err := repo.CreateTenant(ids[0], ten1) + err := repo.CreateAccount(ids[0], ten1) assert.Nil(t, err) - err = repo.CreateTenant(ids[1], ten2) + err = repo.CreateAccount(ids[1], ten2) assert.Nil(t, err) - err = repo.CreateTenant(ids[2], ten3) + err = repo.CreateAccount(ids[2], ten3) assert.Nil(t, err) - tenants, err := repo.GetAllTenants() + accounts, err := repo.GetAllAccounts() assert.Nil(t, err) - assert.Equal(t, 3, len(tenants)) - t0Id, _ := tenants[0].GetIdentityID() - t1Id, _ := tenants[1].GetIdentityID() - t2Id, _ := tenants[2].GetIdentityID() + assert.Equal(t, 3, len(accounts)) + t0Id, _ := accounts[0].GetIdentityID() + t1Id, _ := accounts[1].GetIdentityID() + t2Id, _ := accounts[2].GetIdentityID() assert.Contains(t, ids, t0Id) assert.Contains(t, ids, t1Id) assert.Contains(t, ids, t2Id) diff --git a/config/configstore/service.go b/config/configstore/service.go index 42b51b9bd..9c9dcbc42 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -41,12 +41,12 @@ func (s service) GetConfig() (config.Configuration, error) { return s.repo.GetConfig() } -func (s service) GetTenant(identifier []byte) (config.TenantConfiguration, error) { - return s.repo.GetTenant(identifier) +func (s service) GetAccount(identifier []byte) (config.Account, error) { + return s.repo.GetAccount(identifier) } -func (s service) GetAllTenants() ([]config.TenantConfiguration, error) { - return s.repo.GetAllTenants() +func (s service) GetAllAccounts() ([]config.Account, error) { + return s.repo.GetAllAccounts() } func (s service) CreateConfig(data config.Configuration) (config.Configuration, error) { @@ -57,22 +57,22 @@ func (s service) CreateConfig(data config.Configuration) (config.Configuration, return data, s.repo.UpdateConfig(data) } -func (s service) CreateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { +func (s service) CreateAccount(data config.Account) (config.Account, error) { id, err := data.GetIdentityID() if err != nil { return nil, err } - return data, s.repo.CreateTenant(id, data) + return data, s.repo.CreateAccount(id, data) } -func (s service) GenerateTenant() (config.TenantConfiguration, error) { +func (s service) GenerateAccount() (config.Account, error) { nc, err := s.GetConfig() if err != nil { return nil, err } - // copy the main tenant for basic settings - mtc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), nc) + // copy the main account for basic settings + mtc, err := NewAccount(nc.GetEthereumDefaultAccountName(), nc) if nil != err { return nil, err } @@ -87,48 +87,48 @@ func (s service) GenerateTenant() (config.TenantConfiguration, error) { } <-confirmations - // copy the main tenant again to create the new tenant - tc, err := NewTenantConfig(nc.GetEthereumDefaultAccountName(), nc) + // copy the main account again to create the new account + acc, err := NewAccount(nc.GetEthereumDefaultAccountName(), nc) if err != nil { return nil, err } CID := id.CentID() - tc, err = generateTenantKeys(nc.GetTenantsKeystore(), tc.(*TenantConfig), CID) + acc, err = generateAccountKeys(nc.GetAccountsKeystore(), acc.(*Account), CID) if err != nil { return nil, err } - // minor hack to set same p2p keys as node to tenant: Set the new tenant ID to copy of main tenant and create p2p keys - mtcc := mtc.(*TenantConfig) + // minor hack to set same p2p keys as node to account: Set the new account ID to copy of main account and create p2p keys + mtcc := mtc.(*Account) mtcc.IdentityID = CID[:] err = s.idService.AddKeyFromConfig(mtcc, identity.KeyPurposeP2P) if err != nil { return nil, err } - err = s.idService.AddKeyFromConfig(tc, identity.KeyPurposeSigning) + err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeSigning) if err != nil { return nil, err } - err = s.idService.AddKeyFromConfig(tc, identity.KeyPurposeEthMsgAuth) + err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeEthMsgAuth) if err != nil { return nil, err } - err = s.repo.CreateTenant(CID[:], tc) + err = s.repo.CreateAccount(CID[:], acc) if err != nil { return nil, err } // initiate network handling s.protocolSetterFinder().InitProtocolForCID(CID) - return tc, nil + return acc, nil } -func generateTenantKeys(keystore string, tc *TenantConfig, CID identity.CentID) (*TenantConfig, error) { - tc.IdentityID = CID[:] +func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*Account, error) { + acc.IdentityID = CID[:] Pub, err := createKeyPath(keystore, CID, signingPubKeyName) if err != nil { return nil, err @@ -137,7 +137,7 @@ func generateTenantKeys(keystore string, tc *TenantConfig, CID identity.CentID) if err != nil { return nil, err } - tc.SigningKeyPair = KeyPair{ + acc.SigningKeyPair = KeyPair{ Pub: Pub, Priv: Priv, } @@ -149,24 +149,24 @@ func generateTenantKeys(keystore string, tc *TenantConfig, CID identity.CentID) if err != nil { return nil, err } - tc.EthAuthKeyPair = KeyPair{ + acc.EthAuthKeyPair = KeyPair{ Pub: ePub, Priv: ePriv, } - err = crypto.GenerateSigningKeyPair(tc.SigningKeyPair.Pub, tc.SigningKeyPair.Priv, "ed25519") + err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, "ed25519") if err != nil { return nil, err } - err = crypto.GenerateSigningKeyPair(tc.EthAuthKeyPair.Pub, tc.EthAuthKeyPair.Priv, "secp256k1") + err = crypto.GenerateSigningKeyPair(acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv, "secp256k1") if err != nil { return nil, err } - return tc, nil + return acc, nil } func createKeyPath(keyStorepath string, CID identity.CentID, keyName string) (string, error) { tdir := fmt.Sprintf("%s/%s", keyStorepath, CID.String()) - // create tenant specific key dir + // create account specific key dir if _, err := os.Stat(tdir); os.IsNotExist(err) { err := os.MkdirAll(tdir, os.ModePerm) if err != nil { @@ -176,16 +176,16 @@ func createKeyPath(keyStorepath string, CID identity.CentID, keyName string) (st return fmt.Sprintf("%s/%s", tdir, keyName), nil } -func (s service) UpdateTenant(data config.TenantConfiguration) (config.TenantConfiguration, error) { +func (s service) UpdateAccount(data config.Account) (config.Account, error) { id, err := data.GetIdentityID() if err != nil { return nil, err } - return data, s.repo.UpdateTenant(id, data) + return data, s.repo.UpdateAccount(id, data) } -func (s service) DeleteTenant(identifier []byte) error { - return s.repo.DeleteTenant(identifier) +func (s service) DeleteAccount(identifier []byte) error { + return s.repo.DeleteAccount(identifier) } // RetrieveConfig retrieves system config giving priority to db stored config diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go index 3e104d529..2d454a735 100644 --- a/config/configstore/service_integration_test.go +++ b/config/configstore/service_integration_test.go @@ -37,11 +37,11 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestService_GenerateTenantHappy(t *testing.T) { - tct, err := cfg.GenerateTenant() +func TestService_GenerateAccountHappy(t *testing.T) { + tct, err := cfg.GenerateAccount() assert.NoError(t, err) i, _ := tct.GetIdentityID() - tc, err := cfg.GetTenant(i) + tc, err := cfg.GetAccount(i) assert.NoError(t, err) assert.NotNil(t, tc) i, _ = tc.GetIdentityID() diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index d8d1158f3..89f9f8e90 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -38,29 +38,29 @@ func TestService_GetConfig(t *testing.T) { assert.NotNil(t, cfg) } -func TestService_GetTenant_NoTenant(t *testing.T) { +func TestService_GetAccount_NoAccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) - cfg, err := svc.GetTenant([]byte("0x123456789")) + cfg, err := svc.GetAccount([]byte("0x123456789")) assert.NotNil(t, err) assert.Nil(t, cfg) } -func TestService_GetTenant(t *testing.T) { +func TestService_GetAccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) - tenantCfg, err := NewTenantConfig("main", cfg) + accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tid, _ := tenantCfg.GetIdentityID() - err = repo.CreateTenant(tid, tenantCfg) + tid, _ := accountCfg.GetIdentityID() + err = repo.CreateAccount(tid, accountCfg) assert.Nil(t, err) - cfg, err := svc.GetTenant(tid) + cfg, err := svc.GetAccount(tid) assert.Nil(t, err) assert.NotNil(t, cfg) } @@ -81,81 +81,81 @@ func TestService_CreateConfig(t *testing.T) { assert.Nil(t, err) } -func TestService_CreateTenant(t *testing.T) { +func TestService_Createaccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) - tenantCfg, err := NewTenantConfig("main", cfg) + accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - newCfg, err := svc.CreateTenant(tenantCfg) + newCfg, err := svc.CreateAccount(accountCfg) assert.Nil(t, err) i, err := newCfg.GetIdentityID() assert.Nil(t, err) - tid, err := tenantCfg.GetIdentityID() + tid, err := accountCfg.GetIdentityID() assert.Nil(t, err) assert.Equal(t, tid, i) - //Tenant already exists - _, err = svc.CreateTenant(tenantCfg) + //account already exists + _, err = svc.CreateAccount(accountCfg) assert.NotNil(t, err) } -func TestService_UpdateTenant(t *testing.T) { +func TestService_Updateaccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) - tenantCfg, err := NewTenantConfig("main", cfg) + accountCfg, err := NewAccount("main", cfg) - // Tenant doesn't exist - newCfg, err := svc.UpdateTenant(tenantCfg) + // account doesn't exist + newCfg, err := svc.UpdateAccount(accountCfg) assert.NotNil(t, err) - newCfg, err = svc.CreateTenant(tenantCfg) + newCfg, err = svc.CreateAccount(accountCfg) assert.Nil(t, err) i, err := newCfg.GetIdentityID() assert.Nil(t, err) - tid, err := tenantCfg.GetIdentityID() + tid, err := accountCfg.GetIdentityID() assert.Nil(t, err) assert.Equal(t, tid, i) - tc := tenantCfg.(*TenantConfig) - tc.EthereumDefaultAccountName = "other" - newCfg, err = svc.UpdateTenant(tenantCfg) + acc := accountCfg.(*Account) + acc.EthereumDefaultAccountName = "other" + newCfg, err = svc.UpdateAccount(accountCfg) assert.Nil(t, err) - assert.Equal(t, tc.EthereumDefaultAccountName, newCfg.GetEthereumDefaultAccountName()) + assert.Equal(t, acc.EthereumDefaultAccountName, newCfg.GetEthereumDefaultAccountName()) } -func TestService_DeleteTenant(t *testing.T) { +func TestService_Deleteaccount(t *testing.T) { idService := &testingcommons.MockIDService{} repo, _, err := getRandomStorage() assert.Nil(t, err) - repo.RegisterTenant(&TenantConfig{}) + repo.RegisterAccount(&Account{}) svc := DefaultService(repo, idService) - tenantCfg, err := NewTenantConfig("main", cfg) + accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tid, err := tenantCfg.GetIdentityID() + tid, err := accountCfg.GetIdentityID() assert.Nil(t, err) //No config, no error - err = svc.DeleteTenant(tid) + err = svc.DeleteAccount(tid) assert.Nil(t, err) - _, err = svc.CreateTenant(tenantCfg) + _, err = svc.CreateAccount(accountCfg) assert.Nil(t, err) - err = svc.DeleteTenant(tid) + err = svc.DeleteAccount(tid) assert.Nil(t, err) - _, err = svc.GetTenant(tid) + _, err = svc.GetAccount(tid) assert.NotNil(t, err) } -func TestGenerateTenantKeys(t *testing.T) { - tc, err := generateTenantKeys("/tmp/tenants/", &TenantConfig{}, identity.RandomCentID()) +func TestGenerateaccountKeys(t *testing.T) { + tc, err := generateAccountKeys("/tmp/accounts/", &Account{}, identity.RandomCentID()) assert.Nil(t, err) assert.NotNil(t, tc.SigningKeyPair) assert.NotNil(t, tc.EthAuthKeyPair) diff --git a/config/configuration.go b/config/configuration.go index 957e038fc..df3533e75 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -31,8 +31,8 @@ import ( var log = logging.Logger("config") -// TenantKey is used as key for the tenant identity in the context.ContextWithValue. -var TenantKey struct{} +// AccountHeaderKey is used as key for the account identity in the context.ContextWithValue. +var AccountHeaderKey struct{} // ContractName is a type to indicate a contract name parameter type ContractName string @@ -73,7 +73,7 @@ type Configuration interface { GetStoragePath() string GetConfigStoragePath() string - GetTenantsKeystore() string + GetAccountsKeystore() string GetP2PPort() int GetP2PExternalIP() string GetP2PConnectionTimeout() time.Duration @@ -111,8 +111,8 @@ type Configuration interface { CreateProtobuf() *configpb.ConfigData } -// TenantConfiguration exposes tenant specific config options -type TenantConfiguration interface { +// Account exposes account options +type Account interface { storage.Model GetEthereumAccount() *AccountConfig @@ -130,13 +130,13 @@ type TenantConfiguration interface { // Service exposes functions over the config objects type Service interface { GetConfig() (Configuration, error) - GetTenant(identifier []byte) (TenantConfiguration, error) - GetAllTenants() ([]TenantConfiguration, error) + GetAccount(identifier []byte) (Account, error) + GetAllAccounts() ([]Account, error) CreateConfig(data Configuration) (Configuration, error) - CreateTenant(data TenantConfiguration) (TenantConfiguration, error) - GenerateTenant() (TenantConfiguration, error) - UpdateTenant(data TenantConfiguration) (TenantConfiguration, error) - DeleteTenant(identifier []byte) error + CreateAccount(data Account) (Account, error) + GenerateAccount() (Account, error) + UpdateAccount(data Account) (Account, error) + DeleteAccount(identifier []byte) error } // configuration holds the configuration details for the node. @@ -231,9 +231,9 @@ func (c *configuration) GetConfigStoragePath() string { return c.GetString("configStorage.path") } -// GetTenantsKeystore returns the tenants keystore location. -func (c *configuration) GetTenantsKeystore() string { - return c.GetString("tenants.keystore") +// GetAccountsKeystore returns the accounts keystore location. +func (c *configuration) GetAccountsKeystore() string { + return c.GetString("accounts.keystore") } // GetP2PPort returns P2P Port. @@ -489,7 +489,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.SetConfigType("yaml") v.Set("storage.path", targetDataDir+"/db/centrifuge_data.leveldb") v.Set("configStorage.path", targetDataDir+"/db/centrifuge_config_data.leveldb") - v.Set("tenants.keystore", targetDataDir+"/tenants") + v.Set("accounts.keystore", targetDataDir+"/accounts") v.Set("identityId", "") v.Set("centrifugeNetwork", network) v.Set("nodeHostname", "0.0.0.0") diff --git a/contextutil/context.go b/contextutil/context.go index 524867d21..9a2989cef 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -26,33 +26,33 @@ const ( ) // NewCentrifugeContext creates new instance of the request headers. -func NewCentrifugeContext(ctx context.Context, cfg config.TenantConfiguration) (context.Context, error) { +func NewCentrifugeContext(ctx context.Context, cfg config.Account) (context.Context, error) { return context.WithValue(ctx, self, cfg), nil } // Self returns Self CentID. func Self(ctx context.Context) (*identity.IDConfig, error) { - tc, ok := ctx.Value(self).(config.TenantConfiguration) + tc, ok := ctx.Value(self).(config.Account) if !ok { return nil, ErrSelfNotFound } return identity.GetIdentityConfig(tc) } -// Tenant extracts the TenanConfig from the given context value -func Tenant(ctx context.Context) (config.TenantConfiguration, error) { - tc, ok := ctx.Value(self).(config.TenantConfiguration) +// Account extracts the TenanConfig from the given context value +func Account(ctx context.Context) (config.Account, error) { + tc, ok := ctx.Value(self).(config.Account) if !ok { return nil, ErrSelfNotFound } return tc, nil } -// Context updates a context with tenant info using the configstore, must only be used for api handlers +// Context updates a context with account info using the configstore, must only be used for api handlers func Context(ctx context.Context, cs config.Service) (context.Context, error) { - tcIDHex, ok := ctx.Value(config.TenantKey).(string) + tcIDHex, ok := ctx.Value(config.AccountHeaderKey).(string) if !ok { - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header %v", config.TenantKey)) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header %v", config.AccountHeaderKey)) } tcID, err := hexutil.Decode(tcIDHex) @@ -60,7 +60,7 @@ func Context(ctx context.Context, cs config.Service) (context.Context, error) { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - tc, err := cs.GetTenant(tcID) + tc, err := cs.GetAccount(tcID) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } diff --git a/documents/anchor_task.go b/documents/anchor_task.go index d9ec909a0..2b700b07a 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -94,7 +94,7 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) }() - tc, err := d.config.GetTenant(d.tenantID[:]) + tc, err := d.config.GetAccount(d.tenantID[:]) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) diff --git a/identity/ethid/ethereum_identity.go b/identity/ethid/ethereum_identity.go index dca7dc080..c8f5c0247 100644 --- a/identity/ethid/ethereum_identity.go +++ b/identity/ethid/ethereum_identity.go @@ -394,7 +394,7 @@ func (ids *ethereumIdentityService) CheckIdentityExists(centrifugeID identity.Ce // CreateIdentity creates an identity representing the id on ethereum func (ids *ethereumIdentityService) CreateIdentity(ctx context.Context, centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { log.Infof("Creating Identity [%x]", centrifugeID) - tc, err := contextutil.Tenant(ctx) + tc, err := contextutil.Account(ctx) if err != nil { return nil, confirmations, err } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index b3e0ac174..b06c6a930 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -106,7 +106,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, docu // MintNFT mints an NFT func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { - tc, err := contextutil.Tenant(ctx) + tc, err := contextutil.Account(ctx) if err != nil { return nil, err } diff --git a/nft/handler_test.go b/nft/handler_test.go index 5cecdf5e3..db221c161 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -51,8 +51,8 @@ func TestNFTMint_success(t *testing.T) { func mockmockConfigStore() *configstore.MockService { mockConfigStore := &configstore.MockService{} - mockConfigStore.On("GetTenant", mock.Anything).Return(&configstore.TenantConfig{}, nil) - mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{}}, nil) + mockConfigStore.On("GetAccount", mock.Anything).Return(&configstore.Account{}, nil) + mockConfigStore.On("GetAllAccounts").Return([]config.Account{&configstore.Account{}}, nil) return mockConfigStore } @@ -60,7 +60,7 @@ func TestNFTMint_InvalidIdentifier(t *testing.T) { nftMintRequest := getTestSetupData() nftMintRequest.Identifier = "32321" mockConfigStore := mockmockConfigStore() - mockConfigStore.On("GetAllTenants").Return(testingconfig.HandlerContext(mockConfigStore)) + mockConfigStore.On("GetAllAccounts").Return(testingconfig.HandlerContext(mockConfigStore)) handler := grpcHandler{mockConfigStore, &mockPaymentObligationService{}} _, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) assert.Error(t, err, "invalid identifier should throw an error") diff --git a/notification/notification.go b/notification/notification.go index 087d53b30..b1adae0d3 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -45,7 +45,7 @@ type webhookSender struct { // Send sends notification to the defined webhook. func (wh webhookSender) Send(ctx context.Context, notification *notificationpb.NotificationMessage) (Status, error) { - tc, err := contextutil.Tenant(ctx) + tc, err := contextutil.Account(ctx) if err != nil { return Failure, err } diff --git a/p2p/client.go b/p2p/client.go index 7c8975722..4baa1a138 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -42,7 +42,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) cid := id.CentID() - tc, err := s.config.GetTenant(cid[:]) + tc, err := s.config.GetAccount(cid[:]) if err == nil { // this is a local tenant h := s.handlerCreator() @@ -142,7 +142,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden var resp *p2ppb.SignatureResponse var header *p2ppb.Header - tc, err := s.config.GetTenant(receiverCentID[:]) + tc, err := s.config.GetAccount(receiverCentID[:]) if err == nil { // this is a local tenant h := s.handlerCreator() diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index c17a2e469..110ce53d3 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -75,17 +75,17 @@ func TestClient_SendAnchoredDocument(t *testing.T) { } } -func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.TenantConfig, identity.Identity, error) { +func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account, identity.Identity, error) { tcID := identity.RandomCentID() - tc, err := configstore.TempTenantConfig("", cfg) + tc, err := configstore.TempAccount("", cfg) assert.NoError(t, err) - tcr := tc.(*configstore.TenantConfig) + tcr := tc.(*configstore.Account) tcr.IdentityID = tcID[:] id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService) if corruptID { tcr.IdentityID = utils.RandomSlice(identity.CentIDLength) } - tc, err = cfgStore.CreateTenant(tcr) + tc, err = cfgStore.CreateAccount(tcr) assert.NoError(t, err) return tcr, id, err } diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index 7e5d4f291..115d556ec 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -89,7 +89,7 @@ func TestPrepareP2PEnvelope(t *testing.T) { id, _ := cfg.GetIdentityID() spk, ssk := cfg.GetSigningKeyPair() - tc := &configstore.TenantConfig{ + tc := &configstore.Account{ IdentityID: id, SigningKeyPair: configstore.KeyPair{ Priv: ssk, diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 534db3b33..f1298492a 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -74,7 +74,7 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - tc, err := srv.config.GetTenant(cid[:]) + tc, err := srv.config.GetAccount(cid[:]) if err != nil { return convertToErrorEnvelop(err) } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 5b8b0ff0d..4fb1d6544 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -67,8 +67,8 @@ func TestMain(m *testing.M) { func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) ctxh := testingconfig.CreateTenantContext(t, cfg) - tc, err := contextutil.Tenant(ctxh) - _, err = cfgService.CreateTenant(tc) + tc, err := contextutil.Account(ctxh) + _, err = cfgService.CreateAccount(tc) assert.NoError(t, err) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) diff --git a/p2p/server.go b/p2p/server.go index 829db6415..011b5b350 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -98,7 +98,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- } func (s *peer) initProtocols() error { - tcs, err := s.config.GetAllTenants() + tcs, err := s.config.GetAllAccounts() if err != nil { return err } diff --git a/p2p/server_test.go b/p2p/server_test.go index f6d644c92..4b36d2f72 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -156,6 +156,6 @@ func updateKeys(c config.Configuration) config.Configuration { func mockmockConfigStore(n config.Configuration) *configstore.MockService { mockConfigStore := &configstore.MockService{} mockConfigStore.On("GetConfig").Return(n, nil) - mockConfigStore.On("GetAllTenants").Return([]config.TenantConfiguration{&configstore.TenantConfig{IdentityID: utils.RandomSlice(identity.CentIDLength)}}, nil) + mockConfigStore.On("GetAllAccounts").Return([]config.Account{&configstore.Account{IdentityID: utils.RandomSlice(identity.CentIDLength)}}, nil) return mockConfigStore } diff --git a/resources/data.go b/resources/data.go index e4c7ca72c..e7a32be2e 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x49\x73\xdb\x3a\x12\xbe\xeb\x57\x74\xc9\x97\x99\xaa\xa1\xcc\x7d\x51\xd5\xab\x29\x79\x4b\xf2\xe2\x78\x64\x5b\x8e\x5f\x7c\x99\x80\x40\x53\x44\x4c\x01\x0c\x00\x6a\xc9\xaf\x9f\x02\x48\x39\x76\xbc\xbc\x59\x6a\x72\x31\x05\xa0\x1b\xbd\x7c\xfd\xa1\x3b\x07\x70\x82\x15\xe9\x1a\x03\x0c\xd7\xd8\xc8\x76\x85\xc2\x80\x41\x6d\x04\x1a\x20\x4b\xc2\x85\x36\xa0\xb8\xb8\xc7\x72\x37\xa2\x28\x8c\xe2\x55\xb7\xc4\x0b\x34\x1b\xa9\xee\xa7\xa0\x3a\xad\x39\x11\x35\x6f\x9a\x91\x53\xc6\x05\x82\xa9\x11\xd8\xa0\x57\xf4\x27\x35\x98\x9a\x18\x38\x7e\xd0\x00\x2b\xc2\x85\xb1\xfa\x47\xfb\x23\xd3\x11\xc0\x01\x9c\x4b\x4a\x1a\x67\x02\x17\x4b\xa0\x52\x18\x45\xa8\x01\xc2\x98\x42\xad\x51\x83\x40\x64\x60\x24\x94\x08\x1a\x0d\x6c\xb8\xa9\x01\xc5\x1a\xd6\x44\x71\x52\x36\xa8\x27\x23\xd8\xcb\x5b\x95\x00\x9c\x4d\x21\x8a\x22\xf7\x8d\xa6\x46\x85\xdd\x6a\xf0\xe0\x03\x9b\x42\x1e\xe5\xfd\x5e\x29\xa5\xd1\x46\x91\x76\x8e\xa8\x74\x2f\xeb\xc1\xf8\x90\xb7\xf1\x61\x10\x66\x13\x7f\xe2\x4f\x82\x43\x43\xdb\xc3\x28\x0f\xfd\xf0\x90\xb7\x95\x3e\xbc\x5c\x2d\x2e\xb7\xe5\xe6\xbe\xbb\xfb\xf2\xe5\xa4\xea\x7e\x2c\xca\xed\xe9\xec\x0a\x17\x17\xc7\xe7\xf2\xc7\x6e\x97\x24\xf9\xfa\x52\x2c\x3f\xaf\xe7\x9f\xbe\x9d\x7f\xb9\x1f\xff\x89\xd2\x68\xaf\xf4\x73\x95\x9e\x5e\xa4\xab\xfb\xef\xb7\xf8\xed\xf6\xe3\x6d\xf8\x7d\xde\x05\xe9\x1f\x2d\x7b\x17\xdd\xff\x2e\x83\x45\xb4\xaa\x49\x3d\x3f\x4a\xae\x31\x11\x41\xaf\x74\x1f\xaa\xd9\x3e\x52\xbd\x03\xd6\x7d\x14\x86\x9b\xdd\x19\xa1\x46\xaa\xdd\x14\xc6\xe3\x5f\x76\xae\x70\xc9\xb5\x79\xb2\x45\x04\xad\xa5\xba\xc2\x56\x6a\xfe\x8b\x54\x4b\x76\x16\x26\xff\x28\x1b\xbe\x24\x86\x4b\xe1\xf6\x5c\xf2\x3e\x11\x2e\x5e\x84\xd2\x90\xe3\x11\x3c\x46\x4c\x6f\xe0\x01\x5c\x74\x2b\x54\x9c\xc2\x87\x13\x90\x95\x43\xcf\x23\x9c\xfc\x94\xec\x13\x99\x04\x83\xd4\xd1\x3e\x5b\xd0\x70\x6d\xac\xa4\x90\x0c\x9f\x03\xad\x55\x72\xcd\xdd\x86\x74\xba\x1f\x19\xb0\x37\xef\x4f\xb3\x1f\x25\x93\x30\x4c\x26\xa1\xef\x4f\xe2\xf0\x57\x04\x04\xe1\x49\xf4\x51\xca\xdb\x73\xce\xe9\xe5\xe7\xcd\xa2\x5e\x1c\x7d\x49\xb7\x1f\xe9\x5c\x9e\x57\xe9\xd5\xe5\x97\xdf\xcf\xda\x4d\x15\xa8\x2c\xd9\x9c\x6f\xc3\xbb\xab\xa8\x3d\x66\xc1\xf8\x25\xf5\x79\x3a\x09\x03\xff\x35\xf5\x97\x77\x9f\x66\xf9\xbb\xf9\x7b\xb5\x3e\xbd\x3b\x2a\x36\xec\x5e\xde\xd0\xd9\x6c\x75\x7c\xf7\xbe\x2d\x70\xb7\xbb\x8b\xaf\x4f\xf3\xe5\x99\x8a\xea\xc5\xc5\x1f\xe3\x21\x46\xa7\x03\xda\xf7\x51\xb4\x21\xf6\xe0\x6a\xa8\xe7\x57\xea\x21\x1e\x84\xcf\x89\x0d\x0f\x30\x6c\x1b\xb9\x43\x06\xd7\x2b\xa2\x0c\x1c\x0f\x30\xd3\x50\x49\xe5\x02\xba\xe4\x6b\x14\x4f\x42\xf9\x1c\x8a\xf0\x2a\x16\xfd\x6d\xe1\xb3\xb0\x88\x93\x2c\xc0\x2c\xca\xe3\x30\x2d\x32\x92\xa6\x65\x46\x8a\x82\xf8\x05\x63\x29\xcd\x22\x16\x25\x29\x7b\x03\xb5\xfe\xb6\x48\x53\x9f\xfa\x51\xc1\xa2\x20\x88\x93\x88\x54\x3e\x4b\x72\x9a\xa4\x69\x9a\x85\x11\x2b\x68\x58\x91\x8c\xa5\x48\xdf\xc0\xb7\xbf\xcd\xaa\x3c\x89\x59\x45\x8a\xdc\x0f\x42\x96\x55\x24\x49\x68\xee\x47\x65\x49\xc2\x30\xf5\x4b\xca\x10\xe3\x32\x41\xf6\x56\x25\xf8\x5b\x56\xfa\x49\x1e\xcc\x8a\x28\xcc\xd3\x34\xce\x93\x24\x0a\xf3\x19\x3b\x29\xfd\xd3\x30\x09\x82\x3c\x4e\x63\xbf\x2a\x30\x39\x71\x35\x53\xa2\x12\xa4\xa9\x91\x2f\x6b\x33\x80\xee\xe0\xe0\x60\xc8\xc0\x47\xb9\x26\x02\xce\x66\x97\xc3\x6f\x0f\x6e\x2d\xdb\x71\x51\x75\x8a\xc0\x4e\x76\xb0\xb4\x34\x2d\x00\x95\x92\xca\xc2\x69\x51\x73\x0d\x0a\xbf\x77\x36\x73\x5c\x83\x90\x06\x74\xd7\xb6\x52\x19\x64\x50\x22\x25\x9d\x46\x2b\xa9\x5c\xb5\xd8\x23\xaa\x13\xc2\x52\xad\x23\x52\x6d\x88\xb1\x25\xd3\xd9\xa5\x09\x5c\x75\xa2\x5f\xf7\xbc\x61\xed\x37\xa2\x68\xcd\xd7\x38\x19\xff\x6d\x30\x0a\x60\x63\x2b\xce\x48\x60\xf2\xef\x4e\x82\x40\xe3\x48\xbc\x25\x8a\x9b\x5d\x7f\x91\xd3\x72\xef\xfc\xc1\xe5\xb4\xff\xf9\x75\x38\xe0\x79\xb4\x26\x5c\xfc\xd6\x6f\x7b\x9e\xb5\xf6\xb7\xc8\x8f\xfc\x18\x3c\x6f\x43\x54\x3b\xfc\xf1\x4a\xa2\x14\x47\x05\x49\x9a\xfb\xbe\xef\x83\xe7\x09\xe9\x11\x41\x39\x0a\xe3\x95\x8d\xa4\xf7\xba\x5f\xd3\xa8\xd6\xe8\x35\x36\xa8\xe0\x79\x2b\xb2\xf5\x5a\x5b\xd4\x10\x26\x56\x48\x0b\xd2\xea\x5a\x9a\x61\xd1\xad\xad\xb8\x78\xf2\xd3\xda\x4c\xa8\xe1\x6b\x04\xcf\xb3\x60\xb6\x21\x92\x55\xf5\x3c\x12\xe0\x79\xac\xf4\xa8\x5c\xb5\xf6\xbc\x14\xa0\x35\xb3\x2e\x11\x5a\xa3\xa7\xf9\x0f\x84\xd8\x2f\x52\xf0\xbc\x6f\x5a\x0a\xd5\x52\xaf\x96\xda\x68\x20\x4d\xf3\x68\x8d\x0b\x83\xaa\x22\x14\xed\xfa\xd7\xa7\xe9\x7e\x1e\xcc\x97\x32\x7f\x64\xdd\x47\x66\x6b\x4f\x60\x6f\x88\x91\x70\x8b\xe5\xb5\x5d\x37\x1a\x5c\x4c\x14\x54\x4a\xae\xa0\x13\x46\x75\xda\x42\x42\x2a\xbe\xe4\x62\x0a\x93\xc9\xf8\xd5\x7c\xda\x22\x7f\x96\xcb\xaf\x9e\xd7\x09\x4d\x2a\xf4\x70\xdb\x4a\x8d\x5f\xa1\x6a\xc8\xf2\x17\x00\xff\x67\xcc\x1e\xfe\x8f\xcc\xfe\xa4\x96\xfe\x6d\x6e\x0f\xfc\x78\x12\x24\xf1\x24\xc8\x27\xc9\xb3\xd7\x7d\x4f\xbe\x73\x9d\x72\x82\x37\xdd\xd9\xdd\x45\x17\xbc\xdb\xae\xf5\xee\x68\x71\xad\x16\xba\x58\x9b\xa3\xb4\x34\x9f\x66\xe2\xfd\x99\x3c\xff\x56\xde\xff\x38\x26\xe3\x17\xd4\x27\x93\x20\x4f\x26\x61\x94\xbd\x7a\xc1\xf1\x3b\xba\xe1\x8b\x6f\xf2\xe3\xed\xfb\xea\x88\xc4\x79\x78\x33\x37\x04\x6f\xb6\x17\xe7\x1b\x96\xff\x28\xc5\x51\x70\x9d\x6d\x70\x76\x77\xb3\xbd\x7b\x9b\xdd\x1d\x69\xbc\xca\xed\xe1\xff\x81\xdc\xdf\xe0\xf6\x3c\x29\xa3\xb0\xca\x48\x54\xc5\x7e\x9c\x07\x55\x10\x46\x51\xec\xc7\x41\x9a\xf9\x34\xa7\x25\xfa\x59\x95\xb1\xac\xa0\x6f\x72\x7b\x12\x13\x8c\xb2\xa8\xf2\x8b\xb4\x22\x55\xc8\xca\xb4\xcc\x49\x9c\x66\x41\x46\xfd\xb2\xc8\x91\x56\xc4\xcf\x12\xc6\xde\xe4\xf6\x38\x8e\xab\x34\x2e\x30\xf2\xb3\x38\x0e\x31\x4b\x29\xad\xb2\x28\x8b\xd3\x14\x93\xb0\x0a\x52\xbf\x28\x8b\x3c\x4c\xfd\xb7\xb9\xdd\x8f\x83\x0c\xcb\x28\x2b\xe2\x20\x48\xe3\x28\xcd\x63\x3f\x38\x49\xd3\xb4\xc8\x63\x7a\x7a\x92\xa5\x45\x3c\x3b\xa2\x47\x65\x30\x1e\xd9\x76\x98\x18\x02\xd7\x46\x2a\xb2\xc4\x91\xee\xff\xf6\x4d\xee\x9c\x98\xda\x85\xb8\xb1\xbd\xd2\xc9\x11\x54\xbc\xc1\x91\xbd\xd4\xd4\x53\x38\x34\xab\xf6\xf0\x67\xb3\xfd\x4f\x46\x0c\x99\xb8\x93\xac\xb4\x7a\x8f\xa5\xa8\xf8\xb2\x53\xce\xac\x87\x0b\xa8\x5b\xbd\xfe\xef\xaf\xe9\x15\x3c\xbb\x6d\x81\x82\x08\x03\xf7\xb8\x83\xc1\x87\x91\x71\x4b\x2e\xf1\xf7\xb8\xb3\xab\x38\xa8\x1b\x76\xac\xdc\x87\x07\x4a\xdb\x58\x18\x3a\x34\xcd\xe6\x1f\x80\x08\x06\xf3\x70\x0e\xd7\x3d\x1f\xd9\x12\x47\x61\x6b\x78\x64\xab\xfc\xbd\xd4\x46\x90\x15\x4e\xc1\x77\xad\xb1\x3f\x3a\x80\xb9\x54\x66\x50\x62\x15\xbc\x2c\x68\x0f\x4d\x21\xf7\xf3\xd0\x5e\x6e\xeb\xdc\x33\xd2\x51\x3a\xd0\xc7\xf1\xd2\xa3\x36\x6c\xfb\xf0\x5c\xb7\x48\x79\xb5\x83\xd3\xad\x71\xcc\x01\x1f\xe6\x8f\x6c\x75\x54\x47\x89\xb0\x83\x86\x42\xcb\xe6\x0c\x88\x01\x5e\x41\x89\x35\x17\x0c\x2e\x66\x0b\xab\x06\x07\xe9\x0f\xf3\x29\x6c\x26\xdb\xc9\x6e\xf2\xa3\x0f\xbe\xb5\xba\xd3\xc8\x1e\x6a\xc9\x7a\xdd\x90\x1d\x2a\x9b\x02\x67\xae\x23\x02\x77\x7a\xc1\x57\x28\x3b\xe7\xa6\x00\xd9\xa2\x18\xa6\x9f\x81\xcb\x1d\xc7\xb9\xf7\x69\x04\xfb\xe5\x41\x64\x0a\xe3\xc8\xd7\x0e\x70\x97\x1d\x76\xf8\x8b\xbb\xee\x76\xa2\x77\x82\xd6\x4a\x0a\xd9\x69\x4b\x9b\x14\xb5\xe6\x62\x39\xfa\x6e\x05\xfa\x60\xf4\xb3\x9b\xee\x5d\xef\x56\x25\x2a\x4b\xbc\x96\x37\x50\xe9\x43\x2a\x85\xb6\x5c\x3e\x90\xf0\xc6\x36\xcf\xa5\x7b\xac\x24\x25\xa6\x8f\x8c\x36\x44\x99\xae\x1d\x81\x95\xbf\xed\x05\xa7\xd0\xbb\x77\xa6\x10\x35\x74\x2d\x1c\xcf\x6f\x80\xee\x68\x83\xba\x77\xb5\xbf\xc0\xf6\x21\x1b\xc2\xdd\xc8\x67\xed\xc5\x35\x5a\x14\xc1\xb0\x7d\x4b\xb8\xf3\xf6\xd3\xf5\x14\x02\xeb\xe8\x03\xf3\x69\x97\x42\x4e\x9f\x3a\x3d\xda\x33\xdf\x90\x67\x6c\xd0\x72\xda\xa6\xe6\xb4\x7e\x60\x45\x20\x94\xca\x4e\xb8\x97\xce\x36\x45\xc3\x03\x25\x6d\x10\x86\x97\x85\x01\xef\x5f\x3f\xda\x69\x23\x57\xc3\x25\xfb\x2a\x1a\x46\xdc\x59\xaf\xe6\xc2\x81\x76\x6c\xc7\xda\xf1\xc3\x20\xeb\x0a\x74\x50\xfc\x70\x2f\x6d\x6c\xbf\xd2\xe3\xeb\x2f\x1b\x74\xed\x1a\x57\x08\x1b\x0d\x52\x01\x6f\xe9\x30\xdd\xda\x61\xd6\x7e\x52\x62\xac\xd9\x2e\x24\x7f\xb5\xd1\x95\x0c\x6f\xae\xce\xa7\x50\x1b\xd3\x4e\x0f\x0f\x5d\x7f\x60\x9b\x8a\x69\x91\xc4\xc9\x3e\x99\x6e\xfa\x5e\x12\xeb\x0b\xa7\xd6\xdc\x25\xd1\x73\xfb\x39\x85\xc0\xdf\xff\x7b\x76\xb8\xe1\x2b\x6e\xfa\xc3\xe7\xf6\x73\x0a\x71\x16\x84\x51\x9e\x3f\x01\xa9\x91\x2e\x5b\x3d\xb4\xc4\x4f\xcf\x8c\x22\x42\x93\x87\xe6\xc3\xfa\xc0\x58\x3f\xad\x13\x70\xfd\x99\xab\xfe\xde\x15\x30\x8a\x2f\x97\xa8\x90\xf5\x90\x36\xb8\x35\xfb\x44\xf7\xb0\x4e\x7d\x8b\xeb\xd7\x2e\x56\x48\x18\x48\xd1\xec\x6c\xb9\xec\xc1\xbe\xff\x2f\x8b\xbd\x49\x3f\x55\x5f\x21\x61\x4f\xd5\x07\xc9\xa0\xfd\xc2\x66\xe2\xb1\xed\xad\x94\x0d\xac\xc8\x16\x14\x1a\xc5\xfb\x06\x43\xa3\x60\x40\x9e\x1c\x93\x6b\x57\xca\x2b\xb2\xbd\xea\xcf\x4d\x21\x1c\x62\xfa\xb2\x4a\xd7\xe5\xad\x49\xe3\xf4\xee\xfa\x02\x20\xd6\x40\xda\x29\xe5\xc6\xe5\x47\x12\x35\xd1\x50\x22\xda\x79\xda\x20\x35\x2e\x4c\x7b\x05\xf6\x3e\xfb\xac\x85\x83\x07\x27\x5c\x3b\xb4\x38\x8d\x5a\xae\x9e\xa1\x4d\x03\x93\x8f\x87\x01\x30\x5b\x67\x11\x69\xf9\x08\xc0\x6c\xe7\x52\x36\x33\x6a\x69\xe1\x54\x58\x4d\x6c\x0a\x46\x75\x68\x6b\x8d\x88\x1d\x30\x2c\xbb\xe5\x72\xa0\x24\x5b\x02\x8e\x00\x96\x12\xec\x25\x23\xb7\xdb\x97\x5a\xdb\x2a\x59\xb9\xf4\x3c\x88\x58\xb2\xb3\xab\x53\xa8\x48\xa3\x71\xf4\xaf\x00\x00\x00\xff\xff\x32\xb3\x83\xb8\x74\x12\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xb9\x71\x5c\xd9\x96\xe3\x1b\xbf\x34\x20\x70\x28\x22\xa6\x00\x06\x00\xb5\xe4\xd7\x77\x00\x52\x8e\x1d\x2f\xb7\xcb\x34\x2f\xa6\x00\x9c\xfd\x3b\x1f\x0e\x72\x00\x27\x58\x91\xae\x31\xc0\x70\x8d\x8d\x6c\x57\x28\x0c\x18\xd4\x46\xa0\x01\xb2\x24\x5c\x68\x03\x8a\x8b\x7b\x2c\x77\x23\x8a\xc2\x28\x5e\x75\x4b\xbc\x40\xb3\x91\xea\x7e\x0a\xaa\xd3\x9a\x13\x51\xf3\xa6\x19\x39\x65\x5c\x20\x98\x1a\x81\x0d\x7a\x45\x7f\x52\x83\xa9\x89\x81\xe3\x07\x0d\xb0\x22\x5c\x18\xab\x7f\xb4\x3f\x32\x1d\x01\x1c\xc0\xb9\xa4\xa4\x71\x2e\x70\xb1\x04\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x89\xa0\xd1\xc0\x86\x9b\x1a\x50\xac\x61\x4d\x14\x27\x65\x83\x7a\x32\x82\xbd\xbc\x55\x09\xc0\xd9\x14\xa2\x28\x72\xdf\x68\x6a\x54\xd8\xad\x86\x08\x3e\xb0\x29\xe4\x51\xde\xef\x95\x52\x1a\x6d\x14\x69\xe7\x88\x4a\xf7\xb2\x1e\x8c\x0f\x79\x1b\x1f\x06\x61\x36\xf1\x27\xfe\x24\x38\x34\xb4\x3d\x8c\xf2\xd0\x0f\x0f\x79\x5b\xe9\xc3\xcb\xd5\xe2\x72\x5b\x6e\xee\xbb\xbb\x2f\x5f\x4e\xaa\xee\xc7\xa2\xdc\x9e\xce\xae\x70\x71\x71\x7c\x2e\x7f\xec\x76\x49\x92\xaf\x2f\xc5\xf2\xf3\x7a\xfe\xe9\xdb\xf9\x97\xfb\xf1\x9f\x28\x8d\xf6\x4a\x3f\x57\xe9\xe9\x45\xba\xba\xff\x7e\x8b\xdf\x6e\x3f\xde\x86\xdf\xe7\x5d\x90\xfe\xd1\xb2\x77\xd1\xfd\xef\x32\x58\x44\xab\x9a\xd4\xf3\xa3\xe4\x1a\x13\x11\xf4\x4a\xf7\xa9\x9a\xed\x33\xd5\x07\x60\xc3\x47\x61\xb8\xd9\x9d\x11\x6a\xa4\xda\x4d\x61\x3c\xfe\x65\xe7\x0a\x97\x5c\x9b\x27\x5b\x44\xd0\x5a\xaa\x2b\x6c\xa5\xe6\xbf\x48\xb5\x64\x67\x61\xf2\x8f\xb2\xe1\x4b\x62\xb8\x14\x6e\xcf\x15\xef\x13\xe1\xe2\x45\x28\x0d\x35\x1e\xc1\x63\xc4\xf4\x0e\x1e\xc0\x45\xb7\x42\xc5\x29\x7c\x38\x01\x59\x39\xf4\x3c\xc2\xc9\x4f\xc9\xbe\x90\x49\x30\x48\x1d\xed\xab\x05\x0d\xd7\xc6\x4a\x0a\xc9\xf0\x39\xd0\x5a\x25\xd7\xdc\x6d\x48\xa7\xfb\x91\x03\x7b\xf7\xfe\xb4\xfa\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x45\x40\x10\x9e\x44\x1f\xa5\xbc\x3d\xe7\x9c\x5e\x7e\xde\x2c\xea\xc5\xd1\x97\x74\xfb\x91\xce\xe5\x79\x95\x5e\x5d\x7e\xf9\xfd\xac\xdd\x54\x81\xca\x92\xcd\xf9\x36\xbc\xbb\x8a\xda\x63\x16\x8c\x5f\x52\x9f\xa7\x93\x30\xf0\x5f\x53\x7f\x79\xf7\x69\x96\xbf\x9b\xbf\x57\xeb\xd3\xbb\xa3\x62\xc3\xee\xe5\x0d\x9d\xcd\x56\xc7\x77\xef\xdb\x02\x77\xbb\xbb\xf8\xfa\x34\x5f\x9e\xa9\xa8\x5e\x5c\xfc\x31\x1e\x72\x74\x3a\xa0\x7d\x9f\x45\x9b\x62\x0f\xae\x86\x7e\x7e\xa5\x1f\xe2\x41\xf8\x9c\xd8\xf4\x00\xc3\xb6\x91\x3b\x64\x70\xbd\x22\xca\xc0\xf1\x00\x33\x0d\x95\x54\x2e\xa1\x4b\xbe\x46\xf1\x24\x95\xcf\xa1\x08\xaf\x62\xd1\xdf\x16\x3e\x0b\x8b\x38\xc9\x02\xcc\xa2\x3c\x0e\xd3\x22\x23\x69\x5a\x66\xa4\x28\x88\x5f\x30\x96\xd2\x2c\x62\x51\x92\xb2\x37\x50\xeb\x6f\x8b\x34\xf5\xa9\x1f\x15\x2c\x0a\x82\x38\x89\x48\xe5\xb3\x24\xa7\x49\x9a\xa6\x59\x18\xb1\x82\x86\x15\xc9\x58\x8a\xf4\x0d\x7c\xfb\xdb\xac\xca\x93\x98\x55\xa4\xc8\xfd\x20\x64\x59\x45\x92\x84\xe6\x7e\x54\x96\x24\x0c\x53\xbf\xa4\x0c\x31\x2e\x13\x64\x6f\x75\x82\xbf\x65\xa5\x9f\xe4\xc1\xac\x88\xc2\x3c\x4d\xe3\x3c\x49\xa2\x30\x9f\xb1\x93\xd2\x3f\x0d\x93\x20\xc8\xe3\x34\xf6\xab\x02\x93\x13\xd7\x33\x25\x2a\x41\x9a\x1a\xf9\xb2\x36\x03\xe8\x0e\x0e\x0e\x86\x0a\x7c\x94\x6b\x22\xe0\x6c\x76\x39\xfc\xf6\xe0\xd6\xb2\x1d\x17\x55\xa7\x08\xec\x64\x07\x4b\x4b\xd3\x02\x50\x29\xa9\x2c\x9c\x16\x35\xd7\xa0\xf0\x7b\x67\x2b\xc7\x35\x08\x69\x40\x77\x6d\x2b\x95\x41\x06\x25\x52\xd2\x69\xb4\x92\xca\x75\x8b\x3d\xa2\x3a\x21\x2c\xd5\x3a\x22\xd5\x86\x18\xdb\x32\x9d\x5d\x9a\xc0\x55\x27\xfa\x75\xcf\x1b\xd6\x7e\x23\x8a\xd6\x7c\x8d\x93\xf1\xdf\x06\xa7\x00\x36\xb6\xe3\x8c\x04\x26\xff\xee\x24\x08\x34\x8e\xc4\x5b\xa2\xb8\xd9\xf5\x86\x9c\x96\x7b\x17\x0f\x2e\xa7\xfd\xcf\xaf\xc3\x01\xcf\xa3\x35\xe1\xe2\xb7\x7e\xdb\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xda\xe1\x8f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x24\xbd\xd7\xfd\x9a\x46\xb5\x46\xaf\xb1\x49\x05\xcf\x5b\x91\xad\xd7\xda\xa6\x86\x30\xb1\x42\x5a\x90\x56\xd7\xd2\x0c\x8b\x6e\x6d\xc5\xc5\x93\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x05\xb3\x4d\x91\xac\xaa\xe7\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb5\xe7\xa5\x00\xad\x99\x0d\x89\xd0\x1a\x3d\xcd\x7f\x20\xc4\x7e\x91\x82\xe7\x7d\xd3\x52\xa8\x96\x7a\xb5\xd4\x46\x03\x69\x9a\x47\x6b\x5c\x18\x54\x15\xa1\x68\xd7\xbf\x3e\x2d\xf7\xf3\x64\xbe\x54\xf9\x23\x1b\x3e\x32\xdb\x7b\x02\x7b\x47\x8c\x84\x5b\x2c\xaf\xed\xba\xd1\xe0\x72\xa2\xa0\x52\x72\x05\x9d\x30\xaa\xd3\x16\x12\x52\xf1\x25\x17\x53\x98\x4c\xc6\xaf\xd6\xd3\x36\xf9\xb3\x5a\x7e\xf5\xbc\x4e\x68\x52\xa1\x87\xdb\x56\x6a\xfc\x0a\x55\x43\x96\xbf\x00\xf8\x3f\x63\xf6\xf0\x7f\x64\xf6\x27\xbd\xf4\x6f\x73\x7b\xe0\xc7\x93\x20\x89\x27\x41\x3e\x49\x9e\xdd\xee\x7b\xf2\x9d\xeb\x94\x13\xbc\xe9\xce\xee\x2e\xba\xe0\xdd\x76\xad\x77\x47\x8b\x6b\xb5\xd0\xc5\xda\x1c\xa5\xa5\xf9\x34\x13\xef\xcf\xe4\xf9\xb7\xf2\xfe\xc7\x31\x19\xbf\xa0\x3e\x99\x04\x79\x32\x09\xa3\xec\x55\x03\xc7\xef\xe8\x86\x2f\xbe\xc9\x8f\xb7\xef\xab\x23\x12\xe7\xe1\xcd\xdc\x10\xbc\xd9\x5e\x9c\x6f\x58\xfe\xa3\x14\x47\xc1\x75\xb6\xc1\xd9\xdd\xcd\xf6\xee\x6d\x76\x77\xa4\xf1\x2a\xb7\x87\xff\x07\x72\x7f\x83\xdb\xf3\xa4\x8c\xc2\x2a\x23\x51\x15\xfb\x71\x1e\x54\x41\x18\x45\xb1\x1f\x07\x69\xe6\xd3\x9c\x96\xe8\x67\x55\xc6\xb2\x82\xbe\xc9\xed\x49\x4c\x30\xca\xa2\xca\x2f\xd2\x8a\x54\x21\x2b\xd3\x32\x27\x71\x9a\x05\x19\xf5\xcb\x22\x47\x5a\x11\x3f\x4b\x18\x7b\x93\xdb\xe3\x38\xae\xd2\xb8\xc0\xc8\xcf\xe2\x38\xc4\x2c\xa5\xb4\xca\xa2\x2c\x4e\x53\x4c\xc2\x2a\x48\xfd\xa2\x2c\xf2\x30\xf5\xdf\xe6\x76\x3f\x0e\x32\x2c\xa3\xac\x88\x83\x20\x8d\xa3\x34\x8f\xfd\xe0\x24\x4d\xd3\x22\x8f\xe9\xe9\x49\x96\x16\xf1\xec\x88\x1e\x95\xc1\x78\x64\xc7\x61\x62\x08\x5c\x1b\xa9\xc8\x12\x47\xba\xff\xdb\x0f\xb9\x73\x62\x6a\x97\xe2\xc6\xce\x4a\x27\x47\x50\xf1\x06\x47\xd6\xa8\xa9\xa7\x70\x68\x56\xed\xe1\xcf\x61\xfb\x9f\x8c\x18\x32\x71\x27\x59\x69\xf5\x1e\x4b\x51\xf1\x65\xa7\x9c\x5b\x0f\x06\xa8\x5b\xbd\xfe\xef\xcd\xf4\x0a\x9e\x59\x9b\x51\x2a\x3b\x61\x34\xdc\xe3\x0e\x86\x28\x46\x64\x58\xb4\x76\xee\x71\x67\x97\x71\xd0\xb8\xdf\xb2\xb2\x1f\x1e\x68\x6d\x63\xa1\xe8\x10\x35\x9b\x7f\x00\x22\x18\xcc\xc3\x39\x5c\xf7\x9c\x64\xdb\x1c\x85\xed\xe3\x91\xed\xf4\xf7\x52\x1b\x41\x56\x38\x05\xdf\x8d\xc7\xfe\xe8\x00\xe6\x52\x99\x41\x89\x55\xf0\xb2\xa0\x3d\x34\x85\xdc\xcf\x43\x6b\xdc\xf6\xba\x67\xa4\xa3\x75\xa0\x8f\x73\xa6\x47\x6d\xd8\xf6\x29\xba\x6e\x91\xf2\x6a\x07\xa7\x5b\xe3\xd8\x03\x3e\xcc\x1f\xf9\xea\xe8\x8e\x12\x61\x1f\x1b\x0a\x2d\xa3\x33\x20\x06\x78\x05\x25\xd6\x5c\x30\xb8\x98\x2d\xac\x1a\x1c\xa4\x3f\xcc\xa7\xb0\x99\x6c\x27\xbb\xc9\x8f\xbe\x00\xd6\xeb\x4e\x23\x7b\xe8\x27\x1b\x75\x43\x76\xa8\x6c\x19\x9c\xbb\x8e\x0c\xdc\xe9\x05\x5f\xa1\xec\x5c\x98\x02\x64\x8b\x62\x78\x01\x0d\x7c\xee\x78\xce\xdd\x51\x23\xd8\x2f\x0f\x22\x53\x18\x47\xbe\x76\xa0\xbb\xec\xb0\xc3\x5f\xc2\x75\xd6\x89\xde\x09\x5a\x2b\x29\x64\xa7\x2d\x75\x52\xd4\x9a\x8b\xe5\xe8\xbb\x15\xe8\x93\xd1\xbf\xdf\x74\x1f\x7a\xb7\x2a\x51\x59\xf2\xb5\xdc\x81\x4a\x1f\x52\x29\xb4\xe5\xf3\x81\x88\x37\x76\x80\x2e\xdd\x85\x25\x29\x31\x7d\x66\xb4\x21\xca\x74\xed\x08\xac\xfc\x6d\x2f\x38\x85\x3e\xbc\x33\x85\xa8\xa1\x6b\xe1\x78\x7e\x03\x74\x47\x1b\xd4\x7d\xa8\xbd\x01\x3b\x8b\x6c\x08\x77\xcf\x3e\xeb\x2f\xae\xd1\xa2\x08\x86\xed\x5b\xc2\x5d\xb4\x9f\xae\xa7\x10\xd8\x40\x1f\xd8\x4f\xbb\x12\x72\xfa\x34\xe8\xd1\x9e\xfd\x86\x3a\x63\x83\x96\xd7\x36\x35\xa7\xf5\x03\x33\xc2\x00\x56\x9b\x59\x3b\x18\x0d\x97\x94\xb4\x49\x18\x6e\x17\x06\xbc\xbf\x01\x69\xa7\x8d\x5c\x0d\x46\xf6\x9d\x34\x3c\x73\x87\x1e\xb9\x70\xa0\x1d\xdb\xa7\xed\xf8\xe1\x31\xeb\x9a\x74\x50\xfc\x60\x97\x36\x76\x66\xe9\xf1\xf5\x97\x0d\xba\x91\x8d\x2b\x84\x8d\x06\xa9\x80\xb7\x74\x78\xe1\xda\x07\xad\xfd\xa4\xc4\x58\xb7\x5d\x4a\xfe\x6a\xb3\x2b\x19\xde\x5c\x9d\x4f\xa1\x36\xa6\x9d\x1e\x1e\xba\x19\xc1\x0e\x16\xd3\x22\x89\x93\x7d\x31\xdd\x0b\x7c\x49\x6c\x2c\x9c\x5a\x77\x97\x44\xcf\xed\xe7\x14\x02\x7f\xff\xef\xd9\xe1\x86\xaf\xb8\xe9\x0f\x9f\xdb\xcf\x29\xc4\x59\x10\x46\x79\xfe\x04\xa4\x46\xba\x6a\xf5\xd0\x12\x3f\x23\x33\x8a\x08\x4d\x1e\x06\x10\x1b\x03\x63\xfd\x8b\x9d\x80\x9b\xd1\x5c\xf7\xf7\xa1\x80\x51\x7c\xb9\x44\x85\xac\x87\xb4\xc1\xad\xd9\x17\xba\x87\x75\xea\x5b\x5c\xbf\x66\x58\x21\x61\x20\x45\xb3\xb3\xed\xb2\x07\xfb\xfe\xbf\x2d\xf6\x2e\xfd\x54\x7d\x85\x84\x3d\x55\x1f\x24\x83\xf6\x0b\x5b\x89\xc7\xbe\xb7\x52\x36\xb0\x22\x5b\x50\x68\x14\xef\x87\x0c\x8d\x82\x01\x79\x72\x4c\xae\x5d\x2b\xaf\xc8\xf6\xaa\x3f\x37\x85\x70\xc8\xe9\xcb\x2a\xdd\xa4\xb7\x26\x8d\xd3\xbb\xeb\x1b\x80\x58\x07\x69\xa7\x94\x7b\x32\x3f\x92\xa8\x89\x86\x12\xd1\xbe\xa9\x0d\x52\xe3\xd2\xb4\x57\x60\xed\xd9\xab\x2d\x1c\x22\x38\xe1\xda\xa1\xc5\x69\xd4\x72\xf5\x0c\x6d\x1a\x98\x7c\xfc\x20\x00\xb3\x75\x1e\x91\x96\x8f\x00\xcc\x76\x2e\x65\x33\xa3\x96\x16\x4e\x85\xd5\xc4\xa6\x60\x54\x87\xb6\xd7\x88\xd8\x01\xc3\xb2\x5b\x2e\x07\x4a\xb2\x2d\xe0\x08\x60\x29\xc1\x1a\x19\xb9\xdd\xbe\xd5\xda\x56\xc9\xca\x95\xe7\x41\xc4\x92\x9d\x5d\x9d\x42\x45\x1a\x8d\xa3\x7f\x05\x00\x00\xff\xff\x80\x6a\xa2\xe3\x78\x12\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,12 +84,12 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4724, mode: os.FileMode(420), modTime: time.Unix(1547483298, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4728, mode: os.FileMode(420), modTime: time.Unix(1547653425, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\xc9\x8e\xdc\x36\x10\xbd\xeb\x2b\x88\xca\x61\x2e\xbd\x70\x15\x97\x3f\x08\x8c\xe4\x12\x03\x3e\x17\xc9\x62\x8f\xd0\xd3\x6a\x85\xa4\x66\xdc\x30\xfc\xef\x81\xda\x3d\x99\xeb\x18\xba\x90\x4f\x6f\xa9\x92\x5e\xa2\xb9\xd7\xa9\xac\x27\xfa\x9b\xfa\xdb\xb5\x9e\x03\xeb\xd4\xfa\x34\x9f\x06\xea\xcf\x54\x69\xbd\x84\x81\x31\x4c\xe9\xba\xce\xbd\x6d\x67\xc6\x2e\x38\xcd\x81\xdd\x8f\x8c\x9d\xe9\x16\xd8\xd3\x0f\xc0\x9c\x2b\xb5\x06\x01\x9c\x8f\x1c\xdd\x68\x9c\x4a\x5a\x6b\x8d\xa9\x64\x2b\xa2\x1e\x15\xf1\xac\x92\x31\x48\x42\x0b\x89\x06\x76\x90\xea\x6d\xe9\x57\x08\x3f\x20\x4d\xcb\x33\x55\x08\x80\xd4\xf6\x42\xba\x7d\xea\x75\x23\xdc\xe1\x4e\xdf\x3b\x04\x48\xd6\xfa\xe2\x94\xf5\xd9\x5a\x9e\xbd\x4c\x25\x89\x9c\xb3\x46\x57\x94\xc8\x06\x39\xe6\xe4\x8a\x44\x1e\x25\x0a\xcd\x85\xb2\x3c\xab\x51\xf1\xa2\x5c\xe2\xc9\xe1\xff\x7e\x0b\x56\xbc\xb4\x2d\x76\x7a\x85\x00\x6a\x4c\x62\x74\x64\x55\x2c\xde\xf1\x42\xd6\x44\x6e\xa5\x2d\xce\x73\xb4\x02\x33\xfc\xdc\xc1\x39\x17\x08\xd0\xee\x03\xc3\xfd\xfa\x61\x92\xcf\x2f\x34\x43\x50\x72\x07\x33\x04\x39\x4a\xa1\xf5\x0e\x16\x08\x62\x07\x15\x82\xdb\x41\xc3\x97\x6d\x81\x4c\x22\x92\x18\x49\x25\xef\x84\xd7\x3a\x0b\x4a\x28\xa3\x8b\xd2\x92\xa6\x91\x78\x34\xb1\x44\xad\x22\x71\x65\x47\x34\xd9\x39\xe7\x0b\x8e\xd6\xa3\x74\x42\xca\x6d\x90\x0b\xa6\xed\x53\x24\x21\x5d\x74\xc2\x18\x63\x22\x0a\xc2\x6c\x13\x92\xe7\x23\x27\xe7\xb4\xc4\x92\xd0\x29\x33\x66\x3e\x6a\x63\x62\xf6\x68\xac\x91\x11\xc7\x92\x12\xf7\x92\xca\xe6\x34\x65\x08\xa0\x0d\xf1\x91\xe3\xb8\xcf\x12\x69\xaf\x55\x74\x7b\x2f\x65\xd9\x6b\xed\xa4\xd7\xde\x67\x65\x33\xec\xe0\x95\x6a\x9b\xae\xdb\x92\x3f\x9f\x1e\x3f\x7e\xc1\xd6\xde\xae\x35\x07\xf6\xf4\x0e\x3d\x3a\x10\xd8\x67\x2b\x30\x0c\x53\xa6\xb9\x4f\xfd\xf6\x67\x0e\x0c\xf8\x77\x2e\x3e\x1e\x18\x86\x3f\xd8\x57\x9a\x71\xee\x5b\xcb\x58\xeb\xd7\x8a\x27\x1a\xfa\x1d\xba\x77\xf1\x4c\xb7\x0d\xa5\xc0\x8e\xfd\xb2\x1c\x1f\x6f\x86\xe1\xdf\x95\x56\xda\x08\xf3\x7a\xf9\x76\xad\x67\xaa\x2d\x30\x39\x30\xf6\x76\xbf\x7c\xc3\xa9\x7f\x9d\x2e\xf4\xd7\x3f\x81\x89\x61\xd8\x5c\x36\x72\x9b\x4e\xf3\x34\x9f\x7e\x95\x7c\x59\xe3\xcb\x94\xbe\x6c\xed\x3e\x1c\x8e\x87\xc3\x31\xae\xd3\x4b\x3e\x56\x6a\xd7\xb5\x26\x6a\xc7\x07\xfb\x0b\xdd\x0e\xcb\x1a\x0f\x0b\x5d\x7e\xe9\xea\xf4\x8a\x9d\x3e\x27\x3c\x6f\xe2\xbb\x90\xfa\x33\xae\xfd\xf9\x93\xd9\x0f\xf6\x6f\x06\xbf\xab\xde\x53\xff\x0b\x00\x00\xff\xff\x35\xa4\xa3\x67\xfd\x03\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\x3b\x6f\xe4\x36\x10\xee\xf5\x2b\x88\x49\xe1\x66\x1f\x7c\x8a\x8f\x2e\x65\x70\x48\x9a\x04\xb8\x7a\x48\x0e\xd7\xc2\x7a\xb5\x0a\x49\xd9\xb7\x38\xdc\x7f\x0f\xb4\xb7\x8e\x53\x3a\x50\x33\x33\xfa\x1e\x33\xd2\x97\x68\xee\x75\x2a\xeb\x89\xfe\xa0\xfe\x76\xad\xe7\xc0\x3a\xb5\x3e\xcd\xa7\x81\xfa\x33\x55\x5a\x2f\x61\x60\x0c\x53\xba\xae\x73\x6f\x5b\xcd\xd8\x05\xa7\x39\xb0\x7b\xc9\xd8\x99\x6e\x81\x3d\x7d\x07\xcc\xb9\x52\x6b\x10\xc0\xf9\xc8\xd1\x8d\xc6\xa9\xa4\xb5\xd6\x98\x4a\xb6\x22\xea\x51\x11\xcf\x2a\x19\x83\x24\xb4\x90\x68\x60\x07\xa9\xde\x96\x7e\x85\xf0\x1d\xd2\xb4\x3c\x53\x85\x00\x48\x6d\x2f\xa4\xdb\xa7\x5e\x37\xc0\x7d\xdc\xe9\x5b\x87\x00\xc9\x5a\x5f\x9c\xb2\x3e\x5b\xcb\xb3\x97\xa9\x24\x91\x73\xd6\xe8\x8a\x12\xd9\x20\xc7\x9c\x5c\x91\xc8\xa3\x44\xa1\xb9\x50\x96\x67\x35\x2a\x5e\x94\x4b\x3c\x39\xfc\x57\x6f\xc1\x8a\x97\xb6\xd9\x4e\xaf\x10\x40\x8d\x49\x8c\x8e\xac\x8a\xc5\x3b\x5e\xc8\x9a\xc8\xad\xb4\xc5\x79\x8e\x56\x60\x86\x1f\x3b\x38\xe7\x02\x01\xda\x7d\x61\xb8\xb7\x1f\x22\xf9\xfc\x42\x33\x04\x25\x77\x30\x43\x90\xa3\x14\x5a\xef\x60\x81\x20\x76\x50\x21\xb8\x1d\x34\x7c\xd9\x0e\xc8\x24\x22\x89\x91\x54\xf2\x4e\x78\xad\xb3\xa0\x84\x32\xba\x28\x2d\x69\x1a\x89\x47\x13\x4b\xd4\x2a\x12\x57\x76\x44\x93\x9d\x73\xbe\xe0\x68\x3d\x4a\x27\xa4\xdc\x16\xb9\x60\xda\x3e\x45\x12\xd2\x45\x27\x8c\x31\x26\xa2\x20\xcc\x36\x21\x79\x3e\x72\x72\x4e\x4b\x2c\x09\x9d\x32\x63\xe6\xa3\x36\x26\x66\x8f\xc6\x1a\x19\x71\x2c\x29\x71\x2f\xa9\x6c\x4a\x53\x86\x00\xda\x10\x1f\x39\x8e\xfb\x2c\x91\xf6\x5a\x45\xb7\xf7\x52\x96\xbd\xd6\x4e\x7a\xed\x7d\x56\x36\xc3\x0e\x5e\xa9\xb6\xe9\xba\x1d\xf9\xe3\xe9\xf1\xe3\x17\x6c\xed\xed\x5a\x73\x60\x4f\xef\xa3\x47\x06\x02\xfb\x6c\x04\x86\x61\xca\x34\xf7\xa9\xdf\x7e\xcb\x81\x01\xff\xc6\xc5\xc7\x03\xc3\xf0\x0b\xfb\xf5\x91\xbc\x2d\x67\xac\xf5\x6b\xc5\x13\x0d\xff\x8d\xe3\x99\x6e\xdb\x98\x02\x3b\xf6\xcb\x72\x7c\x7f\x35\x0c\x7f\xaf\xb4\xd2\x86\x98\xd7\xcb\xd7\x6b\x3d\x53\x6d\x81\xc9\x81\xb1\xb7\x7b\xf3\x15\xa7\xfe\xd7\x74\xa1\xdf\xff\x0c\x4c\x0c\xc3\x26\xb3\x81\xdb\x74\x9a\xa7\xf9\xf4\x33\xe8\xcb\x1a\x5f\xa6\xf4\x65\x4b\xf8\xe1\x70\x3c\x1c\x8e\x71\x9d\x5e\xf2\xb1\x52\xbb\xae\x35\x51\x3b\x3e\xd0\x5f\xe8\x76\x58\xd6\x78\x58\xe8\xf2\x93\x57\xa7\x57\xec\xf4\x39\xe2\x79\x23\xdf\x89\xd4\x9f\x71\xed\xcf\x9f\xf4\x7e\xa0\xff\xa7\xf1\x3b\xeb\xdd\xf5\x9f\x00\x00\x00\xff\xff\x6a\x9a\xa9\xc9\x01\x04\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1021, mode: os.FileMode(420), modTime: time.Unix(1547483298, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547653425, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testingutils/config/config.go b/testingutils/config/config.go index b05be2df6..e09d49fb8 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -167,7 +167,7 @@ func CreateTenantContext(t *testing.T, cfg config.Configuration) context.Context } func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg config.Configuration) context.Context { - tc, err := configstore.NewTenantConfig("", cfg) + tc, err := configstore.NewAccount("", cfg) assert.Nil(t, err) contextHeader, err := contextutil.NewCentrifugeContext(ctx, tc) @@ -176,9 +176,9 @@ func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg confi } func HandlerContext(service config.Service) context.Context { - tcs, _ := service.GetAllTenants() + tcs, _ := service.GetAllAccounts() cid, _ := tcs[0].GetIdentityID() cidHex := hexutil.Encode(cid) - ctx := context.WithValue(context.Background(), config.TenantKey, cidHex) + ctx := context.WithValue(context.Background(), config.AccountHeaderKey, cidHex) return ctx } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 213b70daf..98de0c17b 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -46,7 +46,7 @@ func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service return idConfig.ID } -func CreateTenantIDWithKeys(contextTimeout time.Duration, cfg *configstore.TenantConfig, idService identity.Service) identity.Identity { +func CreateTenantIDWithKeys(contextTimeout time.Duration, cfg *configstore.Account, idService identity.Service) identity.Identity { ctxh, _ := contextutil.NewCentrifugeContext(context.Background(), cfg) idConfig, _ := identity.GetIdentityConfig(cfg) // only create identity if it doesn't exist diff --git a/transactions/handler.go b/transactions/handler.go index 3442f1d9d..6cd9c2f9f 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -44,7 +44,7 @@ func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactions return nil, ErrInvalidTransactionID } - tc, err := contextutil.Tenant(ctxHeader) + tc, err := contextutil.Account(ctxHeader) if err != nil { return nil, ErrInvalidTenantID } diff --git a/transactions/handler_test.go b/transactions/handler_test.go index dd477cedb..18f6723b2 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -36,7 +36,7 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { assert.True(t, errors.IsOfType(ErrInvalidTransactionID, err)) // missing err - tcs, _ := cService.GetAllTenants() + tcs, _ := cService.GetAllAccounts() tid, _ := tcs[0].GetIdentityID() cid, err := identity.ToCentID(tid) tx := NewTransaction(cid, "") From 7e71bc3d0d8fffde6f0e8f8e865fe835a6926086 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 17 Jan 2019 15:19:59 +0100 Subject: [PATCH 144/220] pump metis version (#657) --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index e171338ef..40cab286e 100644 --- a/version/version.go +++ b/version/version.go @@ -10,7 +10,7 @@ import ( var gitCommit = "master" // CentrifugeNodeVersion is the current version of the app -const CentrifugeNodeVersion = "0.0.1-alpha" +const CentrifugeNodeVersion = "0.0.3-alpha1" // GetVersion returns current cent node version in semvar format. func GetVersion() *semver.Version { From 50fe8d68610ebff8a3915c0d52de5af7d1b8aa32 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 17 Jan 2019 15:34:23 +0100 Subject: [PATCH 145/220] removing confirmation transaction task (#658) * added testworld tests for proofs * added transaction status task * added protobuf header transaction. * removed nft confirm task * implemented getTransactionStatus * formatting * formatting * removed testoutput * formatting * added swagger * added integration tests for transaction task * formatting * formatting * removed mock eth client from identity package * simplified integration tests * changed nft register transactionTask * fixed broken unit test in api package * removing confirmation task --- nft/minting_confirmation_task.go | 170 -------------------------- nft/minting_confirmation_task_test.go | 77 ------------ 2 files changed, 247 deletions(-) delete mode 100644 nft/minting_confirmation_task.go delete mode 100644 nft/minting_confirmation_task_test.go diff --git a/nft/minting_confirmation_task.go b/nft/minting_confirmation_task.go deleted file mode 100644 index 21e868232..000000000 --- a/nft/minting_confirmation_task.go +++ /dev/null @@ -1,170 +0,0 @@ -package nft - -import ( - "context" - "time" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -const ( - mintingConfirmationTaskName string = "MintingConfirmationTaskName" - tokenIDParam string = "TokenIDParam" - registryAddressParam string = "RegistryAddressParam" - tenantIDParam string = "Tenant ID" -) - -// paymentObligationMintedFilterer filters the approved NFTs -type paymentObligationMintedFilterer interface { - - // FilterPaymentObligationMinted filters PaymentObligationMinted events - FilterPaymentObligationMinted(opts *bind.FilterOpts) (*EthereumPaymentObligationContractPaymentObligationMintedIterator, error) -} - -// mintingConfirmationTask confirms the minting of a payment obligation NFT -type mintingConfirmationTask struct { - transactions.BaseTask - - //task parameter - tenantID identity.CentID - tokenID string - blockHeight uint64 - registryAddress string - timeout time.Duration - - //state - ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) -} - -func newMintingConfirmationTask( - timeout time.Duration, - ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), - txService transactions.Service, -) *mintingConfirmationTask { - return &mintingConfirmationTask{ - timeout: timeout, - ethContextInitializer: ethContextInitializer, - BaseTask: transactions.BaseTask{TxService: txService}, - } -} - -// TaskTypeName returns mintingConfirmationTaskName -func (nftc *mintingConfirmationTask) TaskTypeName() string { - return mintingConfirmationTaskName -} - -// Copy returns a new instance of mintingConfirmationTask -func (nftc *mintingConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &mintingConfirmationTask{ - timeout: nftc.timeout, - ethContextInitializer: nftc.ethContextInitializer, - BaseTask: transactions.BaseTask{TxService: nftc.TxService}, - }, nil -} - -// ParseKwargs - define a method to parse CentID -func (nftc *mintingConfirmationTask) ParseKwargs(kwargs map[string]interface{}) (err error) { - err = nftc.ParseTransactionID(kwargs) - if err != nil { - return err - } - - tenantID, ok := kwargs[tenantIDParam].(string) - if !ok { - return errors.New("missing tenant ID") - } - - nftc.tenantID, err = identity.CentIDFromString(tenantID) - if err != nil { - return err - } - - // parse TokenID - tokenID, ok := kwargs[tokenIDParam] - if !ok { - return errors.New("undefined kwarg " + tokenIDParam) - } - nftc.tokenID, ok = tokenID.(string) - if !ok { - return errors.New("malformed kwarg [%s]", tokenIDParam) - } - - // parse blockHeight - nftc.blockHeight, err = queue.ParseBlockHeight(kwargs) - if err != nil { - return err - } - - //parse registryAddress - registryAddress, ok := kwargs[registryAddressParam] - if !ok { - return errors.New("undefined kwarg " + registryAddressParam) - } - - nftc.registryAddress, ok = registryAddress.(string) - if !ok { - return errors.New("malformed kwarg [%s]", registryAddressParam) - } - - // override TimeoutParam if provided - tdRaw, ok := kwargs[queue.TimeoutParam] - if ok { - td, err := queue.GetDuration(tdRaw) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) - } - nftc.timeout = td - } - - return nil -} - -// RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. -func (nftc *mintingConfirmationTask) RunTask() (resp interface{}, err error) { - log.Infof("Waiting for confirmation for the minting of token [%x]", nftc.tokenID) - - ethContext, cancelF := nftc.ethContextInitializer(nftc.timeout) - defer cancelF() - fOpts := &bind.FilterOpts{ - Context: ethContext, - Start: nftc.blockHeight, - } - - defer func() { - err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) - }() - - var filter paymentObligationMintedFilterer - filter, err = bindContract(common.HexToAddress(nftc.registryAddress), ethereum.GetClient()) - if err != nil { - return nil, err - } - - for { - iter, err := filter.FilterPaymentObligationMinted(fOpts) - if err != nil { - return nil, centerrors.Wrap(err, "failed to start filtering token minted logs") - } - - err = utils.LookForEvent(iter) - if err == nil { - log.Infof("Received filtered event NFT minted for token [%s] \n", nftc.tokenID) - return iter.Event, nil - } - - if err != utils.ErrEventNotFound { - return nil, err - } - time.Sleep(100 * time.Millisecond) - } -} diff --git a/nft/minting_confirmation_task_test.go b/nft/minting_confirmation_task_test.go deleted file mode 100644 index cd740b4e5..000000000 --- a/nft/minting_confirmation_task_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// +build unit - -package nft - -import ( - "encoding/hex" - "testing" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" - "github.com/stretchr/testify/assert" -) - -func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { - task := mintingConfirmationTask{} - tokenId := hex.EncodeToString(utils.RandomSlice(256)) - blockHeight := uint64(12) - registryAddress := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" - txID := uuid.Must(uuid.NewV4()).String() - cid := identity.RandomCentID() - - kwargs := map[string]interface{}{ - transactions.TxIDParam: txID, - tenantIDParam: cid.String(), - tokenIDParam: tokenId, - queue.BlockHeightParam: blockHeight, - registryAddressParam: registryAddress, - } - - decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) - assert.Nil(t, err, "json decode should not thrown an error") - err = task.ParseKwargs(decoded) - assert.Nil(t, err, "parsing should be successful") - - assert.Equal(t, cid, task.tenantID) - assert.Equal(t, txID, task.TxID.String()) - assert.Equal(t, tokenId, task.tokenID, "tokenId should be parsed correctly") - assert.Equal(t, blockHeight, task.blockHeight, "blockHeight should be parsed correctly") - assert.Equal(t, registryAddress, task.registryAddress, "registryAddress should be parsed correctly") - -} - -func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { - task := mintingConfirmationTask{} - tests := []map[string]interface{}{ - { - queue.BlockHeightParam: uint64(12), - registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", - }, - { - tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), - registryAddressParam: "0xf72855759a39fb75fc7341139f5d7a3974d4da08", - }, - { - tokenIDParam: hex.EncodeToString(utils.RandomSlice(256)), - queue.BlockHeightParam: uint64(12), - }, - { - //empty map - - }, - { - "dummy": "dummy", - }, - } - - for i, test := range tests { - decoded, err := utils.SimulateJSONDecodeForGocelery(test) - assert.Nil(t, err, "json decode should not thrown an error") - err = task.ParseKwargs(decoded) - assert.Error(t, err, "test case %v: parsing should fail", i) - } -} From 6c6a7ecbaca8462a37944dd09a4e25fa0f66f97f Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 17 Jan 2019 15:55:37 +0100 Subject: [PATCH 146/220] transactionStatusTask: added submitTransaction to ethereum package (#661) * created submitTransaction method * create transactionTask queuing in ethereum package * modified mock clients * moved register transaction task into ethereum package --- bootstrap/bootstrappers/bootstrapper.go | 4 +- .../testingbootstrap/testing_bootstrap.go | 2 +- ethereum/bootstrapper.go | 32 ++++++++++++- ethereum/geth_client.go | 45 ++++++++++++++++++- ethereum/geth_client_integration_test.go | 4 +- nft/bootstrapper.go | 12 ----- nft/ethereum_payment_obligation.go | 37 ++++----------- nft/ethereum_payment_obligation_test.go | 10 ++--- testingutils/commons/mock_ethclient.go | 9 ++++ 9 files changed, 101 insertions(+), 54 deletions(-) diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 87c6a355e..3e00f979e 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -37,8 +37,8 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, - ethereum.Bootstrapper{}, &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, &anchors.Bootstrapper{}, @@ -61,8 +61,8 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, - ethereum.Bootstrapper{}, &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, &anchors.Bootstrapper{}, ðid.Bootstrapper{}, } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 6f6db8c6f..f8efc429b 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -31,8 +31,8 @@ var bootstappers = []bootstrap.TestBootstrapper{ &config.Bootstrapper{}, &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, - ethereum.Bootstrapper{}, &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 0f817f8ed..7ce5dcbf8 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -1,6 +1,13 @@ package ethereum -import "github.com/centrifuge/go-centrifuge/config/configstore" +import ( + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" +) // BootstrappedEthereumClient is a key to mapped client in bootstrap context. const BootstrappedEthereumClient string = "BootstrappedEthereumClient" @@ -14,11 +21,32 @@ func (Bootstrapper) Bootstrap(context map[string]interface{}) error { if err != nil { return err } - client, err := NewGethClient(cfg) + + txService, ok := context[transactions.BootstrappedService].(transactions.Service) + if !ok { + return errors.New("transactions repository not initialised") + } + + if _, ok := context[bootstrap.BootstrappedQueueServer]; !ok { + return errors.New("queue hasn't been initialized") + } + queueSrv := context[bootstrap.BootstrappedQueueServer].(*queue.Server) + + client, err := NewGethClient(cfg, txService, queueSrv) if err != nil { return err } SetClient(client) + + registerTransactionStatusTask(cfg, client, queueSrv, txService) + context[BootstrappedEthereumClient] = client return nil } + +func registerTransactionStatusTask(cfg config.Configuration, client Client, queueSrv *queue.Server, txService transactions.Service) { + // queue task + ethTransTask := NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, client.TransactionByHash, client.TransactionReceipt, DefaultWaitForTransactionMiningContext) + + queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) +} diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index b4cb507ed..be4c7c4e2 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -11,6 +11,10 @@ import ( "sync" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -19,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" logging "github.com/ipfs/go-log" + "github.com/satori/go.uuid" ) const ( @@ -77,6 +82,9 @@ type Client interface { // TransactionReceipt return receipt of a transaction TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) + + // SubmitTransaction creates an Ethereum transactions with retries + SubmitTransaction(tendantID identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) } // gethClient implements Client for Ethereum @@ -87,13 +95,15 @@ type gethClient struct { accounts map[string]*bind.TransactOpts accMu sync.Mutex // accMu to protect accounts config Config + txService transactions.Service + queue *queue.Server // txMu to ensure one transaction at a time per client txMu sync.Mutex } // NewGethClient returns an gethClient which implements Client -func NewGethClient(config Config) (Client, error) { +func NewGethClient(config Config, transService transactions.Service, queue *queue.Server) (Client, error) { log.Info("Opening connection to Ethereum:", config.GetEthereumNodeURL()) u, err := url.Parse(config.GetEthereumNodeURL()) if err != nil { @@ -113,6 +123,8 @@ func NewGethClient(config Config) (Client, error) { txMu: sync.Mutex{}, accMu: sync.Mutex{}, config: config, + txService: transService, + queue: queue, }, nil } @@ -194,6 +206,37 @@ func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, err return opts, nil } +func (gc *gethClient) queueTaskTransactionStatus(tenantID identity.CentID, txHash string) (txID uuid.UUID, err error) { + tx, err := gc.txService.CreateTransaction(tenantID, "polling Ethereum transaction status") + if err != nil { + return txID, err + } + _, err = gc.queue.EnqueueJob(TransactionStatusTaskName, map[string]interface{}{ + transactions.TxIDParam: tx.ID.String(), + TransactionAccountParam: tenantID.String(), + TransactionTxHashParam: txHash, + }) + + return tx.ID, err +} + +// SubmitTransaction creates an Ethereum transactions with retries +func (gc *gethClient) SubmitTransaction(account identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) { + tx, err := gc.SubmitTransactionWithRetries(contractMethod, opts, params...) + if err != nil { + return nil, nil, errors.New("Submit Ethereum transaction failed: %v", err) + } + + txHash := tx.Hash() + txID, err := gc.queueTaskTransactionStatus(account, txHash.String()) + + if err != nil { + return nil, nil, errors.New("Failed to generated a queue task to poll the Ethereum transaction status: %v", err) + } + return &txID, tx, nil + +} + /** SubmitTransactionWithRetries submits transaction to the ethereum chain Blocking Function that sends transaction using reflection wrapped in a retrial block. It is based on the transactionUnderpriced error, diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 0ce695429..faef377f2 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -57,8 +57,8 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, transactions.Bootstrapper{}, - ethereum.Bootstrapper{}, &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, } @@ -93,7 +93,7 @@ func TestGetConnection_returnsSameConnection(t *testing.T) { } func TestNewGethClient(t *testing.T) { - gc, err := ethereum.NewGethClient(cfg) + gc, err := ethereum.NewGethClient(cfg, nil, nil) assert.Nil(t, err) assert.NotNil(t, gc) } diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index e4c4ccc25..4881995d0 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -5,7 +5,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/transactions" @@ -24,11 +23,6 @@ type Bootstrapper struct{} // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(true, ctx) - if err != nil { - return err - } - if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -74,11 +68,5 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return h.Number.Uint64(), nil }) - - // queue task - ethereumClient := ethereum.GetClient() - ethTransTask := ethereum.NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, ethereumClient.TransactionByHash, ethereumClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) - - queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) return nil } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index b06c6a930..9cc31a1ba 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -136,51 +136,30 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, err } - txHash, err := s.sendMintTransaction(contract, opts, requestData) + txID, _, err := s.sendMintTransaction(cid, contract, opts, requestData) if err != nil { return nil, errors.New("failed to send transaction: %v", err) } - txID, err := s.queueTaskTransaction(cid, txHash) - - if err != nil { - return nil, err - } - return &MintNFTResponse{ TransactionID: txID.String(), TokenID: requestData.TokenID.String(), }, nil } -func (s *ethereumPaymentObligation) queueTaskTransaction(tenantID identity.CentID, txHash string) (txID uuid.UUID, err error) { - tx, err := s.txService.CreateTransaction(tenantID, "Mint NFT") - if err != nil { - return txID, err - } - _, err = s.queue.EnqueueJobWithMaxTries(ethereum.TransactionStatusTaskName, map[string]interface{}{ - transactions.TxIDParam: tx.ID.String(), - ethereum.TransactionAccountParam: tenantID.String(), - ethereum.TransactionTxHashParam: txHash, - }) - - return tx.ID, err -} - // sendMintTransaction sends the actual transaction to mint the NFT -func (s *ethereumPaymentObligation) sendMintTransaction(contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (string, error) { - tx, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, +func (s *ethereumPaymentObligation) sendMintTransaction(cid identity.CentID, contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (*uuid.UUID, *types.Transaction, error) { + tx, ethTx, err := s.ethClient.SubmitTransaction(cid, contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) + if err != nil { - return "", err + return nil, nil, err } - txHash := tx.Hash() - log.Infof("Sent off tx to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", - requestData.TokenID, requestData.AnchorID, requestData.To, tx.Hash(), tx.Nonce(), tx.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return txHash.String(), nil + requestData.TokenID, requestData.AnchorID, requestData.To, ethTx.Hash(), ethTx.Nonce(), ethTx.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", ethTx.Hash()) + return tx, ethTx, nil } // MintRequest holds the data needed to mint and NFT from a Centrifuge document diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 93d8ff2ff..ac7166c63 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/satori/go.uuid" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/identity" @@ -24,7 +26,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -160,11 +161,11 @@ func TestPaymentObligationService(t *testing.T) { idServiceMock := testingcommons.MockIDService{} ethClientMock := testingcommons.MockEthClient{} ethClientMock.On("GetTxOpts", "ethacc").Return(&bind.TransactOpts{}, nil) - ethClientMock.On("SubmitTransactionWithRetries", + ethClientMock.On("SubmitTransaction", + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, - ).Return(&types.Transaction{}, nil) + ).Return(&uuid.UUID{}, &types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") cid := identity.RandomCentID() @@ -175,7 +176,6 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) - queueSrv.On("EnqueueJobWithMaxTries", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv }, &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index 84302c14d..b9eb3bd41 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -5,6 +5,9 @@ package testingcommons import ( "net/url" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/satori/go.uuid" + "github.com/ethereum/go-ethereum/common" "context" @@ -55,3 +58,9 @@ func (m *MockEthClient) TransactionReceipt(ctx context.Context, txHash common.Ha args := m.Called(ctx, txHash) return args.Get(0).(*types.Receipt), args.Error(1) } + +// SubmitTransaction creates an Ethereum transactions with retries +func (m *MockEthClient) SubmitTransaction(tendantID identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) { + args := m.Called(tendantID, contractMethod, opts, params) + return args.Get(0).(*uuid.UUID), args.Get(1).(*types.Transaction), args.Error(2) +} From 110be9228dd3614ddae8f5d1cc7e2a5c9e69a5e9 Mon Sep 17 00:00:00 2001 From: Charly Date: Thu, 17 Jan 2019 16:21:02 +0100 Subject: [PATCH 147/220] support getting core documents (#652) * update MessageTypes to include GetAnchoredDocument type * added generic service to Handler struct * changed naming on messagetypes * updated centrifuge-protobuf package to latest version * implementation for GetDocument method * resolve MessageType for GetDocument methods from string * removed irrelevant senderID * added genericService to p2p bootstrapper --- api/server_test.go | 2 +- bootstrap/bootstrappers/bootstrapper.go | 2 +- .../testingbootstrap/testing_bootstrap.go | 2 +- documents/purchaseorder/model_test.go | 2 +- p2p/bootstrapper.go | 8 ++- p2p/bootstrapper_test.go | 11 ++-- p2p/common/protocol.go | 8 +++ p2p/receiver/handler.go | 51 +++++++++++++++-- p2p/receiver/handler_integration_test.go | 55 ++++++++++++++++++- p2p/receiver/handler_test.go | 9 +-- p2p/server_test.go | 12 ++-- 11 files changed, 138 insertions(+), 24 deletions(-) diff --git a/api/server_test.go b/api/server_test.go index b05cb1b50..3f6fdf32a 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -52,8 +52,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, &genericdoc.Bootstrapper{}, + p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, ðereum.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 3e00f979e..4b43a28ed 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -43,9 +43,9 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &configstore.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, + &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, - &genericdoc.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, coredocument.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index f8efc429b..a9b6ab275 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -37,8 +37,8 @@ var bootstappers = []bootstrap.TestBootstrapper{ &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, &genericdoc.Bootstrapper{}, + p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, coredocument.Bootstrapper{}, diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 7f9d5430e..869eff2e2 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -60,8 +60,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, &genericdoc.Bootstrapper{}, + p2p.Bootstrapper{}, &Bootstrapper{}, &queue.Starter{}, } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 14821afcc..0d58f5175 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -5,6 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -35,8 +36,13 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("identity service not initialised") } + genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + if !ok { + return errors.New("generic service is not initialised") + } + srv := &peer{config: cfgService, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService)) + return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), genService) }} ctx[bootstrap.BootstrappedP2PServer] = srv ctx[bootstrap.BootstrappedP2PClient] = srv diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 3a714ab0c..43c6a40b8 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,16 +5,15 @@ package p2p import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" - - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/node" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/stretchr/testify/assert" ) @@ -35,6 +34,8 @@ func TestBootstrapper_Bootstrap(t *testing.T) { m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() ids := new(testingcommons.MockIDService) m[identity.BootstrappedIDService] = ids + m[genericdoc.BootstrappedGenService] = genericdoc.DefaultService(nil, nil, nil) + err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go index 1d7c8a997..22bc044dd 100644 --- a/p2p/common/protocol.go +++ b/p2p/common/protocol.go @@ -34,6 +34,10 @@ const ( MessageTypeSendAnchoredDoc MessageType = "MessageTypeSendAnchoredDoc" // MessageTypeSendAnchoredDocRep defines SendAnchored response type MessageTypeSendAnchoredDocRep MessageType = "MessageTypeSendAnchoredDocRep" + //MessageTypeGetDoc defines GetAnchoredDoc type + MessageTypeGetDoc MessageType = "MessageTypeGetDoc" + //MessageTypeGetDocRep defines GetAnchoredDoc response type + MessageTypeGetDocRep MessageType = "MessageTypeGetDocRep" ) // Equals compares if string is of a particular MessageType @@ -61,6 +65,10 @@ func MessageTypeFromString(mt string) MessageType { found = MessageTypeSendAnchoredDoc } else if MessageTypeSendAnchoredDocRep.Equals(mt) { found = MessageTypeSendAnchoredDocRep + } else if MessageTypeGetDoc.Equals(mt) { + found = MessageTypeGetDoc + } else if MessageTypeGetDocRep.Equals(mt) { + found = MessageTypeGetDocRep } return found } diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index f1298492a..b31b42fd3 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -3,9 +3,9 @@ package receiver import ( "context" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/contextutil" @@ -52,11 +52,12 @@ type Handler struct { registry *documents.ServiceRegistry config config.Service handshakeValidator ValidatorGroup + genericService genericdoc.Service } // New returns an implementation of P2PServiceServer -func New(config config.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup) *Handler { - return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator} +func New(config config.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup, genericService genericdoc.Service) *Handler { + return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator, genericService: genericService} } // HandleInterceptor acts as main entry point for all message types, routes the request to the correct handler @@ -99,6 +100,8 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return srv.HandleRequestDocumentSignature(ctx, peer, protoc, envelope) case p2pcommon.MessageTypeSendAnchoredDoc: return srv.HandleSendAnchoredDocument(ctx, peer, protoc, envelope) + case p2pcommon.MessageTypeGetDoc: + return srv.HandleGetDocument(ctx, peer, protoc, envelope) default: return convertToErrorEnvelop(errors.New("MessageType [%s] not found", envelope.Header.Type)) } @@ -190,6 +193,46 @@ func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.Anch return &p2ppb.AnchorDocumentResponse{Accepted: true}, nil } +// HandleGetDocument handles HandleGetDocument message +func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc protocol.ID, msg *p2ppb.Envelope) (*pb.P2PEnvelope, error) { + m := new(p2ppb.GetDocumentRequest) + err := proto.Unmarshal(msg.Body, m) + if err != nil { + return convertToErrorEnvelop(err) + } + + res, err := srv.GetDocument(ctx, m) + if err != nil { + return convertToErrorEnvelop(err) + } + + nc, err := srv.config.GetConfig() + if err != nil { + return convertToErrorEnvelop(err) + } + + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeGetDocRep, res) + if err != nil { + return convertToErrorEnvelop(err) + } + + return p2pEnv, nil +} + +// GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository +func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest) (*p2ppb.GetDocumentResponse, error) { + model, err := srv.genericService.GetCurrentVersion(ctx, docReq.DocumentIdentifier) + if err != nil { + return nil, err + } + doc, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + return &p2ppb.GetDocumentResponse{Document: doc}, nil +} + func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { errPb, ok := err.(proto.Message) if !ok { diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 4fb1d6544..df70f08a1 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,6 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/contextutil" cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/golang/protobuf/proto" @@ -57,13 +58,61 @@ func TestMain(m *testing.M) { registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService)) + genService := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), genService) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) } +func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { + b := utils.RandomSlice(32) + req := &p2ppb.GetDocumentRequest{DocumentIdentifier: b} + resp, err := handler.GetDocument(context.Background(), req) + assert.Error(t, err, "must return error") + assert.Nil(t, resp, "must be nil") +} + +func TestHandler_GetDocumentSucceeds(t *testing.T) { + ctxh := testingconfig.CreateTenantContext(t, cfg) + centrifugeId := createIdentity(t) + + doc := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(doc) + resp, err := handler.RequestDocumentSignature(ctxh, req) + assert.Nil(t, err) + assert.NotNil(t, resp) + + // Add signature received + doc.Signatures = append(doc.Signatures, resp.Signature) + tree, _ := coredocument.GetDocumentRootTree(doc) + doc.DocumentRoot = tree.RootHash() + + // Anchor document + idConfig, err := identity.GetIdentityConfig(cfg) + anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) + docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) + messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) + signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + assert.Nil(t, err) + + watchCommittedAnchor := <-anchorConfirmations + assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") + + anchorReq := getAnchoredRequest(doc) + anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) + assert.Nil(t, err) + assert.NotNil(t, anchorResp, "must be non nil") + + // Retrieve document from anchor repository with document_identifier + getReq := getGetDocumentRequest(doc) + getDocResp, err := handler.GetDocument(ctxh, getReq) + assert.Nil(t, err) + assert.ObjectsAreEqual(getDocResp.Document, doc) +} + func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -305,6 +354,10 @@ func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureReque return &p2ppb.SignatureRequest{Document: doc} } +func getGetDocumentRequest(doc *coredocumentpb.CoreDocument) *p2ppb.GetDocumentRequest { + return &p2ppb.GetDocumentRequest{DocumentIdentifier: doc.DocumentIdentifier} +} + func resolveSignatureResponse(t *testing.T, p2pEnv *protocolpb.P2PEnvelope) *p2ppb.SignatureResponse { signResp := new(p2ppb.SignatureResponse) dataEnv, err := p2pcommon.ResolveDataEnvelope(p2pEnv) diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index b28310bc8..3845a1f76 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -8,14 +8,14 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/version" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/version" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-protocol" @@ -67,11 +67,12 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + genService := genericdoc.DefaultService(nil, nil, nil) mockIDService = &testingcommons.MockIDService{} _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil) - handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID(), mockIDService)) + handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID(), mockIDService), genService) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/p2p/server_test.go b/p2p/server_test.go index 4b36d2f72..ab80bed39 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,12 +10,13 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/storage/leveldb" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -31,8 +32,9 @@ import ( ) var ( - cfg config.Service - idService identity.Service + cfg config.Service + idService identity.Service + genericService genericdoc.Service ) func TestMain(m *testing.M) { @@ -64,7 +66,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { cfgMock := mockmockConfigStore(n) assert.NoError(t, err) cp2p := &peer{config: cfgMock, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgMock, nil, receiver.HandshakeValidator(n.NetworkID, idService)) + return receiver.New(cfgMock, nil, receiver.HandshakeValidator(n.NetworkID, idService), genericService) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) From d2691073c27a9543b9b7b60bc3435952d720c31a Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 17 Jan 2019 19:39:11 +0100 Subject: [PATCH 148/220] Feat/read acl nfts (#650) Fixes #590 This would add the NFT validator. --- coredocument/read_acls.go | 187 +++++++++++++++++---- coredocument/read_acls_test.go | 87 ++++++++++ crypto/sign.go | 5 +- nft/bootstrapper.go | 17 +- nft/ethereum_payment_obligation.go | 16 ++ nft/payment_obligation.go | 1 - nft/payment_obligation_integration_test.go | 21 ++- 7 files changed, 288 insertions(+), 46 deletions(-) diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index b20e0ca7b..e604635fc 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -4,15 +4,26 @@ import ( "bytes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/ethereum/go-ethereum/common" ) const ( // ErrZeroCollaborators error when no collaborators are passed ErrZeroCollaborators = errors.Error("require at least one collaborator") + + // nftByteCount is the length of combined bytes of registry and tokenID + nftByteCount = 52 ) +// TokenRegistry defines NFT retrieval functions. +type TokenRegistry interface { + // OwnerOf to retrieve owner of the tokenID + OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) +} + // initReadRules initiates the read rules for a given coredocument. // Collaborators are given Read_Sign action. // if the rules are created already, this is a no-op. @@ -41,52 +52,75 @@ func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs [] role.Collaborators = append(role.Collaborators, c[:]) } - // add the role to Roles - cd.Roles = appendRole(cd.Roles, role) + addNewRule(cd, role, coredocumentpb.Action_ACTION_READ_SIGN) +} + +// addNewRule creates a new rule as per the role and action. +func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, action coredocumentpb.Action) { + roleKey := uint32(len(cd.Roles)) + cd.Roles = append(cd.Roles, &coredocumentpb.RoleEntry{ + RoleKey: roleKey, + Role: role, + }) - // create a rule rule := new(coredocumentpb.ReadRule) - rule.Roles = append(rule.Roles, cd.Roles[len(cd.Roles)-1].RoleKey) - rule.Action = coredocumentpb.Action_ACTION_READ_SIGN + rule.Roles = append(rule.Roles, roleKey) + rule.Action = action cd.ReadRules = append(cd.ReadRules, rule) } -// appendRole appends the roles to role entry -func appendRole(roles []*coredocumentpb.RoleEntry, role *coredocumentpb.Role) []*coredocumentpb.RoleEntry { - return append(roles, &coredocumentpb.RoleEntry{ - RoleKey: uint32(len(roles)), - Role: role, - }) +// addNFTToReadRules adds NFT token to the read rules of core document. +func addNFTToReadRules(cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte) error { + nft, err := constructNFT(registry, tokenID) + if err != nil { + return errors.New("failed to construct NFT: %v", err) + } + + role := new(coredocumentpb.Role) + role.Nfts = append(role.Nfts, nft) + addNewRule(cd, role, coredocumentpb.Action_ACTION_READ) + return nil +} + +// constructNFT appends registry and tokenID to byte slice +func constructNFT(registry common.Address, tokenID []byte) ([]byte, error) { + var nft []byte + // first 20 bytes of registry + nft = append(nft, registry.Bytes()...) + + // next 32 bytes of the tokenID + nft = append(nft, tokenID...) + + if len(nft) != nftByteCount { + return nil, errors.New("byte length mismatch") + } + + return nft, nil } // ReadAccessValidator defines validator functions for peer. type ReadAccessValidator interface { PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool + NFTOwnerCanRead( + cd *coredocumentpb.CoreDocument, + registry common.Address, + tokenID []byte, + signature string, + peer identity.CentID) error } // readAccessValidator implements ReadAccessValidator. -type readAccessValidator struct{} +type readAccessValidator struct { + tokenRegistry TokenRegistry +} // PeerCanRead validate if the core document can be read by the peer. // Returns an error if not. func (r readAccessValidator) PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool { - // lets loop though read rules - for _, rule := range cd.ReadRules { - for _, rk := range rule.Roles { - role, err := getRole(rk, cd.Roles) - if err != nil { - // seems like roles and rules are not in sync - // skip to next one - continue - } - - if isPeerInRole(role, peer) { - return true - } - } - } - - return false + // loop though read rules + return findRole(cd, coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { + return isPeerInRole(role, peer) + }) } func getRole(key uint32, roles []*coredocumentpb.RoleEntry) (*coredocumentpb.Role, error) { @@ -110,7 +144,100 @@ func isPeerInRole(role *coredocumentpb.Role, peer identity.CentID) bool { return false } -// peerValidator return the +// peerValidator returns the ReadAccessValidator tp verify peer. func peerValidator() ReadAccessValidator { return readAccessValidator{} } + +// nftValidator returns the ReadAccessValidator for nft owner verification. +func nftValidator(tr TokenRegistry) ReadAccessValidator { + return readAccessValidator{tokenRegistry: tr} +} + +// NFTOwnerCanRead checks if the nft owner/peer can read the document +// Note: signature should be calculated from the hash which is calculated as +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +func (r readAccessValidator) NFTOwnerCanRead( + cd *coredocumentpb.CoreDocument, + registry common.Address, + tokenID []byte, + signature string, + peer identity.CentID) error { + + // check if the peer can read the doc + if r.PeerCanRead(cd, peer) { + return nil + } + + // check if the nft is present in read rules + found := findRole(cd, coredocumentpb.Action_ACTION_READ, func(role *coredocumentpb.Role) bool { + return isNFTInRole(role, registry, tokenID) + }) + + if !found { + return errors.New("nft missing") + } + + // get the owner of the NFT + owner, err := r.tokenRegistry.OwnerOf(registry, tokenID) + if err != nil { + return errors.New("failed to get NFT owner: %v", err) + } + + msg, err := constructNFT(registry, tokenID) + if err != nil { + return err + } + + if !secp256k1.VerifySignatureWithAddress(owner.String(), signature, msg) { + return errors.New("peer(%s) doesn't own NFT", peer.String()) + } + + return nil +} + +// findRole calls OnRole for every role, +// if onRole returns true, returns true +// else returns false +func findRole( + cd *coredocumentpb.CoreDocument, + action coredocumentpb.Action, + onRole func(role *coredocumentpb.Role) bool) bool { + for _, rule := range cd.ReadRules { + if rule.Action != action { + continue + } + + for _, rk := range rule.Roles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + + if onRole(role) { + return true + } + + } + } + + return false +} + +// isNFTInRole checks if the given nft(registry + token) is part of the core document role. +func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) bool { + enft, err := constructNFT(registry, tokenID) + if err != nil { + return false + } + + for _, n := range role.Nfts { + if bytes.Equal(n, enft) { + return true + } + } + + return false +} diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index ce9544a49..a15f3fc36 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -5,9 +5,18 @@ package coredocument import ( "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestReadACLs_initReadRules(t *testing.T) { @@ -45,3 +54,81 @@ func TestReadAccessValidator_PeerCanRead(t *testing.T) { // peer can access assert.True(t, pv.PeerCanRead(cd, peer)) } + +func Test_addNFTToReadRules(t *testing.T) { + // wrong registry or token format + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(34) + + err := addNFTToReadRules(nil, registry, tokenID) + assert.Error(t, err) + + cd, err := NewWithCollaborators([]string{"0x010203040506"}) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) + assert.Len(t, cd.Roles, 1) + + tokenID = utils.RandomSlice(32) + err = addNFTToReadRules(cd, registry, tokenID) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 2) + assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) + assert.Len(t, cd.Roles, 2) +} + +type mockRegistry struct { + mock.Mock +} + +func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { + args := m.Called(registry, tokenID) + addr, _ := args.Get(0).(common.Address) + return addr, args.Error(1) +} + +func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { + peer, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + cd, err := NewWithCollaborators([]string{peer.String()}) + assert.NoError(t, err) + + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + + // peer can read + validator := nftValidator(nil) + err = validator.NFTOwnerCanRead(cd, registry, nil, "", peer) + assert.NoError(t, err) + + // peer not in read rules and nft missing + peer, err = identity.CentIDFromString("0x010203040505") + assert.NoError(t, err) + tokenID := utils.RandomSlice(32) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, "", peer) + assert.Error(t, err) + + tr := mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() + addNFTToReadRules(cd, registry, tokenID) + validator = nftValidator(tr) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, "", peer) + assert.Error(t, err) + assert.Contains(t, err, "failed to get owner of") + tr.AssertExpectations(t) + + c := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + acc, err := c.GetEthereumAccount("main") + assert.NoError(t, err) + key, err := keystore.DecryptKey([]byte(acc.Key), "") + assert.NoError(t, err) + msg, err := constructNFT(registry, tokenID) + assert.NoError(t, err) + sig, err := secp256k1.SignEthereum(msg, key.PrivateKey.D.Bytes()) + assert.NoError(t, err) + tr = mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(key.Address, nil).Once() + validator = nftValidator(tr) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, hexutil.Encode(sig), peer) + assert.NoError(t, err) +} diff --git a/crypto/sign.go b/crypto/sign.go index 401e3ee0f..e4038e873 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -5,11 +5,10 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/utils" - "golang.org/x/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/utils" + "golang.org/x/crypto/ed25519" ) // SignMessage signs the message using the private key as the curveType provided. diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 4881995d0..6b30ba53a 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -3,20 +3,20 @@ package nft import ( "context" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" ) -// BootstrappedPayObService is the key to PaymentObligationService in bootstrap context. -const BootstrappedPayObService = "BootstrappedPayObService" +const ( + // BootstrappedPayObService is the key to PaymentObligationService in bootstrap context. + BootstrappedPayObService = "BootstrappedPayObService" +) // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} @@ -53,7 +53,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } client := ethereum.GetClient() - ctx[BootstrappedPayObService] = newEthereumPaymentObligation( + payOb := newEthereumPaymentObligation( registry, idService, client, @@ -68,5 +68,6 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return h.Number.Uint64(), nil }) + ctx[BootstrappedPayObService] = payOb return nil } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 9cc31a1ba..a407d05c2 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -30,6 +30,9 @@ type ethereumPaymentObligationContract interface { // Mint method abstracts Mint method on the contract Mint(opts *bind.TransactOpts, to common.Address, tokenID *big.Int, tokenURI string, anchorID *big.Int, merkleRoot [32]byte, values []string, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) + + // OwnerOf to retrieve owner of the tokenID + OwnerOf(opts *bind.CallOpts, tokenID *big.Int) (common.Address, error) } // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum @@ -147,6 +150,19 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by }, nil } +// OwnerOf returns the owner of the NFT token on ethereum chain +func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []byte) (owner common.Address, err error) { + contract, err := s.bindContract(registry, s.ethClient) + if err != nil { + return owner, errors.New("failed to bind the registry contract: %v", err) + } + + opts, cancF := s.ethClient.GetGethCallOpts() + defer cancF() + + return contract.OwnerOf(opts, utils.ByteSliceToBigInt(tokenID)) +} + // sendMintTransaction sends the actual transaction to mint the NFT func (s *ethereumPaymentObligation) sendMintTransaction(cid identity.CentID, contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (*uuid.UUID, *types.Transaction, error) { tx, ethTx, err := s.ethClient.SubmitTransaction(cid, contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index 165b9ea9b..6a9f93049 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -6,7 +6,6 @@ import ( // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { - // MintNFT mints an NFT MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) } diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 9271a18e8..651db220d 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,25 +3,28 @@ package nft_test import ( + "math/big" "os" "testing" "time" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/golang/protobuf/ptypes/timestamp" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -30,6 +33,7 @@ var cfg config.Configuration var idService identity.Service var payOb nft.PaymentObligation var txService transactions.Service +var tokenRegistry coredocument.TokenRegistry func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") @@ -39,6 +43,7 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txService = ctx[transactions.BootstrappedService].(transactions.Service) + tokenRegistry = ctx[nft.BootstrappedPayObService].(coredocument.TokenRegistry) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) @@ -75,13 +80,21 @@ func TestPaymentObligationService_mint(t *testing.T) { assert.Nil(t, err, "should not error out when getting invoice ID") // call mint // assert no error + depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" + registry := cfg.GetContractAddress(config.PaymentObligation).String() resp, err := payOb.MintNFT( contextHeader, ID, - cfg.GetContractAddress(config.PaymentObligation).String(), - "0xf72855759a39fb75fc7341139f5d7a3974d4da08", + registry, + depositAddr, []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, ) assert.Nil(t, err, "should not error out when minting an invoice") assert.NotNil(t, resp.TokenID, "token id should be present") + assert.NoError(t, txService.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) + b := new(big.Int) + b.SetString(resp.TokenID, 10) + owner, err := tokenRegistry.OwnerOf(common.HexToAddress(registry), b.Bytes()) + assert.NoError(t, err) + assert.Equal(t, common.HexToAddress(depositAddr), owner) } From 910aa7335fb0311d0916422455fd1ddcfe0821af Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 18 Jan 2019 11:22:46 +0100 Subject: [PATCH 149/220] remove the signature from NFT read acls (#664) As per our discussion yesterday --- coredocument/read_acls.go | 13 +++---------- coredocument/read_acls_test.go | 29 +++++++++-------------------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index e604635fc..9b364631e 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -4,7 +4,6 @@ import ( "bytes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/common" @@ -105,7 +104,6 @@ type ReadAccessValidator interface { cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte, - signature string, peer identity.CentID) error } @@ -161,7 +159,6 @@ func (r readAccessValidator) NFTOwnerCanRead( cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte, - signature string, peer identity.CentID) error { // check if the peer can read the doc @@ -184,13 +181,9 @@ func (r readAccessValidator) NFTOwnerCanRead( return errors.New("failed to get NFT owner: %v", err) } - msg, err := constructNFT(registry, tokenID) - if err != nil { - return err - } - - if !secp256k1.VerifySignatureWithAddress(owner.String(), signature, msg) { - return errors.New("peer(%s) doesn't own NFT", peer.String()) + // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address + if !bytes.Equal(owner.Bytes(), peer[:]) { + return errors.New("peer(%v) not owner of the NFT", peer.String()) } return nil diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index a15f3fc36..241d789f7 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -6,15 +6,10 @@ import ( "testing" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -98,37 +93,31 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { // peer can read validator := nftValidator(nil) - err = validator.NFTOwnerCanRead(cd, registry, nil, "", peer) + err = validator.NFTOwnerCanRead(cd, registry, nil, peer) assert.NoError(t, err) // peer not in read rules and nft missing peer, err = identity.CentIDFromString("0x010203040505") assert.NoError(t, err) tokenID := utils.RandomSlice(32) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, "", peer) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) assert.Error(t, err) tr := mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() addNFTToReadRules(cd, registry, tokenID) validator = nftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, "", peer) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) assert.Error(t, err) assert.Contains(t, err, "failed to get owner of") tr.AssertExpectations(t) - c := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - acc, err := c.GetEthereumAccount("main") - assert.NoError(t, err) - key, err := keystore.DecryptKey([]byte(acc.Key), "") - assert.NoError(t, err) - msg, err := constructNFT(registry, tokenID) - assert.NoError(t, err) - sig, err := secp256k1.SignEthereum(msg, key.PrivateKey.D.Bytes()) - assert.NoError(t, err) + // not the same owner + owner := common.BytesToAddress(utils.RandomSlice(20)) tr = mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(key.Address, nil).Once() + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() validator = nftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, hexutil.Encode(sig), peer) - assert.NoError(t, err) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) + assert.Error(t, err) + tr.AssertExpectations(t) } From 9c18c8435bb62cf7d61de10aeb279aa4782a12bd Mon Sep 17 00:00:00 2001 From: Charly Date: Fri, 18 Jan 2019 16:36:24 +0100 Subject: [PATCH 150/220] Refactor/message types to map (#662) * if else block to map --- p2p/common/protocol.go | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go index 22bc044dd..98e1df20c 100644 --- a/p2p/common/protocol.go +++ b/p2p/common/protocol.go @@ -40,6 +40,18 @@ const ( MessageTypeGetDocRep MessageType = "MessageTypeGetDocRep" ) +//MessageTypes map for MessageTypeFromString function +var messageTypes = map[string]MessageType{ + "MessageTypeError": "MessageTypeError", + "MessageTypeInvalid": "MessageTypeInvalid", + "MessageTypeRequestSignature": "MessageTypeRequestSignature", + "MessageTypeRequestSignatureRep": "MessageTypeRequestSignatureRep", + "MessageTypeSendAnchoredDoc": "MessageTypeSendAnchoredDoc", + "MessageTypeSendAnchoredDocRep": "MessageTypeSendAnchoredDocRep", + "MessageTypeGetDoc": "MessageTypeGetDoc", + "MessageTypeGetDocRep": "MessageTypeGetDocRep", +} + // Equals compares if string is of a particular MessageType func (mt MessageType) Equals(mt2 string) bool { return mt.String() == mt2 @@ -51,26 +63,12 @@ func (mt MessageType) String() string { } // MessageTypeFromString Resolves MessageType out of string -func MessageTypeFromString(mt string) MessageType { - var found MessageType - if MessageTypeError.Equals(mt) { - found = MessageTypeError - } else if MessageTypeInvalid.Equals(mt) { - found = MessageTypeInvalid - } else if MessageTypeRequestSignature.Equals(mt) { - found = MessageTypeRequestSignature - } else if MessageTypeRequestSignatureRep.Equals(mt) { - found = MessageTypeRequestSignatureRep - } else if MessageTypeSendAnchoredDoc.Equals(mt) { - found = MessageTypeSendAnchoredDoc - } else if MessageTypeSendAnchoredDocRep.Equals(mt) { - found = MessageTypeSendAnchoredDocRep - } else if MessageTypeGetDoc.Equals(mt) { - found = MessageTypeGetDoc - } else if MessageTypeGetDocRep.Equals(mt) { - found = MessageTypeGetDocRep +func MessageTypeFromString(ht string) MessageType { + var messageType MessageType + if mt, exists := messageTypes[ht]; exists { + messageType = mt } - return found + return messageType } // ProtocolForCID creates the protocol string for the given CID From b14c0e8120365290ff8b013f2677f615df6473f1 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 18 Jan 2019 16:47:28 +0100 Subject: [PATCH 151/220] Account rename 3: use of tenant in variable names (#665) * Account rename 3: use of tenant in variable names * fix compile --- api/server.go | 4 +-- cmd/centrifuge/manage_identities.go | 2 +- cmd/common.go | 2 +- config/configstore/handler_test.go | 12 ++++---- config/configstore/service.go | 2 +- config/configstore/service_test.go | 22 +++++++------- contextutil/context.go | 6 ++-- documents/anchor_task.go | 32 ++++++++++---------- documents/anchor_task_test.go | 8 ++--- documents/error.go | 4 +-- documents/genericdoc/service.go | 14 ++++----- documents/genericdoc/service_test.go | 18 +++++------ documents/invoice/service.go | 10 +++---- documents/invoice/service_test.go | 28 ++++++++--------- documents/purchaseorder/model.go | 2 +- documents/purchaseorder/service.go | 10 +++---- documents/purchaseorder/service_test.go | 28 ++++++++--------- documents/repository.go | 38 ++++++++++++------------ documents/repository_test.go | 38 ++++++++++++------------ ethereum/geth_client.go | 6 ++-- ethereum/transaction_status_task.go | 14 ++++----- ethereum/transaction_status_task_test.go | 2 +- p2p/client.go | 14 ++++----- p2p/client_integration_test.go | 2 +- p2p/common/protocol_test.go | 4 +-- p2p/receiver/handler.go | 2 +- p2p/server.go | 4 +-- testingutils/config/config.go | 2 +- testingutils/identity/identity.go | 4 +-- testworld/config_test.go | 16 +++++----- testworld/httputils.go | 6 ++-- testworld/park.go | 8 ++--- transactions/base_task.go | 4 +-- transactions/base_task_test.go | 18 +++++------ transactions/handler.go | 14 ++++----- transactions/handler_test.go | 4 +-- transactions/service.go | 18 +++++------ 37 files changed, 211 insertions(+), 211 deletions(-) diff --git a/api/server.go b/api/server.go index 571e18b99..1fe797604 100644 --- a/api/server.go +++ b/api/server.go @@ -187,13 +187,13 @@ func grpcInterceptor() grpc.ServerOption { return grpc.UnaryInterceptor(auth) } -// auth is the grpc unary interceptor to to check if the tenant ID is passed in the header. +// auth is the grpc unary interceptor to to check if the account ID is passed in the header. // interceptor will check "authorisation" header. If not set, we return an error. // // at this point we are going with one interceptor. Once we have more than one interceptor, // we can write a wrapper interceptor that will call the chain of interceptor // -// Note: each handler can access tenantID from the context: ctx.Value(api.AccountHeaderKey) +// Note: each handler can access accountID from the context: ctx.Value(api.AccountHeaderKey) func auth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { // if this request is for ping if utils.ContainsString(noAuthPaths[:], info.FullMethod) { diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index f7192cca6..134c7612b 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -42,7 +42,7 @@ var createIdentityCmd = &cobra.Command{ panic(err) } - tctx, err := contextutil.NewCentrifugeContext(context.Background(), tc) + tctx, err := contextutil.New(context.Background(), tc) if err != nil { panic(err) } diff --git a/cmd/common.go b/cmd/common.go index 164030133..beed5aba0 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -94,7 +94,7 @@ func CreateConfig( return err } - tctx, err := contextutil.NewCentrifugeContext(context.Background(), tc) + tctx, err := contextutil.New(context.Background(), tc) if err != nil { return err } diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 13ff32a6e..1e151532f 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -66,9 +66,9 @@ func TestGrpcHandler_GetAccount(t *testing.T) { assert.NoError(t, err) _, err = h.CreateAccount(context.Background(), accpb) assert.Nil(t, err) - tid, err := accountCfg.GetIdentityID() + accID, err := accountCfg.GetIdentityID() assert.Nil(t, err) - readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) + readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(accID)}) assert.Nil(t, err) assert.NotNil(t, readCfg) } @@ -157,7 +157,7 @@ func TestGrpcHandler_UpdateAccount(t *testing.T) { tcfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tid, err := tcfg.GetIdentityID() + accID, err := tcfg.GetIdentityID() assert.Nil(t, err) acc := tcfg.(*Account) @@ -165,7 +165,7 @@ func TestGrpcHandler_UpdateAccount(t *testing.T) { // Config doesn't exist accpb, err := tcfg.CreateProtobuf() assert.NoError(t, err) - _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: accpb}) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(accID), Data: accpb}) assert.NotNil(t, err) accpb, err = tcfg.CreateProtobuf() @@ -175,10 +175,10 @@ func TestGrpcHandler_UpdateAccount(t *testing.T) { acc.EthereumDefaultAccountName = "other" tccpb, err := acc.CreateProtobuf() assert.NoError(t, err) - _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(tid), Data: tccpb}) + _, err = h.UpdateAccount(context.Background(), &accountpb.UpdateAccountRequest{Identifier: hexutil.Encode(accID), Data: tccpb}) assert.Nil(t, err) - readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(tid)}) + readCfg, err := h.GetAccount(context.Background(), &accountpb.GetAccountRequest{Identifier: hexutil.Encode(accID)}) assert.Nil(t, err) assert.Equal(t, acc.EthereumDefaultAccountName, readCfg.EthDefaultAccountName) } diff --git a/config/configstore/service.go b/config/configstore/service.go index 9c9dcbc42..c808309e1 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -76,7 +76,7 @@ func (s service) GenerateAccount() (config.Account, error) { if nil != err { return nil, err } - ctx, err := contextutil.NewCentrifugeContext(context.Background(), mtc) + ctx, err := contextutil.New(context.Background(), mtc) if err != nil { return nil, err } diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index 89f9f8e90..a6da4eb90 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -57,10 +57,10 @@ func TestService_GetAccount(t *testing.T) { svc := DefaultService(repo, idService) accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tid, _ := accountCfg.GetIdentityID() - err = repo.CreateAccount(tid, accountCfg) + accID, _ := accountCfg.GetIdentityID() + err = repo.CreateAccount(accID, accountCfg) assert.Nil(t, err) - cfg, err := svc.GetAccount(tid) + cfg, err := svc.GetAccount(accID) assert.Nil(t, err) assert.NotNil(t, cfg) } @@ -93,9 +93,9 @@ func TestService_Createaccount(t *testing.T) { assert.Nil(t, err) i, err := newCfg.GetIdentityID() assert.Nil(t, err) - tid, err := accountCfg.GetIdentityID() + accID, err := accountCfg.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, tid, i) + assert.Equal(t, accID, i) //account already exists _, err = svc.CreateAccount(accountCfg) @@ -118,9 +118,9 @@ func TestService_Updateaccount(t *testing.T) { assert.Nil(t, err) i, err := newCfg.GetIdentityID() assert.Nil(t, err) - tid, err := accountCfg.GetIdentityID() + accID, err := accountCfg.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, tid, i) + assert.Equal(t, accID, i) acc := accountCfg.(*Account) acc.EthereumDefaultAccountName = "other" @@ -137,20 +137,20 @@ func TestService_Deleteaccount(t *testing.T) { svc := DefaultService(repo, idService) accountCfg, err := NewAccount("main", cfg) assert.Nil(t, err) - tid, err := accountCfg.GetIdentityID() + accID, err := accountCfg.GetIdentityID() assert.Nil(t, err) //No config, no error - err = svc.DeleteAccount(tid) + err = svc.DeleteAccount(accID) assert.Nil(t, err) _, err = svc.CreateAccount(accountCfg) assert.Nil(t, err) - err = svc.DeleteAccount(tid) + err = svc.DeleteAccount(accID) assert.Nil(t, err) - _, err = svc.GetAccount(tid) + _, err = svc.GetAccount(accID) assert.NotNil(t, err) } diff --git a/contextutil/context.go b/contextutil/context.go index 9a2989cef..75c64b962 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -25,8 +25,8 @@ const ( self = contextKey("self") ) -// NewCentrifugeContext creates new instance of the request headers. -func NewCentrifugeContext(ctx context.Context, cfg config.Account) (context.Context, error) { +// New creates new instance of the request headers. +func New(ctx context.Context, cfg config.Account) (context.Context, error) { return context.WithValue(ctx, self, cfg), nil } @@ -65,7 +65,7 @@ func Context(ctx context.Context, cs config.Service) (context.Context, error) { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - ctxHeader, err := NewCentrifugeContext(ctx, tc) + ctxHeader, err := New(ctx, tc) if err != nil { return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 2b700b07a..e0d005b69 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -23,7 +23,7 @@ import ( const ( modelIDParam = "modelID" - tenantIDParam = "tenantID" + accountIDParam = "accountID" documentAnchorTaskName = "Document Anchoring" ) @@ -32,14 +32,14 @@ var log = logging.Logger("anchor_task") type documentAnchorTask struct { transactions.BaseTask - id []byte - tenantID identity.CentID + id []byte + accountID identity.CentID // state config config.Service processor anchorProcessor - modelGetFunc func(tenantID, id []byte) (Model, error) - modelSaveFunc func(tenantID, id []byte, model Model) error + modelGetFunc func(accountID, id []byte) (Model, error) + modelSaveFunc func(accountID, id []byte, model Model) error } // TaskTypeName returns the name of the task. @@ -64,12 +64,12 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { return errors.New("invalid model ID") } - tenantID, ok := kwargs[tenantIDParam].(string) + accountID, ok := kwargs[accountIDParam].(string) if !ok { - return errors.New("missing tenant ID") + return errors.New("missing account ID") } - d.tenantID, err = identity.CentIDFromString(tenantID) + d.accountID, err = identity.CentIDFromString(accountID) if err != nil { return errors.New("invalid cent ID") } @@ -91,26 +91,26 @@ func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { func (d *documentAnchorTask) RunTask() (res interface{}, err error) { log.Infof("starting anchor task: %v\n", d.TxID.String()) defer func() { - err = d.UpdateTransaction(d.tenantID, d.TaskTypeName(), err) + err = d.UpdateTransaction(d.accountID, d.TaskTypeName(), err) }() - tc, err := d.config.GetAccount(d.tenantID[:]) + tc, err := d.config.GetAccount(d.accountID[:]) if err != nil { apiLog.Error(err) return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) } - ctxh, err := contextutil.NewCentrifugeContext(context.Background(), tc) + ctxh, err := contextutil.New(context.Background(), tc) if err != nil { return false, errors.New("failed to get context header: %v", err) } - model, err := d.modelGetFunc(d.tenantID[:], d.id) + model, err := d.modelGetFunc(d.accountID[:], d.id) if err != nil { return false, errors.New("failed to get model: %v", err) } if _, err = AnchorDocument(ctxh, model, d.processor, func(id []byte, model Model) error { - return d.modelSaveFunc(d.tenantID[:], id, model) + return d.modelSaveFunc(d.accountID[:], id, model) }); err != nil { return false, errors.New("failed to anchor document: %v", err) } @@ -119,8 +119,8 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { } // InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. -func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Service, tenantID identity.CentID, modelID []byte) (uuid.UUID, error) { - tx, err := txService.CreateTransaction(tenantID, documentAnchorTaskName) +func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Service, accountID identity.CentID, modelID []byte) (uuid.UUID, error) { + tx, err := txService.CreateTransaction(accountID, documentAnchorTaskName) if err != nil { return uuid.Nil, err } @@ -128,7 +128,7 @@ func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Service, params := map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), modelIDParam: hexutil.Encode(modelID), - tenantIDParam: tenantID.String(), + accountIDParam: accountID.String(), } _, err = tq.EnqueueJob(documentAnchorTaskName, params) diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index 670224fae..6bc96ea33 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -40,14 +40,14 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { err: "missing model ID", }, - // missing tenantID + // missing accountID { kwargs: map[string]interface{}{ transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), modelIDParam: hexutil.Encode(utils.RandomSlice(32)), }, - err: "missing tenant ID", + err: "missing account ID", }, // all good @@ -56,7 +56,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { kwargs: map[string]interface{}{ transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), modelIDParam: hexutil.Encode(utils.RandomSlice(32)), - tenantIDParam: identity.RandomCentID().String(), + accountIDParam: identity.RandomCentID().String(), }, }, } @@ -78,7 +78,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { if c.err == "" { assert.Equal(t, task.TxID.String(), c.kwargs[transactions.TxIDParam]) assert.Equal(t, hexutil.Encode(task.id), c.kwargs[modelIDParam]) - assert.Equal(t, task.tenantID.String(), c.kwargs[tenantIDParam]) + assert.Equal(t, task.accountID.String(), c.kwargs[accountIDParam]) return } diff --git a/documents/error.go b/documents/error.go index 40cd52fef..6b5f8f244 100644 --- a/documents/error.go +++ b/documents/error.go @@ -8,8 +8,8 @@ import ( const ( - // ErrDocumentConfigTenantID must be used for errors related to tenantID operations - ErrDocumentConfigTenantID = errors.Error("error with tenantID operations") + // ErrDocumentConfigAccountID must be used for errors related to accountID operations + ErrDocumentConfigAccountID = errors.Error("error with accountID operations") // ErrDocumentBootstrap must be used for errors related to documents package bootstrapping ErrDocumentBootstrap = errors.Error("error when bootstrapping document package") diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go index 24e92c44a..8ce050833 100644 --- a/documents/genericdoc/service.go +++ b/documents/genericdoc/service.go @@ -145,7 +145,7 @@ func (s service) CreateProofsForVersion(ctx context.Context, documentID, version func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { idConf, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { @@ -170,17 +170,17 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - tenantID := idConf.ID[:] + accountID := idConf.ID[:] // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) + if !s.repo.Exists(accountID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(accountID, doc.DocumentIdentifier, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } } - err = s.repo.Create(tenantID, doc.CurrentVersion, model) + err = s.repo.Create(accountID, doc.CurrentVersion, model) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -192,7 +192,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model documents.M func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error { idConf, err := contextutil.Self(ctx) if err != nil { - return documents.ErrDocumentConfigTenantID + return documents.ErrDocumentConfigAccountID } if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { @@ -237,7 +237,7 @@ func (s service) Exists(ctx context.Context, documentID []byte) bool { func (s service) getVersion(ctx context.Context, documentID, version []byte) (documents.Model, error) { idConf, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } model, err := s.repo.Get(idConf.ID[:], version) if err != nil { diff --git a/documents/genericdoc/service_test.go b/documents/genericdoc/service_test.go index 7b410a4fb..1663d0dc3 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/genericdoc/service_test.go @@ -37,7 +37,7 @@ var testRepoGlobal documents.Repository var ( cid = identity.RandomCentID() centIDBytes = cid[:] - tenantID = cid[:] + accountID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -137,7 +137,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, } if !skipSave { - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(accountID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -175,7 +175,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv if err != nil { return nil, err } - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(accountID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -217,7 +217,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(accountID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -313,7 +313,7 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { }, } - err := testRepo().Create(tenantID, version, inv) + err := testRepo().Create(accountID, version, inv) currentVersion = version version = next assert.Nil(t, err) @@ -345,7 +345,7 @@ func TestService_GetVersion_successful(t *testing.T) { } ctxh := testingconfig.CreateTenantContext(t, cfg) - err := testRepo().Create(tenantID, currentVersion, inv) + err := testRepo().Create(accountID, currentVersion, inv) assert.Nil(t, err) mod, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) @@ -375,7 +375,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { }, } - err = testRepo().Create(tenantID, documentIdentifier, inv) + err = testRepo().Create(accountID, documentIdentifier, inv) assert.Nil(t, err) _, err = service.GetCurrentVersion(ctxh, documentIdentifier) @@ -401,7 +401,7 @@ func TestService_GetVersion_error(t *testing.T) { CurrentVersion: currentVersion, }, } - err = testRepo().Create(tenantID, currentVersion, inv) + err = testRepo().Create(accountID, currentVersion, inv) assert.Nil(t, err) //random version @@ -442,7 +442,7 @@ func TestService_Exists(t *testing.T) { }, } - err = testRepo().Create(tenantID, documentIdentifier, inv) + err = testRepo().Create(accountID, documentIdentifier, inv) exists := service.Exists(ctxh, documentIdentifier) assert.True(t, exists, "document should exist") diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 24852563e..a48f15849 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -97,7 +97,7 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv id, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } invoiceModel := new(Invoice) @@ -113,7 +113,7 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } inv, ok := new.(*Invoice) @@ -146,7 +146,7 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } inv, err = s.calculateDataRoot(ctx, nil, inv, CreateValidator()) @@ -175,7 +175,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } cd, err := inv.PackCoreDocument() @@ -309,7 +309,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv idConf, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index d65189fe8..cc0006dc6 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -35,7 +35,7 @@ import ( var ( cid = identity.RandomCentID() centIDBytes = cid[:] - tenantID = cid[:] + accountID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -88,7 +88,7 @@ func createMockDocument() (*Invoice, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(tenantID, documentIdentifier, inv1) + err := testRepo().Create(accountID, documentIdentifier, inv1) return inv1, err } @@ -156,7 +156,7 @@ func TestService_GetLastVersion(t *testing.T) { }, } - err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, inv2) + err = testRepo().Create(accountID, doc.CoreDocument.NextVersion, inv2) assert.Nil(t, err) mod2, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) @@ -180,7 +180,7 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(tenantID, currentVersion, po) + err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -200,7 +200,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(tenantID, currentVersion, inv) + err := testRepo().Create(accountID, currentVersion, inv) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -224,7 +224,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(tenantID, documentIdentifier, inv) + err := testRepo().Create(accountID, documentIdentifier, inv) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -254,8 +254,8 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) } func TestService_DeriveInvoiceData(t *testing.T) { @@ -330,7 +330,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(tenantID, id, old) + err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ Sender: "0x010101010101", @@ -403,7 +403,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) inv.(*Invoice).CoreDocument = cd - testRepo().Create(tenantID, cd.CurrentVersion, inv) + testRepo().Create(accountID, cd.CurrentVersion, inv) // calculate data root fails model = &mockModel{} @@ -433,9 +433,9 @@ func TestService_Update(t *testing.T) { assert.NotNil(t, inv) newCD, err := inv.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(tenantID, newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.PreviousVersion)) newData, err = invSrv.DeriveInvoiceData(inv) assert.Nil(t, err) assert.Equal(t, data, newData) @@ -469,7 +469,7 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - err = invSrv.repo.Create(tenantID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) + err = invSrv.repo.Create(accountID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) assert.Nil(t, err) inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, CreateValidator()) assert.Nil(t, inv) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index cccaa5d42..56e2870da 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -36,7 +36,7 @@ type PurchaseOrder struct { RecipientStreet string RecipientCity string RecipientZipcode string - RecipientCountry string // country ISO code of the receipient of this purchase order + RecipientCountry string // country ISO code of the recipient of this purchase order Currency string // ISO currency code OrderAmount int64 // ordering gross amount including tax NetAmount int64 // invoice amount excluding tax diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index ef4751788..38201a672 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -93,7 +93,7 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } po, ok := new.(*PurchaseOrder) @@ -126,7 +126,7 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } po, err = s.calculateDataRoot(ctx, nil, po, CreateValidator()) @@ -151,7 +151,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigTenantID, err) + return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } cd, err := po.PackCoreDocument() @@ -185,7 +185,7 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientpop idConf, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } po := new(PurchaseOrder) @@ -229,7 +229,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpop idConf, err := contextutil.Self(ctx) if err != nil { - return nil, documents.ErrDocumentConfigTenantID + return nil, documents.ErrDocumentConfigAccountID } collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index b32f3ac16..38bdcc29e 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -33,7 +33,7 @@ import ( var ( cid = identity.RandomCentID() - tenantID = cid[:] + accountID = cid[:] centIDBytes = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} @@ -94,7 +94,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) cd.DocumentRoot = utils.RandomSlice(32) po.(*PurchaseOrder).CoreDocument = cd - testRepo().Create(tenantID, cd.CurrentVersion, po) + testRepo().Create(accountID, cd.CurrentVersion, po) // calculate data root fails model = &testingdocuments.MockModel{} @@ -125,9 +125,9 @@ func TestService_Update(t *testing.T) { newCD, err := po.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(tenantID, newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.PreviousVersion)) newData, err = poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -176,7 +176,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old.CoreDocument.DocumentIdentifier = id old.CoreDocument.CurrentVersion = id old.CoreDocument.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(tenantID, id, old) + err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "0x010203040506", @@ -293,8 +293,8 @@ func TestService_Create(t *testing.T) { newCD, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(tenantID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(tenantID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) } func TestService_DerivePurchaseOrderData(t *testing.T) { @@ -373,7 +373,7 @@ func createMockDocument() (*PurchaseOrder, error) { NextVersion: nextIdentifier, }, } - err := testRepo().Create(tenantID, documentIdentifier, model) + err := testRepo().Create(accountID, documentIdentifier, model) return model, err } @@ -390,7 +390,7 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(tenantID, currentVersion, po) + err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -423,7 +423,7 @@ func TestService_GetCurrentVersion(t *testing.T) { }, } - err = testRepo().Create(tenantID, doc.CoreDocument.NextVersion, po2) + err = testRepo().Create(accountID, doc.CoreDocument.NextVersion, po2) assert.Nil(t, err) mod2, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) @@ -448,7 +448,7 @@ func TestService_GetVersion(t *testing.T) { CurrentVersion: currentVersion, }, } - err := testRepo().Create(tenantID, currentVersion, po) + err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -472,7 +472,7 @@ func TestService_Exists(t *testing.T) { CurrentVersion: documentIdentifier, }, } - err := testRepo().Create(tenantID, documentIdentifier, po) + err := testRepo().Create(accountID, documentIdentifier, po) assert.Nil(t, err) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -512,7 +512,7 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - err = poSrv.repo.Create(tenantID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) + err = poSrv.repo.Create(accountID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) assert.Nil(t, err) po, err = poSrv.calculateDataRoot(ctxh, nil, po, CreateValidator()) assert.Nil(t, po) diff --git a/documents/repository.go b/documents/repository.go index fc156cc01..8af162178 100644 --- a/documents/repository.go +++ b/documents/repository.go @@ -7,19 +7,19 @@ import ( // Repository defines the required methods for a document repository. // Can be implemented by any type that stores the documents. Ex: levelDB, sql etc... type Repository interface { - // Exists checks if the id, owned by tenantID, exists in DB - Exists(tenantID, id []byte) bool + // Exists checks if the id, owned by accountID, exists in DB + Exists(accountID, id []byte) bool - // Get returns the Model associated with ID, owned by tenantID - Get(tenantID, id []byte) (Model, error) + // Get returns the Model associated with ID, owned by accountID + Get(accountID, id []byte) (Model, error) // Create creates the model if not present in the DB. // should error out if the document exists. - Create(tenantID, id []byte, model Model) error + Create(accountID, id []byte, model Model) error // Update strictly updates the model. // Will error out when the model doesn't exist in the DB. - Update(tenantID, id []byte, model Model) error + Update(accountID, id []byte, model Model) error // Register registers the model so that the DB can return the document without knowing the type Register(model Model) @@ -34,9 +34,9 @@ type repo struct { db storage.Repository } -// getKey returns tenantID+id -func (r *repo) getKey(tenantID, id []byte) []byte { - return append(tenantID, id...) +// getKey returns accountID+id +func (r *repo) getKey(accountID, id []byte) []byte { + return append(accountID, id...) } // Register registers the model so that the DB can return the document without knowing the type @@ -44,15 +44,15 @@ func (r *repo) Register(model Model) { r.db.Register(model) } -// Exists checks if the id, owned by tenantID, exists in DB -func (r *repo) Exists(tenantID, id []byte) bool { - key := r.getKey(tenantID, id) +// Exists checks if the id, owned by accountID, exists in DB +func (r *repo) Exists(accountID, id []byte) bool { + key := r.getKey(accountID, id) return r.db.Exists(key) } -// Get returns the Model associated with ID, owned by tenantID -func (r *repo) Get(tenantID, id []byte) (Model, error) { - key := r.getKey(tenantID, id) +// Get returns the Model associated with ID, owned by accountID +func (r *repo) Get(accountID, id []byte) (Model, error) { + key := r.getKey(accountID, id) model, err := r.db.Get(key) if err != nil { return nil, err @@ -62,14 +62,14 @@ func (r *repo) Get(tenantID, id []byte) (Model, error) { // Create creates the model if not present in the DB. // should error out if the document exists. -func (r *repo) Create(tenantID, id []byte, model Model) error { - key := r.getKey(tenantID, id) +func (r *repo) Create(accountID, id []byte, model Model) error { + key := r.getKey(accountID, id) return r.db.Create(key, model) } // Update strictly updates the model. // Will error out when the model doesn't exist in the DB. -func (r *repo) Update(tenantID, id []byte, model Model) error { - key := r.getKey(tenantID, id) +func (r *repo) Update(accountID, id []byte, model Model) error { + key := r.getKey(accountID, id) return r.db.Update(key, model) } diff --git a/documents/repository_test.go b/documents/repository_test.go index ee07ae17a..f42e9404e 100644 --- a/documents/repository_test.go +++ b/documents/repository_test.go @@ -37,63 +37,63 @@ func (m *doc) Type() reflect.Type { func TestLevelDBRepo_Create_Exists(t *testing.T) { repo := getRepository(ctx) d := &doc{SomeString: "Hello, World!"} - tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) - assert.False(t, repo.Exists(tenantID, id), "doc must not be present") - err := repo.Create(tenantID, id, d) + accountID, id := utils.RandomSlice(32), utils.RandomSlice(32) + assert.False(t, repo.Exists(accountID, id), "doc must not be present") + err := repo.Create(accountID, id, d) assert.Nil(t, err, "Create: unknown error") - assert.True(t, repo.Exists(tenantID, id), "doc must be present") + assert.True(t, repo.Exists(accountID, id), "doc must be present") // overwrite - err = repo.Create(tenantID, id, d) + err = repo.Create(accountID, id, d) assert.Error(t, err, "Create: must not overwrite existing doc") } func TestLevelDBRepo_Update_Exists(t *testing.T) { repo := getRepository(ctx) d := &doc{SomeString: "Hello, World!"} - tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) - assert.False(t, repo.Exists(tenantID, id), "doc must not be present") - err := repo.Update(tenantID, id, d) + accountID, id := utils.RandomSlice(32), utils.RandomSlice(32) + assert.False(t, repo.Exists(accountID, id), "doc must not be present") + err := repo.Update(accountID, id, d) assert.Error(t, err, "Update: should error out") - assert.False(t, repo.Exists(tenantID, id), "doc must not be present") + assert.False(t, repo.Exists(accountID, id), "doc must not be present") // overwrite - err = repo.Create(tenantID, id, d) + err = repo.Create(accountID, id, d) assert.Nil(t, err, "Create: unknown error") d.SomeString = "Hello, Repo!" - err = repo.Update(tenantID, id, d) + err = repo.Update(accountID, id, d) assert.Nil(t, err, "Update: unknown error") - assert.True(t, repo.Exists(tenantID, id), "doc must be [resent") + assert.True(t, repo.Exists(accountID, id), "doc must be [resent") } func TestLevelDBRepo_Get_Create_Update(t *testing.T) { repo := getRepository(ctx) - tenantID, id := utils.RandomSlice(32), utils.RandomSlice(32) - m, err := repo.Get(tenantID, id) + accountID, id := utils.RandomSlice(32), utils.RandomSlice(32) + m, err := repo.Get(accountID, id) assert.Error(t, err, "must return error") assert.Nil(t, m) d := &doc{SomeString: "Hello, Repo!"} - err = repo.Create(tenantID, id, d) + err = repo.Create(accountID, id, d) assert.Nil(t, err, "Create: unknown error") - m, err = repo.Get(tenantID, id) + m, err = repo.Get(accountID, id) assert.Error(t, err, "doc is not registered yet") assert.Nil(t, m) repo.Register(&doc{}) - m, err = repo.Get(tenantID, id) + m, err = repo.Get(accountID, id) assert.Nil(t, err) assert.NotNil(t, m) nd := m.(*doc) assert.Equal(t, d, nd, "must be equal") d.SomeString = "Hello, World!" - err = repo.Update(tenantID, id, d) + err = repo.Update(accountID, id, d) assert.Nil(t, err, "Update: unknown error") - m, err = repo.Get(tenantID, id) + m, err = repo.Get(accountID, id) assert.Nil(t, err, "Get: unknown error") nd = m.(*doc) assert.Equal(t, d, nd, "must be equal") diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index be4c7c4e2..79870b2c4 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -206,14 +206,14 @@ func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, err return opts, nil } -func (gc *gethClient) queueTaskTransactionStatus(tenantID identity.CentID, txHash string) (txID uuid.UUID, err error) { - tx, err := gc.txService.CreateTransaction(tenantID, "polling Ethereum transaction status") +func (gc *gethClient) queueTaskTransactionStatus(accountID identity.CentID, txHash string) (txID uuid.UUID, err error) { + tx, err := gc.txService.CreateTransaction(accountID, "polling Ethereum transaction status") if err != nil { return txID, err } _, err = gc.queue.EnqueueJob(TransactionStatusTaskName, map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), - TransactionAccountParam: tenantID.String(), + TransactionAccountParam: accountID.String(), TransactionTxHashParam: txHash, }) diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index f8f8e26f7..74a57ee15 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -37,8 +37,8 @@ type TransactionStatusTask struct { transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) //txHash is the id of an Ethereum transaction - txHash string - tenantID identity.CentID + txHash string + accountID identity.CentID } // NewTransactionStatusTask returns a the struct for the task @@ -69,7 +69,7 @@ func (nftc *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { return &TransactionStatusTask{ timeout: nftc.timeout, txHash: nftc.txHash, - tenantID: nftc.tenantID, + accountID: nftc.accountID, transactionByHash: nftc.transactionByHash, transactionReceipt: nftc.transactionReceipt, ethContextInitializer: nftc.ethContextInitializer, @@ -84,12 +84,12 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e return err } - tenantID, ok := kwargs[TransactionAccountParam].(string) + accountID, ok := kwargs[TransactionAccountParam].(string) if !ok { - return errors.New("missing tenant ID") + return errors.New("missing account ID") } - nftc.tenantID, err = identity.CentIDFromString(tenantID) + nftc.accountID, err = identity.CentIDFromString(accountID) if err != nil { return err } @@ -135,7 +135,7 @@ func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { ctx, cancelF := nftc.ethContextInitializer(nftc.timeout) defer cancelF() defer func() { - err = nftc.UpdateTransaction(nftc.tenantID, nftc.TaskTypeName(), err) + err = nftc.UpdateTransaction(nftc.accountID, nftc.TaskTypeName(), err) }() _, isPending, err := nftc.transactionByHash(ctx, common.HexToHash(nftc.txHash)) diff --git a/ethereum/transaction_status_task_test.go b/ethereum/transaction_status_task_test.go index 6e7b6c1a2..06e4fdb99 100644 --- a/ethereum/transaction_status_task_test.go +++ b/ethereum/transaction_status_task_test.go @@ -29,7 +29,7 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { err = task.ParseKwargs(decoded) assert.Nil(t, err, "parsing should be successful") - assert.Equal(t, cid, task.tenantID, "tenantID should be parsed correctly") + assert.Equal(t, cid, task.accountID, "accountID should be parsed correctly") assert.Equal(t, txID, task.TxID.String(), "txID should be parsed correctly") assert.Equal(t, txHash, task.txHash, "txHash should be parsed correctly") diff --git a/p2p/client.go b/p2p/client.go index 4baa1a138..c91ae233f 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -44,17 +44,17 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i cid := id.CentID() tc, err := s.config.GetAccount(cid[:]) if err == nil { - // this is a local tenant + // this is a local account h := s.handlerCreator() // the following context has to be different from the parent context since its initiating a local peer call - localCtx, err := contextutil.NewCentrifugeContext(peerCtx, tc) + localCtx, err := contextutil.New(peerCtx, tc) if err != nil { return nil, err } return h.SendAnchoredDocument(localCtx, in, cid[:]) } - // this is a remote tenant + // this is a remote account pid, err := s.getPeerID(id) if err != nil { return nil, err @@ -144,10 +144,10 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden tc, err := s.config.GetAccount(receiverCentID[:]) if err == nil { - // this is a local tenant + // this is a local account h := s.handlerCreator() - // create a context with receiving tenant value - localPeerCtx, err := contextutil.NewCentrifugeContext(ctx, tc) + // create a context with receiving account value + localPeerCtx, err := contextutil.New(ctx, tc) if err != nil { return nil, err } @@ -158,7 +158,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden } header = &p2ppb.Header{NodeVersion: version.GetVersion().String()} } else { - // this is a remote tenant + // this is a remote account id, err := identityService.LookupIdentityForID(receiverCentID) if err != nil { return nil, err diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 110ce53d3..9b3a8c9f1 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -81,7 +81,7 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account assert.NoError(t, err) tcr := tc.(*configstore.Account) tcr.IdentityID = tcID[:] - id := testingidentity.CreateTenantIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService) + id := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService) if corruptID { tcr.IdentityID = utils.RandomSlice(identity.CentIDLength) } diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index 115d556ec..d70db0d01 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -89,7 +89,7 @@ func TestPrepareP2PEnvelope(t *testing.T) { id, _ := cfg.GetIdentityID() spk, ssk := cfg.GetSigningKeyPair() - tc := &configstore.Account{ + acc := &configstore.Account{ IdentityID: id, SigningKeyPair: configstore.KeyPair{ Priv: ssk, @@ -100,7 +100,7 @@ func TestPrepareP2PEnvelope(t *testing.T) { Pub: spk, }, } - ctx, _ := contextutil.NewCentrifugeContext(context.Background(), tc) + ctx, _ := contextutil.New(context.Background(), acc) assert.NotNil(t, ctx) // Nil proto.Message diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index b31b42fd3..8efefe95a 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -80,7 +80,7 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - ctx, err = contextutil.NewCentrifugeContext(ctx, tc) + ctx, err = contextutil.New(ctx, tc) if err != nil { return convertToErrorEnvelop(err) } diff --git a/p2p/server.go b/p2p/server.go index 011b5b350..7968f2838 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -104,11 +104,11 @@ func (s *peer) initProtocols() error { } var protocols []protocol.ID for _, t := range tcs { - tid, err := t.GetIdentityID() + accID, err := t.GetIdentityID() if err != nil { return err } - CID, err := identity.ToCentID(tid) + CID, err := identity.ToCentID(accID) if err != nil { return err } diff --git a/testingutils/config/config.go b/testingutils/config/config.go index e09d49fb8..57d070874 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -170,7 +170,7 @@ func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg confi tc, err := configstore.NewAccount("", cfg) assert.Nil(t, err) - contextHeader, err := contextutil.NewCentrifugeContext(ctx, tc) + contextHeader, err := contextutil.New(ctx, tc) assert.Nil(t, err) return contextHeader } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 98de0c17b..e943864e9 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -46,8 +46,8 @@ func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service return idConfig.ID } -func CreateTenantIDWithKeys(contextTimeout time.Duration, cfg *configstore.Account, idService identity.Service) identity.Identity { - ctxh, _ := contextutil.NewCentrifugeContext(context.Background(), cfg) +func CreateAccountIDWithKeys(contextTimeout time.Duration, cfg *configstore.Account, idService identity.Service) identity.Identity { + ctxh, _ := contextutil.New(context.Background(), cfg) idConfig, _ := identity.GetIdentityConfig(cfg) // only create identity if it doesn't exist id, err := idService.LookupIdentityForID(idConfig.ID) diff --git a/testworld/config_test.go b/testworld/config_test.go index 149237b43..3f075ed29 100644 --- a/testworld/config_test.go +++ b/testworld/config_test.go @@ -13,19 +13,19 @@ func TestConfig_Happy(t *testing.T) { // check charlies node config res := getNodeConfig(charlie.httpExpect, charlie.id.String(), http.StatusOK) - tenantID := res.Value("main_identity").Path("$.identity_id").String().NotEmpty() - tenantID.Equal(charlie.id.String()) + accountID := res.Value("main_identity").Path("$.identity_id").String().NotEmpty() + accountID.Equal(charlie.id.String()) - // check charlies main tenant config + // check charlies main account res = getAccount(charlie.httpExpect, charlie.id.String(), http.StatusOK, charlie.id.String()) - tenantID2 := res.Value("identity_id").String().NotEmpty() - tenantID2.Equal(charlie.id.String()) + accountID2 := res.Value("identity_id").String().NotEmpty() + accountID2.Equal(charlie.id.String()) - // check charlies all tenant configs + // check charlies all accounts res = getAllAccounts(charlie.httpExpect, charlie.id.String(), http.StatusOK) tenants := res.Value("data").Array() - tids := getAccounts(tenants) - if _, ok := tids[charlie.id.String()]; !ok { + accIDs := getAccounts(tenants) + if _, ok := accIDs[charlie.id.String()]; !ok { t.Error("Charlies id needs to exist in the accounts list") } diff --git a/testworld/httputils.go b/testworld/httputils.go index dde0db94b..1c9321a75 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -152,10 +152,10 @@ func addCommonHeaders(req *httpexpect.Request, auth string) *httpexpect.Request } func getAccounts(accounts *httpexpect.Array) map[string]string { - tids := make(map[string]string) + accIDs := make(map[string]string) for i := 0; i < int(accounts.Length().Raw()); i++ { val := accounts.Element(i).Path("$.identity_id").String().NotEmpty().Raw() - tids[val] = val + accIDs[val] = val } - return tids + return accIDs } diff --git a/testworld/park.go b/testworld/park.go index 70b3ef5c3..958f60183 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -356,10 +356,10 @@ func (h *host) createAccounts(e *httpexpect.Expect) error { func (h *host) loadAccounts(e *httpexpect.Expect) error { res := getAllAccounts(e, h.identity.CentID().String(), http.StatusOK) - tenants := res.Value("data").Array() - tids := getAccounts(tenants) - keys := make([]string, 0, len(tids)) - for k := range tids { + accounts := res.Value("data").Array() + accIDs := getAccounts(accounts) + keys := make([]string, 0, len(accIDs)) + for k := range accIDs { keys = append(keys, k) } h.accounts = keys diff --git a/transactions/base_task.go b/transactions/base_task.go index 371889e76..6e3006860 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -39,7 +39,7 @@ func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { } // UpdateTransaction add a new log and updates the status of the transaction based on the error. -func (b *BaseTask) UpdateTransaction(tenantID identity.CentID, name string, err error) error { +func (b *BaseTask) UpdateTransaction(accountID identity.CentID, name string, err error) error { if err == gocelery.ErrTaskRetryable { return err } @@ -50,7 +50,7 @@ func (b *BaseTask) UpdateTransaction(tenantID identity.CentID, name string, err log.Infof("Transaction successful:%v\n", b.TxID.String()) } - tx, erri := b.TxService.GetTransaction(tenantID, b.TxID) + tx, erri := b.TxService.GetTransaction(accountID, b.TxID) if erri != nil { return errors.AppendError(err, erri) } diff --git a/transactions/base_task_test.go b/transactions/base_task_test.go index a804644de..1da134f11 100644 --- a/transactions/base_task_test.go +++ b/transactions/base_task_test.go @@ -16,38 +16,38 @@ import ( func TestDocumentAnchorTask_updateTransaction(t *testing.T) { task := new(BaseTask) - tenantID := identity.RandomCentID() + accountID := identity.RandomCentID() name := "some task" task.TxID = uuid.Must(uuid.NewV4()) task.TxService = NewService(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) // missing transaction with nil error - err := task.UpdateTransaction(tenantID, name, nil) + err := task.UpdateTransaction(accountID, name, nil) err = errors.GetErrs(err)[0] assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) // missing transaction with error - err = task.UpdateTransaction(tenantID, name, errors.New("anchor error")) + err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) err = errors.GetErrs(err)[1] assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) // no error and success - tx := NewTransaction(tenantID, "") + tx := NewTransaction(accountID, "") assert.NoError(t, task.TxService.SaveTransaction(tx)) task.TxID = tx.ID - assert.NoError(t, task.UpdateTransaction(tenantID, name, nil)) - tx, err = task.TxService.GetTransaction(tenantID, task.TxID) + assert.NoError(t, task.UpdateTransaction(accountID, name, nil)) + tx, err = task.TxService.GetTransaction(accountID, task.TxID) assert.NoError(t, err) assert.Equal(t, tx.Status, Success) assert.Len(t, tx.Logs, 1) // failed task - tx = NewTransaction(tenantID, "") + tx = NewTransaction(accountID, "") assert.NoError(t, task.TxService.SaveTransaction(tx)) task.TxID = tx.ID - err = task.UpdateTransaction(tenantID, name, errors.New("anchor error")) + err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) assert.EqualError(t, errors.GetErrs(err)[0], "anchor error") - tx, err = task.TxService.GetTransaction(tenantID, task.TxID) + tx, err = task.TxService.GetTransaction(accountID, task.TxID) assert.NoError(t, err) assert.Equal(t, tx.Status, Failed) assert.Len(t, tx.Logs, 1) diff --git a/transactions/handler.go b/transactions/handler.go index 6cd9c2f9f..585c5e5f3 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -15,8 +15,8 @@ import ( // ErrInvalidTransactionID error for Invalid transaction ID. const ErrInvalidTransactionID = errors.Error("Invalid Transaction ID") -// ErrInvalidTenantID error for Invalid tenant ID. -const ErrInvalidTenantID = errors.Error("Invalid Tenant ID") +// ErrInvalidAccountID error for Invalid account ID. +const ErrInvalidAccountID = errors.Error("Invalid Tenant ID") var apiLog = logging.Logger("transaction-api") @@ -46,16 +46,16 @@ func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactions tc, err := contextutil.Account(ctxHeader) if err != nil { - return nil, ErrInvalidTenantID + return nil, ErrInvalidAccountID } - tid, err := tc.GetIdentityID() + accID, err := tc.GetIdentityID() if err != nil { - return nil, ErrInvalidTenantID + return nil, ErrInvalidAccountID } - cid, err := identity.ToCentID(tid) + cid, err := identity.ToCentID(accID) if err != nil { - return nil, ErrInvalidTenantID + return nil, ErrInvalidAccountID } return h.srv.GetTransactionStatus(cid, id) diff --git a/transactions/handler_test.go b/transactions/handler_test.go index 18f6723b2..0042e1ef7 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -37,8 +37,8 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { // missing err tcs, _ := cService.GetAllAccounts() - tid, _ := tcs[0].GetIdentityID() - cid, err := identity.ToCentID(tid) + accID, _ := tcs[0].GetIdentityID() + cid, err := identity.ToCentID(accID) tx := NewTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) diff --git a/transactions/service.go b/transactions/service.go index 2baa1bdeb..24e3d9eb2 100644 --- a/transactions/service.go +++ b/transactions/service.go @@ -13,11 +13,11 @@ import ( // Service wraps the repository and exposes specific functions. type Service interface { - CreateTransaction(tenantID identity.CentID, desc string) (*Transaction, error) - GetTransaction(tenantID identity.CentID, id uuid.UUID) (*Transaction, error) + CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) + GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) SaveTransaction(tx *Transaction) error GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) - WaitForTransaction(tenantID identity.CentID, txID uuid.UUID) error + WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error } // NewService returns a Service implementation. @@ -36,21 +36,21 @@ func (s service) SaveTransaction(tx *Transaction) error { } // GetTransaction returns the transaction associated with identity and id. -func (s service) GetTransaction(tenantID identity.CentID, id uuid.UUID) (*Transaction, error) { - return s.repo.Get(tenantID, id) +func (s service) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) { + return s.repo.Get(accountID, id) } // CreateTransaction creates a new transaction and saves it to the DB. -func (s service) CreateTransaction(tenantID identity.CentID, desc string) (*Transaction, error) { - tx := NewTransaction(tenantID, desc) +func (s service) CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) { + tx := NewTransaction(accountID, desc) return tx, s.SaveTransaction(tx) } // WaitForTransaction blocks until transaction status is moved from pending state. // Note: use it with caution as this will block. -func (s service) WaitForTransaction(tenantID identity.CentID, txID uuid.UUID) error { +func (s service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { for { - resp, err := s.GetTransactionStatus(tenantID, txID) + resp, err := s.GetTransactionStatus(accountID, txID) if err != nil { return err } From 2343a4035f1ffef2d780394fd0a5a6c1e8b08167 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 18 Jan 2019 18:17:12 +0100 Subject: [PATCH 152/220] Document service refactor (#666) * break the coredocument package * fix anchors * fix unit tests * fix unit tests * fix tests * break the coredocument package * fix anchors * fix unit tests * fix unit tests * fix tests --- anchors/anchor.go | 4 +- anchors/anchor_repository_integration_test.go | 7 +- api/bootstrapper.go | 14 - api/bootstrapper_test.go | 2 - api/server_test.go | 10 +- api/service.go | 18 +- bootstrap/bootstrapper.go | 4 +- bootstrap/bootstrappers/bootstrapper.go | 6 +- .../testingbootstrap/testing_bootstrap.go | 4 - config/configstore/bootstrapper.go | 2 +- .../configstore/service_integration_test.go | 2 +- coredocument/bootstrapper.go | 38 -- coredocument/bootstrapper_test.go | 14 - coredocument/coredocument_test.go | 13 +- coredocument/test_bootstrapper.go | 11 - coredocument/validator.go | 353 ----------- coredocument/validator_test.go | 554 ------------------ documents/anchor.go | 12 +- documents/anchor_task.go | 15 +- documents/anchor_task_test.go | 1 - documents/bootstrapper.go | 49 +- documents/bootstrapper_test.go | 12 +- .../{test => documents_test}/anchor_test.go | 83 ++- .../service_test.go | 42 +- documents/genericdoc/bootstrapper.go | 37 -- documents/genericdoc/service.go | 256 -------- documents/genericdoc/test_bootstrapper.go | 11 - documents/handler_test.go | 3 +- documents/invoice/bootstrapper.go | 29 +- documents/invoice/handler.go | 13 +- documents/invoice/model_test.go | 4 +- documents/invoice/service.go | 79 +-- documents/invoice/service_test.go | 21 +- documents/invoice/validator.go | 3 +- documents/model.go | 3 +- documents/model_test.go | 16 +- {coredocument => documents}/processor.go | 54 +- {coredocument => documents}/processor_test.go | 46 +- documents/purchaseorder/bootstrapper.go | 30 +- documents/purchaseorder/handler.go | 17 +- documents/purchaseorder/model_test.go | 3 +- documents/purchaseorder/service.go | 78 +-- documents/purchaseorder/service_test.go | 14 +- documents/purchaseorder/validator.go | 3 +- documents/service.go | 274 +++++++++ documents/test_bootstrapper.go | 4 - documents/validator.go | 346 +++++++++++ documents/validator_test.go | 542 +++++++++++++++++ identity/identity_test.go | 83 +-- nft/bootstrapper.go | 13 +- nft/ethereum_payment_obligation.go | 14 +- nft/ethereum_payment_obligation_test.go | 4 +- node/bootstrapper.go | 2 +- p2p/bootstrapper.go | 16 +- p2p/bootstrapper_test.go | 15 +- p2p/client.go | 10 - p2p/client_integration_test.go | 6 +- p2p/receiver/handler.go | 75 +-- p2p/receiver/handler_integration_test.go | 36 +- p2p/receiver/handler_test.go | 110 +--- p2p/server_test.go | 28 +- testingutils/anchors/mock_anchor_repo.go | 19 + testingutils/coredocument/coredocument.go | 59 +- testingutils/documents/documents.go | 1 + 64 files changed, 1581 insertions(+), 2066 deletions(-) delete mode 100644 coredocument/bootstrapper.go delete mode 100644 coredocument/bootstrapper_test.go delete mode 100644 coredocument/test_bootstrapper.go delete mode 100644 coredocument/validator.go delete mode 100644 coredocument/validator_test.go rename documents/{test => documents_test}/anchor_test.go (67%) rename documents/{genericdoc => documents_test}/service_test.go (93%) delete mode 100644 documents/genericdoc/bootstrapper.go delete mode 100644 documents/genericdoc/service.go delete mode 100644 documents/genericdoc/test_bootstrapper.go rename {coredocument => documents}/processor.go (82%) rename {coredocument => documents}/processor_test.go (94%) create mode 100644 testingutils/anchors/mock_anchor_repo.go diff --git a/anchors/anchor.go b/anchors/anchor.go index aaf1137fc..6de125f13 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -2,11 +2,9 @@ package anchors import ( "math/big" - - "github.com/centrifuge/go-centrifuge/errors" - "time" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/crypto" diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 9ab9710b2..3262184fa 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -7,15 +7,14 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" diff --git a/api/bootstrapper.go b/api/bootstrapper.go index 783a9698a..ec664c247 100644 --- a/api/bootstrapper.go +++ b/api/bootstrapper.go @@ -2,10 +2,7 @@ package api import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" ) // Bootstrapper implements bootstrapper.Bootstrapper @@ -18,17 +15,6 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return err } - _, ok := ctx[config.BootstrappedConfigStorage].(config.Service) - if !ok { - return errors.New("config store not initialised") - } - - // just check to make sure that registry is initialised - _, ok = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - if !ok { - return errors.New("service registry not initialised") - } - srv := apiServer{config: cfg} ctx[bootstrap.BootstrappedAPIServer] = srv return nil diff --git a/api/bootstrapper_test.go b/api/bootstrapper_test.go index 88cb762ca..6b5ee87e1 100644 --- a/api/bootstrapper_test.go +++ b/api/bootstrapper_test.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/stretchr/testify/assert" @@ -28,7 +27,6 @@ func TestBootstrapper_Bootstrap(t *testing.T) { cs := new(configstore.MockService) m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) - m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() err = b.Bootstrap(m) assert.Nil(t, err) assert.NotNil(t, m[bootstrap.BootstrappedAPIServer]) diff --git a/api/server_test.go b/api/server_test.go index 3f6fdf32a..481ad4675 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,21 +9,20 @@ import ( "sync" "testing" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/go-centrifuge/p2p" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" - "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -35,7 +34,6 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration -var registry *documents.ServiceRegistry func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -52,8 +50,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, + documents.PostBootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, ðereum.Bootstrapper{}, @@ -63,7 +61,6 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -74,7 +71,6 @@ func TestCentAPIServer_StartContextCancel(t *testing.T) { cfg.Set("nodeHostname", "0.0.0.0") cfg.Set("nodePort", 9000) cfg.Set("centrifugeNetwork", "") - registry.Register(documenttypes.InvoiceDataTypeUrl, invoice.DefaultService(nil, nil, nil, nil, nil, nil)) capi := apiServer{config: cfg} ctx, canc := context.WithCancel(context.WithValue(context.Background(), bootstrap.NodeObjRegistry, ctx)) startErr := make(chan error) diff --git a/api/service.go b/api/service.go index 9a0998581..1ebda4efb 100644 --- a/api/service.go +++ b/api/service.go @@ -56,23 +56,23 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // invoice - handler, err := invoice.GRPCHandler(configService, registry) - if err != nil { - return err + invHandler, ok := nodeObjReg[invoice.BootstrappedInvoiceHandler].(invoicepb.DocumentServiceServer) + if !ok { + return errors.New("invoice grpc handler not registered") } - invoicepb.RegisterDocumentServiceServer(grpcServer, handler) + + invoicepb.RegisterDocumentServiceServer(grpcServer, invHandler) err = invoicepb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err } - // purchase orders - srv, err := purchaseorder.GRPCHandler(configService, registry) - if err != nil { - return errors.New("failed to get purchase order handler: %v", err) + poHandler, ok := nodeObjReg[purchaseorder.BootstrappedPOHandler].(purchaseorderpb.DocumentServiceServer) + if !ok { + return errors.New("purchase order grpc handler not registered") } - purchaseorderpb.RegisterDocumentServiceServer(grpcServer, srv) + purchaseorderpb.RegisterDocumentServiceServer(grpcServer, poHandler) err = purchaseorderpb.RegisterDocumentServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts) if err != nil { return err diff --git a/bootstrap/bootstrapper.go b/bootstrap/bootstrapper.go index 61af54681..052072dcb 100644 --- a/bootstrap/bootstrapper.go +++ b/bootstrap/bootstrapper.go @@ -5,12 +5,10 @@ package bootstrap // Bootstrap constants are keys to mapped value in bootstrapped context const ( BootstrappedConfig string = "BootstrappedConfig" - BootstrappedP2PServer string = "BootstrappedP2PServer" - BootstrappedP2PClient string = "BootstrappedP2PClient" + BootstrappedPeer string = "BootstrappedPeer" BootstrappedAPIServer string = "BootstrappedAPIServer" BootstrappedQueueServer string = "BootstrappedQueueServer" NodeObjRegistry string = "NodeObjRegistry" - BootstrappedCoreDocProc string = "BootstrappedCoreDocProc" ) // Bootstrapper must be implemented by all packages that needs bootstrapping at application start diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 4b43a28ed..45f24f8e2 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -6,9 +6,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -43,13 +41,11 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &configstore.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, - &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, api.Bootstrapper{}, + documents.PostBootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, - coredocument.Bootstrapper{}, - documents.PostBootstrapper{}, &nft.Bootstrapper{}, } } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index a9b6ab275..8b77257bb 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -8,9 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" @@ -37,11 +35,9 @@ var bootstappers = []bootstrap.TestBootstrapper{ &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, - coredocument.Bootstrapper{}, documents.PostBootstrapper{}, &nft.Bootstrapper{}, &queue.Starter{}, diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 2763181d6..0926df39c 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -28,7 +28,7 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { repo := &repo{configdb} service := &service{repo, idService, func() ProtocolSetter { - return context[bootstrap.BootstrappedP2PServer].(ProtocolSetter) + return context[bootstrap.BootstrappedPeer].(ProtocolSetter) }} nc := NewNodeConfig(cfg) diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go index 2d454a735..9bec65a63 100644 --- a/config/configstore/service_integration_test.go +++ b/config/configstore/service_integration_test.go @@ -30,7 +30,7 @@ func TestMain(m *testing.M) { time.Sleep(time.Second + 2) ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[config.BootstrappedConfigStorage].(config.Service) - ctx[bootstrap.BootstrappedP2PServer] = &MockProtocolSetter{} + ctx[bootstrap.BootstrappedPeer] = &MockProtocolSetter{} identityService = ctx[identity.BootstrappedIDService].(identity.Service) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() diff --git a/coredocument/bootstrapper.go b/coredocument/bootstrapper.go deleted file mode 100644 index e74964a2f..000000000 --- a/coredocument/bootstrapper.go +++ /dev/null @@ -1,38 +0,0 @@ -package coredocument - -import ( - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" -) - -// Bootstrapper to initialise processor -type Bootstrapper struct{} - -// Bootstrap adds processor to the context. -func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(true, ctx) - if err != nil { - return err - } - - anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - if !ok { - return errors.New("anchor repository not initialised") - } - - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) - if !ok { - return errors.New("identity service not initialised") - } - - p2pClient, ok := ctx[bootstrap.BootstrappedP2PClient].(client) - if !ok { - return errors.New("p2p client not initialised") - } - - ctx[bootstrap.BootstrappedCoreDocProc] = DefaultProcessor(idService, p2pClient, anchorRepo, cfg) - return nil -} diff --git a/coredocument/bootstrapper_test.go b/coredocument/bootstrapper_test.go deleted file mode 100644 index a7a657ff2..000000000 --- a/coredocument/bootstrapper_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build unit - -package coredocument - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBootstrapper_Bootstrap(t *testing.T) { - err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) - assert.Error(t, err, "Should throw an error because of empty context") -} diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index d2404f06a..25f5b03a4 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -23,14 +23,6 @@ import ( "github.com/stretchr/testify/assert" ) -var ( - id1 = utils.RandomSlice(32) - id2 = utils.RandomSlice(32) - id3 = utils.RandomSlice(32) - id4 = utils.RandomSlice(32) - id5 = utils.RandomSlice(32) -) - var ctx = map[string]interface{}{} var cfg config.Configuration @@ -40,11 +32,11 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - flag.Parse() cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + flag.Parse() result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -245,7 +237,8 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + self, err := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + assert.NoError(t, err) collaborators, err := GetExternalCollaborators(self.ID, cd) assert.Nil(t, err) assert.NotNil(t, collaborators) diff --git a/coredocument/test_bootstrapper.go b/coredocument/test_bootstrapper.go deleted file mode 100644 index f6e0eb6f9..000000000 --- a/coredocument/test_bootstrapper.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build integration unit - -package coredocument - -func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { - return b.Bootstrap(context) -} - -func (Bootstrapper) TestTearDown() error { - return nil -} diff --git a/coredocument/validator.go b/coredocument/validator.go deleted file mode 100644 index 646177a54..000000000 --- a/coredocument/validator.go +++ /dev/null @@ -1,353 +0,0 @@ -package coredocument - -import ( - "fmt" - - "github.com/centrifuge/go-centrifuge/crypto" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -// UpdateVersionValidator validates if the new core document is properly derived from old one -func UpdateVersionValidator() documents.Validator { - return documents.ValidatorFunc(func(old, new documents.Model) error { - if old == nil || new == nil { - return errors.New("need both the old and new model") - } - - oldCD, err := old.PackCoreDocument() - if err != nil { - return errors.New("failed to fetch old core document: %v", err) - } - - newCD, err := new.PackCoreDocument() - if err != nil { - return errors.New("failed to fetch new core document: %v", err) - } - - checks := []struct { - name string - a, b []byte - }{ - { - name: "cd_document_identifier", - a: oldCD.DocumentIdentifier, - b: newCD.DocumentIdentifier, - }, - - { - name: "cd_previous_version", - a: oldCD.CurrentVersion, - b: newCD.PreviousVersion, - }, - - { - name: "cd_current_version", - a: oldCD.NextVersion, - b: newCD.CurrentVersion, - }, - - { - name: "cd_previous_version", - a: oldCD.DocumentRoot, - b: newCD.PreviousRoot, - }, - } - - for _, c := range checks { - if !utils.CheckMultiple32BytesFilled(c.a, c.b) { - err = errors.AppendError(err, documents.NewError(c.name, "missing identifiers")) - continue - } - - if !utils.IsSameByteSlice(c.a, c.b) { - err = errors.AppendError(err, documents.NewError(c.name, "mismatched")) - } - } - - if utils.IsEmptyByteSlice(newCD.NextVersion) { - err = errors.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) - } - - return err - }) -} - -// getCoreDocument takes an model and returns the core document of the model -func getCoreDocument(model documents.Model) (*coredocumentpb.CoreDocument, error) { - if model == nil { - return nil, errors.New("nil model") - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, errors.New("failed to pack core document: %v", err) - } - - return cd, nil -} - -// baseValidator validates the core document basic fields like identifier, versions, and salts -func baseValidator() documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) error { - cd, err := getCoreDocument(model) - if err != nil { - return err - } - - if cd == nil { - return errors.New("nil document") - } - - if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { - err = errors.AppendError(err, documents.NewError("cd_identifier", centerrors.RequiredField)) - } - - if utils.IsEmptyByteSlice(cd.CurrentVersion) { - err = errors.AppendError(err, documents.NewError("cd_current_version", centerrors.RequiredField)) - } - - if utils.IsEmptyByteSlice(cd.NextVersion) { - err = errors.AppendError(err, documents.NewError("cd_next_version", centerrors.RequiredField)) - } - - if utils.IsEmptyByteSlice(cd.DataRoot) { - err = errors.AppendError(err, documents.NewError("cd_data_root", centerrors.RequiredField)) - } - - // double check the identifiers - isSameBytes := utils.IsSameByteSlice - - // Problem (re-using an old identifier for NextVersion): CurrentVersion or DocumentIdentifier same as NextVersion - if isSameBytes(cd.NextVersion, cd.DocumentIdentifier) || - isSameBytes(cd.NextVersion, cd.CurrentVersion) { - err = errors.AppendError(err, documents.NewError("cd_overall", centerrors.IdentifierReUsed)) - } - - // lets not do verbose check like earlier since these will be - // generated by us mostly - salts := cd.CoredocumentSalts - if salts == nil || - !utils.CheckMultiple32BytesFilled( - salts.CurrentVersion, - salts.NextVersion, - salts.DocumentIdentifier, - salts.PreviousRoot) { - err = errors.AppendError(err, documents.NewError("cd_salts", centerrors.RequiredField)) - } - - return err - }) -} - -// signingRootValidator checks the existence of signing root -// recalculates the signing root and compares with existing one -func signingRootValidator() documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) error { - cd, err := getCoreDocument(model) - if err != nil { - return err - } - - if utils.IsEmptyByteSlice(cd.SigningRoot) { - return errors.New("signing root missing") - } - - tree, err := GetDocumentSigningTree(cd) - if err != nil { - return errors.New("failed to calculate signing root: %v", err) - } - - if !utils.IsSameByteSlice(cd.SigningRoot, tree.RootHash()) { - return errors.New("signing root mismatch") - } - - return nil - }) -} - -// documentRootValidator checks the existence of document root -// recalculates the document root and compares with existing one -func documentRootValidator() documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) error { - cd, err := getCoreDocument(model) - if err != nil { - return err - } - - if utils.IsEmptyByteSlice(cd.DocumentRoot) { - return errors.New("document root missing") - } - - tree, err := GetDocumentRootTree(cd) - if err != nil { - return errors.New("failed to calculate document root: %v", err) - } - - if !utils.IsSameByteSlice(cd.DocumentRoot, tree.RootHash()) { - return errors.New("document root mismatch") - } - - return nil - }) -} - -// readyForSignaturesValidator validates self signature -// re-calculates the signature and compares with existing one -// assumes signing_root is already generated and verified -// Note: this needs to used only before document is sent for signatures from the collaborators -func readyForSignaturesValidator(centIDBytes, priv, pub []byte) documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) error { - cd, err := getCoreDocument(model) - if err != nil { - return err - } - - if len(cd.Signatures) != 1 { - return errors.New("expecting only one signature") - } - - s := crypto.Sign(centIDBytes, priv, pub, cd.SigningRoot) - sh := cd.Signatures[0] - if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { - err = errors.AppendError(err, documents.NewError("cd_entity_id", "entity ID mismatch")) - } - - if !utils.IsSameByteSlice(s.PublicKey, sh.PublicKey) { - err = errors.AppendError(err, documents.NewError("cd_public_key", "public key mismatch")) - } - - if !utils.IsSameByteSlice(s.Signature, sh.Signature) { - err = errors.AppendError(err, documents.NewError("cd_signature", "signature mismatch")) - } - - return err - }) -} - -// signaturesValidator validates all the signatures in the core document -// assumes signing root is verified -// Note: can be used when during the signature request on collaborator side and post signature collection on sender side -// Note: this will break the current flow where we proceed to anchor even signatures verification fails -func signaturesValidator(idService identity.Service) documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) error { - cd, err := getCoreDocument(model) - if err != nil { - return err - } - - if len(cd.Signatures) < 1 { - return errors.New("atleast one signature expected") - } - - for _, sig := range cd.Signatures { - if erri := idService.ValidateSignature(sig, cd.SigningRoot); erri != nil { - err = errors.AppendError( - err, - documents.NewError( - fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), - fmt.Sprintf("signature verification failed: %v", erri))) - } - } - - return err - }) -} - -// anchoredValidator checks if the document root matches the one on chain with specific anchorID -// assumes document root is generated and verified -func anchoredValidator(repo anchors.AnchorRepository) documents.Validator { - return documents.ValidatorFunc(func(_, new documents.Model) error { - cd, err := getCoreDocument(new) - if err != nil { - return errors.New("failed to get core document: %v", err) - } - - anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) - if err != nil { - return errors.New("failed to get anchorID: %v", err) - } - - docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) - if err != nil { - return errors.New("failed to get document root: %v", err) - } - - gotRoot, err := repo.GetDocumentRootOf(anchorID) - if err != nil { - return errors.New("failed to get document root from chain: %v", err) - } - - if !utils.IsSameByteSlice(docRoot[:], gotRoot[:]) { - return errors.New("mismatched document roots") - } - - return nil - }) -} - -// SignatureRequestValidator returns a validator group with following validators -// base validator -// signing root validator -// signatures validator -// should be used when node receives a document requesting for signature -func SignatureRequestValidator(idService identity.Service) documents.ValidatorGroup { - return PostSignatureRequestValidator(idService) -} - -// PreAnchorValidator is a validator group with following validators -// base validator -// signing root validator -// document root validator -// signatures validator -// should be called before pre anchoring -func PreAnchorValidator(idService identity.Service) documents.ValidatorGroup { - return documents.ValidatorGroup{ - PostSignatureRequestValidator(idService), - documentRootValidator(), - } -} - -// PostAnchoredValidator is a validator group with following validators -// PreAnchorValidator -// anchoredValidator -// should be called after anchoring the document/when received anchored document -func PostAnchoredValidator(idService identity.Service, repo anchors.AnchorRepository) documents.ValidatorGroup { - return documents.ValidatorGroup{ - PreAnchorValidator(idService), - anchoredValidator(repo), - } -} - -// PreSignatureRequestValidator is a validator group with following validators -// baseValidator -// signingRootValidator -// readyForSignaturesValidator -// should be called after sender signing the document and before requesting the document -func PreSignatureRequestValidator(centIDBytes, priv, pub []byte) documents.ValidatorGroup { - return documents.ValidatorGroup{ - baseValidator(), - signingRootValidator(), - readyForSignaturesValidator(centIDBytes, priv, pub), - } -} - -// PostSignatureRequestValidator is a validator group with following validators -// baseValidator -// signingRootValidator -// signaturesValidator -// should be called after the signature collection/before preparing for anchoring -func PostSignatureRequestValidator(idService identity.Service) documents.ValidatorGroup { - return documents.ValidatorGroup{ - baseValidator(), - signingRootValidator(), - signaturesValidator(idService), - } -} diff --git a/coredocument/validator_test.go b/coredocument/validator_test.go deleted file mode 100644 index d0b8fec53..000000000 --- a/coredocument/validator_test.go +++ /dev/null @@ -1,554 +0,0 @@ -// +build unit - -package coredocument - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestUpdateVersionValidator(t *testing.T) { - uvv := UpdateVersionValidator() - - // nil models - err := uvv.Validate(nil, nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "need both the old and new model") - - // old model pack core doc fail - old := mockModel{} - newM := mockModel{} - old.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = uvv.Validate(old, newM) - old.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch old core document") - - // newM model pack core doc fail - oldCD := New() - oldCD.DocumentRoot = utils.RandomSlice(32) - old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = uvv.Validate(old, newM) - old.AssertExpectations(t) - newM.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch new core document") - - // mismatched identifiers - newCD := New() - newCD.NextVersion = nil - old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(newCD, nil).Once() - err = uvv.Validate(old, newM) - old.AssertExpectations(t) - newM.AssertExpectations(t) - assert.Error(t, err) - assert.Equal(t, 5, errors.Len(err)) - - // success - newCD, err = PrepareNewVersion(*oldCD, nil) - assert.Nil(t, err) - old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(newCD, nil).Once() - err = uvv.Validate(old, newM) - old.AssertExpectations(t) - newM.AssertExpectations(t) - assert.Nil(t, err) -} - -func Test_getCoreDocument(t *testing.T) { - // nil document - cd, err := getCoreDocument(nil) - assert.Error(t, err) - assert.Nil(t, cd) - - // pack core document fail - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - cd, err = getCoreDocument(model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Nil(t, cd) - - // success - model = mockModel{} - cd = New() - model.On("PackCoreDocument").Return(cd, nil).Once() - got, err := getCoreDocument(model) - model.AssertExpectations(t) - assert.Nil(t, err) - assert.Equal(t, cd, got) -} - -func TestValidator_baseValidator(t *testing.T) { - bv := baseValidator() - - // fail getCoreDocument - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := bv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // failed validator - model = mockModel{} - cd := New() - model.On("PackCoreDocument").Return(cd, nil).Once() - err = bv.Validate(nil, model) - assert.Error(t, err) - assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[1].Error()) - - // success - model = mockModel{} - cd.DataRoot = utils.RandomSlice(32) - assert.Nil(t, FillSalts(cd)) - model.On("PackCoreDocument").Return(cd, nil).Once() - err = bv.Validate(nil, model) - assert.Nil(t, err) -} - -func TestValidator_signingRootValidator(t *testing.T) { - sv := signingRootValidator() - - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := sv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // missing signing_root - cd := New() - assert.Nil(t, FillSalts(cd)) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = sv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "signing root missing") - - // mismatch signing roots - cd.SigningRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = sv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "signing root mismatch") - - // success - tree, err := GetDocumentSigningTree(cd) - assert.Nil(t, err) - cd.SigningRoot = tree.RootHash() - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = sv.Validate(nil, model) - model.AssertExpectations(t) - assert.Nil(t, err) -} - -func TestValidator_documentRootValidator(t *testing.T) { - dv := documentRootValidator() - - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := dv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // missing document root - cd := New() - assert.Nil(t, FillSalts(cd)) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = dv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "document root missing") - - // mismatch signing roots - cd.DocumentRoot = utils.RandomSlice(32) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = dv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "document root mismatch") - - // success - tree, err := GetDocumentRootTree(cd) - assert.Nil(t, err) - cd.DocumentRoot = tree.RootHash() - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = dv.Validate(nil, model) - model.AssertExpectations(t) - assert.Nil(t, err) -} - -func TestValidator_selfSignatureValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) - idKeys := self.Keys[identity.KeyPurposeSigning] - rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) - - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := rfsv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // signature length mismatch - cd := New() - assert.Nil(t, FillSalts(cd)) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = rfsv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "expecting only one signature") - - // mismatch - cd.SigningRoot = utils.RandomSlice(32) - s := &coredocumentpb.Signature{ - Signature: utils.RandomSlice(32), - EntityId: utils.RandomSlice(6), - PublicKey: utils.RandomSlice(32), - } - cd.Signatures = append(cd.Signatures, s) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = rfsv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Equal(t, 3, errors.Len(err)) - - // success - cd.SigningRoot = utils.RandomSlice(32) - c, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = rfsv.Validate(nil, model) - model.AssertExpectations(t) - assert.Nil(t, err) -} - -func TestValidator_signatureValidator(t *testing.T) { - srv := &testingcommons.MockIDService{} - ssv := signaturesValidator(srv) - - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := ssv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // signature length mismatch - cd := New() - assert.Nil(t, FillSalts(cd)) - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = ssv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "atleast one signature expected") - - // failed validation - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("fail")).Once() - s := &coredocumentpb.Signature{EntityId: utils.RandomSlice(7)} - cd.Signatures = append(cd.Signatures, s) - err = ssv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "signature verification failed") - - // success - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - cd.SigningRoot = utils.RandomSlice(32) - cd.Signatures = []*coredocumentpb.Signature{{}} - - err = ssv.Validate(nil, model) - model.AssertExpectations(t) - srv.AssertExpectations(t) - assert.Nil(t, err) -} - -func TestPreAnchorValidator(t *testing.T) { - pav := PreAnchorValidator(nil) - assert.Len(t, pav, 2) -} - -type repo struct { - mock.Mock - anchors.AnchorRepository -} - -func (r repo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { - args := r.Called(anchorID) - docRoot, _ := args.Get(0).(anchors.DocumentRoot) - return docRoot, args.Error(1) -} - -func TestValidator_anchoredValidator(t *testing.T) { - av := anchoredValidator(repo{}) - - // fail get core document - err := av.Validate(nil, nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get core document") - - // failed anchorID - model := &mockModel{} - cd := &coredocumentpb.CoreDocument{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get anchorID") - - // failed docRoot - model = &mockModel{} - cd.CurrentVersion = utils.RandomSlice(32) - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get document root") - - // failed to get docRoot from chain - anchorID, err := anchors.ToAnchorID(utils.RandomSlice(32)) - assert.Nil(t, err) - r := &repo{} - av = anchoredValidator(r) - cd.CurrentVersion = anchorID[:] - r.On("GetDocumentRootOf", anchorID).Return(nil, errors.New("error")).Once() - cd.DocumentRoot = utils.RandomSlice(32) - model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) - model.AssertExpectations(t) - r.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get document root from chain") - - // mismatched doc roots - docRoot := anchors.RandomDocumentRoot() - r = &repo{} - av = anchoredValidator(r) - r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - cd.DocumentRoot = utils.RandomSlice(32) - model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) - model.AssertExpectations(t) - r.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "mismatched document roots") - - // success - r = &repo{} - av = anchoredValidator(r) - r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - cd.DocumentRoot = docRoot[:] - model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) - model.AssertExpectations(t) - r.AssertExpectations(t) - assert.Nil(t, err) -} - -func TestValidate_baseValidator(t *testing.T) { - tests := []struct { - doc *coredocumentpb.CoreDocument - key string - }{ - // empty salts in document - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - DataRoot: id5, - }, - key: "[cd_salts : Required field]", - }, - - // salts missing previous root - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - }, - }, - key: "[cd_salts : Required field]", - }, - - // missing identifiers in core document - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - PreviousRoot: id5, - }, - }, - key: "[cd_data_root : Required field]", - }, - - // missing identifiers in core document and salts - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - }, - }, - key: "[cd_data_root : Required field; cd_salts : Required field]", - }, - - // repeated identifiers - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id3, - DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - PreviousRoot: id5, - }, - }, - key: "[cd_overall : Identifier re-used]", - }, - - // repeated identifiers - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id2, - DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - PreviousRoot: id5, - }, - }, - key: "[cd_overall : Identifier re-used]", - }, - - // All okay - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - PreviousRoot: id5, - }, - }, - }, - } - - baseValidator := baseValidator() - - for _, c := range tests { - - model := mockModel{} - model.On("PackCoreDocument", mock.Anything).Return(c.doc, nil).Once() - - err := baseValidator.Validate(nil, &model) - if c.key == "" { - assert.Nil(t, err) - continue - } - - assert.Equal(t, c.key, err.Error()) - - } -} - -func TestPostAnchoredValidator(t *testing.T) { - pav := PostAnchoredValidator(nil, nil) - assert.Len(t, pav, 2) -} - -func TestPreSignatureRequestValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) - idKeys := self.Keys[identity.KeyPurposeSigning] - psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) - assert.Len(t, psv, 3) -} - -func TestPostSignatureRequestValidator(t *testing.T) { - psv := PostSignatureRequestValidator(nil) - assert.Len(t, psv, 3) -} - -func TestSignatureRequestValidator(t *testing.T) { - srv := SignatureRequestValidator(nil) - assert.Len(t, srv, 3) -} diff --git a/documents/anchor.go b/documents/anchor.go index 7eae900cc..9369af82d 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -3,13 +3,15 @@ package documents import ( "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" ) -// anchorProcessor has same methods to coredoc processor -// this is to avoid import cycles -// this will disappear once we have queueing logic in place -type anchorProcessor interface { +// AnchorProcessor identifies an implementation, which can do a bunch of things with a CoreDocument. +// E.g. send, anchor, etc. +type AnchorProcessor interface { + Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) PrepareForSignatureRequests(ctx context.Context, model Model) error RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error @@ -22,7 +24,7 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators -func AnchorDocument(ctx context.Context, model Model, proc anchorProcessor, updater updaterFunc) (Model, error) { +func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, updater updaterFunc) (Model, error) { cd, err := model.PackCoreDocument() if err != nil { return nil, err diff --git a/documents/anchor_task.go b/documents/anchor_task.go index e0d005b69..f4c959f8a 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -4,16 +4,13 @@ import ( "context" "fmt" - "github.com/centrifuge/go-centrifuge/queue" - - "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common/hexutil" @@ -37,9 +34,9 @@ type documentAnchorTask struct { // state config config.Service - processor anchorProcessor - modelGetFunc func(accountID, id []byte) (Model, error) - modelSaveFunc func(accountID, id []byte, model Model) error + processor AnchorProcessor + modelGetFunc func(tenantID, id []byte) (Model, error) + modelSaveFunc func(tenantID, id []byte, model Model) error } // TaskTypeName returns the name of the task. diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index 6bc96ea33..77a9104d5 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 58a845966..ed0b443af 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -1,9 +1,11 @@ package documents import ( + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" @@ -15,6 +17,9 @@ const ( // BootstrappedDocumentRepository is the key to the database repository of documents BootstrappedDocumentRepository = "BootstrappedDocumentRepository" + + // BootstrappedDocumentService is the key to bootstrapped document service + BootstrappedDocumentService = "BootstrappedDocumentService" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -22,12 +27,27 @@ type Bootstrapper struct{} // Bootstrap sets the required storage and registers func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - ctx[BootstrappedRegistry] = NewServiceRegistry() + registry := NewServiceRegistry() + ldb, ok := ctx[storage.BootstrappedDB].(storage.Repository) if !ok { return ErrDocumentBootstrap } - ctx[BootstrappedDocumentRepository] = NewDBRepository(ldb) + + repo := NewDBRepository(ldb) + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return errors.New("anchor repository not initialised") + } + + ctx[BootstrappedDocumentService] = DefaultService(repo, idService, anchorRepo, registry) + ctx[BootstrappedRegistry] = registry + ctx[BootstrappedDocumentRepository] = repo return nil } @@ -41,14 +61,14 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("config service not initialised") } - queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + cfg, ok := ctx[bootstrap.BootstrappedConfig].(Config) if !ok { - return errors.New("queue not initialised") + return errors.New("documents config not initialised") } - coreDocProc, ok := ctx[bootstrap.BootstrappedCoreDocProc].(anchorProcessor) + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) if !ok { - return errors.New("coredoc processor not initialised") + return errors.New("queue not initialised") } repo, ok := ctx[BootstrappedDocumentRepository].(Repository) @@ -56,12 +76,27 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("document repository not initialised") } + idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + if !ok { + return errors.New("identity service not initialised") + } + + anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + if !ok { + return errors.New("anchor repository not initialised") + } + + p2pClient, ok := ctx[bootstrap.BootstrappedPeer].(Client) + if !ok { + return errors.New("p2p client not initialised") + } + task := &documentAnchorTask{ BaseTask: transactions.BaseTask{ TxService: ctx[transactions.BootstrappedService].(transactions.Service), }, config: cfgService, - processor: coreDocProc, + processor: DefaultProcessor(idService, p2pClient, anchorRepo, cfg), modelGetFunc: repo.Get, modelSaveFunc: repo.Update, } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 822a9f1f2..affbedee8 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -5,12 +5,13 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/testingutils/anchors" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" @@ -24,8 +25,9 @@ func TestBootstrapper_Bootstrap(t *testing.T) { repo := leveldb.NewLevelDBRepository(db) ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo - ctx[bootstrap.BootstrappedQueueServer] = new(queue.Server) ctx[transactions.BootstrappedService] = transactions.NewService(transactions.NewRepository(repo)) + ctx[identity.BootstrappedIDService] = new(testingcommons.MockIDService) + ctx[anchors.BootstrappedAnchorRepo] = new(testinganchors.MockAnchorRepo) err = Bootstrapper{}.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRegistry]) diff --git a/documents/test/anchor_test.go b/documents/documents_test/anchor_test.go similarity index 67% rename from documents/test/anchor_test.go rename to documents/documents_test/anchor_test.go index 4764269e5..a8265240b 100644 --- a/documents/test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -3,34 +3,71 @@ package documents_test import ( + "context" "errors" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "os" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) -var ctx = map[string]interface{}{} -var cfg config.Configuration +type mockAnchorProcessor struct { + mock.Mock +} + +func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { + args := m.Called(coreDocument, ctx, recipient) + return args.Error(0) +} -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &config.Bootstrapper{}, +func (m *mockAnchorProcessor) Anchor( + ctx context.Context, + coreDocument *coredocumentpb.CoreDocument, + saveState func(*coredocumentpb.CoreDocument) error) (err error) { + args := m.Called(ctx, coreDocument, saveState) + if saveState != nil { + err := saveState(coreDocument) + if err != nil { + return err + } } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) + return args.Error(0) +} + +func (m *mockAnchorProcessor) PrepareForSignatureRequests(ctx context.Context, model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *mockAnchorProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { + args := m.Called(ctx, model) + return args.Error(0) +} + +func (m *mockAnchorProcessor) PrepareForAnchoring(model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *mockAnchorProcessor) AnchorDocument(ctx context.Context, model documents.Model) error { + args := m.Called(model) + return args.Error(0) +} + +func (m *mockAnchorProcessor) SendDocument(ctx context.Context, model documents.Model) error { + args := m.Called(ctx, model) + return args.Error(0) +} + +func (m *mockAnchorProcessor) GetDataProofHashes(coreDocument *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { + args := m.Called(coreDocument) + return args.Get(0).([][]byte), args.Error(1) } func TestAnchorDocument(t *testing.T) { @@ -52,7 +89,7 @@ func TestAnchorDocument(t *testing.T) { m = &testingdocuments.MockModel{} cd := coredocument.New() m.On("PackCoreDocument").Return(cd, nil).Once() - proc := &testingcoredocument.MockCoreDocumentProcessor{} + proc := &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) @@ -64,7 +101,7 @@ func TestAnchorDocument(t *testing.T) { // request signatures failed m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingcoredocument.MockCoreDocumentProcessor{} + proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) @@ -77,7 +114,7 @@ func TestAnchorDocument(t *testing.T) { // prepare for anchoring fails m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingcoredocument.MockCoreDocumentProcessor{} + proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(errors.New("error")).Once() @@ -91,7 +128,7 @@ func TestAnchorDocument(t *testing.T) { // anchor fails m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingcoredocument.MockCoreDocumentProcessor{} + proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() @@ -106,7 +143,7 @@ func TestAnchorDocument(t *testing.T) { // send failed m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingcoredocument.MockCoreDocumentProcessor{} + proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() @@ -122,7 +159,7 @@ func TestAnchorDocument(t *testing.T) { // success m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(cd, nil).Once() - proc = &testingcoredocument.MockCoreDocumentProcessor{} + proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() diff --git a/documents/genericdoc/service_test.go b/documents/documents_test/service_test.go similarity index 93% rename from documents/genericdoc/service_test.go rename to documents/documents_test/service_test.go index 1663d0dc3..52fcbd633 100644 --- a/documents/genericdoc/service_test.go +++ b/documents/documents_test/service_test.go @@ -1,22 +1,12 @@ // +build unit -package genericdoc_test +package documents_test import ( "math/big" "os" "testing" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/documents/invoice" - - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -24,10 +14,14 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -37,7 +31,7 @@ var testRepoGlobal documents.Repository var ( cid = identity.RandomCentID() centIDBytes = cid[:] - accountID = cid[:] + tenantID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) @@ -62,18 +56,18 @@ func TestMain(m *testing.M) { } func TestService_ReceiveAnchoredDocument(t *testing.T) { - poSrv := genericdoc.DefaultService(nil, nil, nil) + poSrv := documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) ctxh := testingconfig.CreateTenantContext(t, cfg) err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } -func getServiceWithMockedLayers() (genericdoc.Service, testingcommons.MockIDService) { +func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { repo := testRepo() idService := testingcommons.MockIDService{} idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) mockAnchor = &mockAnchorRepo{} - return genericdoc.DefaultService(repo, mockAnchor, &idService), idService + return documents.DefaultService(repo, &idService, mockAnchor, documents.NewServiceRegistry()), idService } type mockAnchorRepo struct { @@ -137,7 +131,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, } if !skipSave { - err = testRepo().Create(accountID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -175,7 +169,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv if err != nil { return nil, err } - err = testRepo().Create(accountID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) if err != nil { return nil, err } @@ -183,7 +177,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv } // Functions returns service mocks -func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s genericdoc.Service) testingcommons.MockIDService { +func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s documents.Service) testingcommons.MockIDService { idkey := ðid.EthereumIdentityKey{ Key: key1Pub, Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, @@ -217,7 +211,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) i.CoreDocument.SigningRoot = nil - err = testRepo().Update(accountID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) ctxh := testingconfig.CreateTenantContext(t, cfg) @@ -313,7 +307,7 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { }, } - err := testRepo().Create(accountID, version, inv) + err := testRepo().Create(tenantID, version, inv) currentVersion = version version = next assert.Nil(t, err) @@ -345,7 +339,7 @@ func TestService_GetVersion_successful(t *testing.T) { } ctxh := testingconfig.CreateTenantContext(t, cfg) - err := testRepo().Create(accountID, currentVersion, inv) + err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) mod, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) @@ -375,7 +369,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { }, } - err = testRepo().Create(accountID, documentIdentifier, inv) + err = testRepo().Create(tenantID, documentIdentifier, inv) assert.Nil(t, err) _, err = service.GetCurrentVersion(ctxh, documentIdentifier) @@ -401,7 +395,7 @@ func TestService_GetVersion_error(t *testing.T) { CurrentVersion: currentVersion, }, } - err = testRepo().Create(accountID, currentVersion, inv) + err = testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) //random version @@ -442,7 +436,7 @@ func TestService_Exists(t *testing.T) { }, } - err = testRepo().Create(accountID, documentIdentifier, inv) + err = testRepo().Create(tenantID, documentIdentifier, inv) exists := service.Exists(ctxh, documentIdentifier) assert.True(t, exists, "document should exist") diff --git a/documents/genericdoc/bootstrapper.go b/documents/genericdoc/bootstrapper.go deleted file mode 100644 index 0a235b0c2..000000000 --- a/documents/genericdoc/bootstrapper.go +++ /dev/null @@ -1,37 +0,0 @@ -package genericdoc - -import ( - "github.com/centrifuge/go-centrifuge/errors" - - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/identity" -) - -// Bootstrapper implements bootstrap.Bootstrapper. -type Bootstrapper struct{} - -// BootstrappedGenService is a key mapped to the generic document service -const BootstrappedGenService = "BootstrappedGenService " - -// Bootstrap sets the required storage and registers -func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - if !ok { - return errors.New("anchor repository not initialised") - } - - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) - if !ok { - return errors.New("identity service not initialised") - } - - repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) - if !ok { - return errors.New("document db repository not initialised") - } - - ctx[BootstrappedGenService] = DefaultService(repo, anchorRepo, idService) - return nil - -} diff --git a/documents/genericdoc/service.go b/documents/genericdoc/service.go deleted file mode 100644 index 8ce050833..000000000 --- a/documents/genericdoc/service.go +++ /dev/null @@ -1,256 +0,0 @@ -package genericdoc - -import ( - "bytes" - "context" - "time" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/notification" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes" - logging "github.com/ipfs/go-log" -) - -// Service provides an interface for generic document methods -type Service interface { - - // GetCurrentVersion reads a document from the database - GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) - - // Exists checks if a document exists - Exists(ctx context.Context, documentID []byte) bool - - // GetVersion reads a document from the database - GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) - - // CreateProofs creates proofs for the latest version document given the fields - CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) - - // CreateProofsForVersion creates proofs for a particular version of the document given the fields - CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) - - // RequestDocumentSignature Validates and Signs document received over the p2p layer - RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) - - // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB - ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error -} - -// service implements Service -type service struct { - repo documents.Repository - identityService identity.Service - notifier notification.Sender - anchorRepository anchors.AnchorRepository -} - -var srvLog = logging.Logger("document-service") - -// DefaultService returns the default implementation of the service -func DefaultService(repo documents.Repository, - anchorRepo anchors.AnchorRepository, idService identity.Service) Service { - return service{ - repo: repo, - anchorRepository: anchorRepo, - notifier: notification.NewWebhookSender(), - identityService: idService} -} - -func getIDs(model documents.Model) ([]byte, []byte, error) { - cd, err := model.PackCoreDocument() - - if err != nil { - return nil, nil, err - } - - return cd.DocumentIdentifier, cd.NextVersion, nil -} - -func (s service) searchVersion(ctx context.Context, m documents.Model) (documents.Model, error) { - id, next, err := getIDs(m) - - if err != nil { - return nil, err - } - - if s.Exists(ctx, next) { - nm, err := s.getVersion(ctx, id, next) - if err != nil { - - return nil, err - } - return s.searchVersion(ctx, nm) - } - - return m, nil - -} - -func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { - model, err := s.getVersion(ctx, documentID, documentID) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) - } - return s.searchVersion(ctx, model) - -} - -func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (documents.Model, error) { - return s.getVersion(ctx, documentID, version) -} - -func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.GetCurrentVersion(ctx, documentID) - if err != nil { - return nil, err - } - return s.createProofs(model, fields) - -} - -func (s service) createProofs(model documents.Model, fields []string) (*documents.DocumentProof, error) { - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - coreDoc, proofs, err := model.CreateProofs(fields) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentProof, err) - } - return &documents.DocumentProof{ - DocumentID: coreDoc.DocumentIdentifier, - VersionID: coreDoc.CurrentVersion, - FieldProofs: proofs, - }, nil - -} - -func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*documents.DocumentProof, error) { - model, err := s.getVersion(ctx, documentID, version) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) - } - return s.createProofs(model, fields) -} - -func (s service) RequestDocumentSignature(ctx context.Context, model documents.Model) (*coredocumentpb.Signature, error) { - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigAccountID - } - - if err := coredocument.SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - doc, err := model.PackCoreDocument() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - - idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] - if !ok { - return nil, errors.NewTypedError(documents.ErrDocumentSigning, errors.New("missing signing key")) - } - sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) - doc.Signatures = append(doc.Signatures, sig) - err = model.UnpackCoreDocument(doc) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) - } - - accountID := idConf.ID[:] - - // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(accountID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(accountID, doc.DocumentIdentifier, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - } - - err = s.repo.Create(accountID, doc.CurrentVersion, model) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) - return sig, nil -} - -func (s service) ReceiveAnchoredDocument(ctx context.Context, model documents.Model, senderID []byte) error { - idConf, err := contextutil.Self(ctx) - if err != nil { - return documents.ErrDocumentConfigAccountID - } - - if err := coredocument.PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { - return errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - - doc, err := model.PackCoreDocument() - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - err = s.repo.Update(idConf.ID[:], doc.CurrentVersion, model) - if err != nil { - return errors.NewTypedError(documents.ErrDocumentPersistence, err) - } - - ts, _ := ptypes.TimestampProto(time.Now().UTC()) - notificationMsg := ¬ificationpb.NotificationMessage{ - EventType: uint32(notification.ReceivedPayload), - AccountId: idConf.ID.String(), - FromId: hexutil.Encode(senderID), - ToId: idConf.ID.String(), - Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentId: hexutil.Encode(doc.DocumentIdentifier), - } - - // Async until we add queuing - go s.notifier.Send(ctx, notificationMsg) - - return nil -} - -func (s service) Exists(ctx context.Context, documentID []byte) bool { - idConf, err := contextutil.Self(ctx) - if err != nil { - return false - } - return s.repo.Exists(idConf.ID[:], documentID) -} - -func (s service) getVersion(ctx context.Context, documentID, version []byte) (documents.Model, error) { - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigAccountID - } - model, err := s.repo.Get(idConf.ID[:], version) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, err) - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - - if !bytes.Equal(cd.DocumentIdentifier, documentID) { - return nil, errors.NewTypedError(documents.ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) - } - return model, nil -} diff --git a/documents/genericdoc/test_bootstrapper.go b/documents/genericdoc/test_bootstrapper.go deleted file mode 100644 index 07c5819bf..000000000 --- a/documents/genericdoc/test_bootstrapper.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build integration unit - -package genericdoc - -func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { - return b.Bootstrap(context) -} - -func (*Bootstrapper) TestTearDown() error { - return nil -} diff --git a/documents/handler_test.go b/documents/handler_test.go index 08782e903..2a2f6a4c6 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -5,10 +5,9 @@ package documents_test import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index b792a6192..6c846a04a 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -2,16 +2,19 @@ package invoice import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" ) +const ( + // BootstrappedInvoiceHandler maps to grpc handler for invoices + BootstrappedInvoiceHandler string = "BootstrappedInvoiceHandler" +) + // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} @@ -22,14 +25,9 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("service registry not initialised") } - anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + docSrv, ok := ctx[documents.BootstrappedDocumentService].(documents.Service) if !ok { - return errors.New("anchor repository not initialised") - } - - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) - if !ok { - return errors.New("identity service not initialised") + return errors.New("document service not initialised") } repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) @@ -48,19 +46,22 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transaction service not initialised") } - genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + cfgSrv, ok := ctx[config.BootstrappedConfigStorage].(config.Service) if !ok { - return errors.New("generic service is not initialised") + return errors.New("config service not initialised") } + // register service srv := DefaultService( + docSrv, repo, - anchorRepo, - idService, queueSrv, txService, genService) + queueSrv, txService) + err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { return errors.New("failed to register invoice service: %v", err) } + ctx[BootstrappedInvoiceHandler] = GRPCHandler(cfgSrv, srv) return nil } diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index ba9d43321..0e787e324 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -4,9 +4,7 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/documents" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" @@ -23,16 +21,11 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of invoice.DocumentServiceServer -func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (clientinvoicepb.DocumentServiceServer, error) { - srv, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) - if err != nil { - return nil, err - } - +func GRPCHandler(config config.Service, srv Service) clientinvoicepb.DocumentServiceServer { return &grpcHandler{ - service: srv.(Service), + service: srv, config: config, - }, nil + } } // Create handles the creation of the invoices and anchoring the documents on chain diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index d8f2b970a..e7b156892 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -8,7 +8,6 @@ import ( "reflect" "testing" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -60,9 +59,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, - &genericdoc.Bootstrapper{}, + documents.PostBootstrapper{}, &Bootstrapper{}, &queue.Starter{}, } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index a48f15849..9821af454 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -3,26 +3,19 @@ package invoice import ( "context" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/notification" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" - logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) -var srvLog = logging.Logger("invoice-service") - // Service defines specific functions for invoice type Service interface { documents.Service @@ -33,12 +26,6 @@ type Service interface { // DeriveFromUpdatePayload derives invoice model from update payload DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) - // Create validates and persists invoice Model and returns a Updated model - Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) - - // Update validates and updates the invoice model and return the updated model - Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) - // DeriveInvoiceData returns the invoice data as client data DeriveInvoiceData(inv documents.Model) (*clientinvoicepb.InvoiceData, error) @@ -49,32 +36,24 @@ type Service interface { // service implements Service and handles all invoice related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - repo documents.Repository - notifier notification.Sender - anchorRepository anchors.AnchorRepository - identityService identity.Service - queueSrv queue.TaskQueuer - txService transactions.Service - genericdoc.Service + documents.Service + repo documents.Repository + queueSrv queue.TaskQueuer + txService transactions.Service } // DefaultService returns the default implementation of the service. func DefaultService( + srv documents.Service, repo documents.Repository, - anchorRepository anchors.AnchorRepository, - identityService identity.Service, queueSrv queue.TaskQueuer, txService transactions.Service, - genService genericdoc.Service, ) Service { return service{ - repo: repo, - notifier: notification.NewWebhookSender(), - anchorRepository: anchorRepository, - identityService: identityService, - queueSrv: queueSrv, - txService: txService, - Service: genService, + repo: repo, + queueSrv: queueSrv, + txService: txService, + Service: srv, } } @@ -205,34 +184,6 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return inv, txID, nil } -func (s service) checkType(model documents.Model) (documents.Model, error) { - _, ok := model.(*Invoice) - if !ok { - return nil, documents.ErrDocumentInvalidType - } - return model, nil -} - -// GetVersion returns an invoice for a given version -func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (model documents.Model, err error) { - model, err = s.Service.GetVersion(ctx, documentID, version) - if err != nil { - return nil, err - } - return s.checkType(model) - -} - -// GetCurrentVersion returns the last known version of an invoice -func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (model documents.Model, err error) { - model, err = s.Service.GetCurrentVersion(ctx, documentID) - if err != nil { - return nil, err - } - return s.checkType(model) - -} - // DeriveInvoiceResponse returns create response from invoice model func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.InvoiceResponse, error) { cd, err := doc.PackCoreDocument() @@ -320,15 +271,3 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv return inv, nil } - -// Exists checks if an invoice exists -func (s service) Exists(ctx context.Context, documentID []byte) bool { - if s.Service.Exists(ctx, documentID) { - // check if document is an invoice - _, err := s.Service.GetCurrentVersion(ctx, documentID) - if err == nil { - return true - } - } - return false -} diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index cc0006dc6..73d7f5e82 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -5,28 +5,23 @@ package invoice import ( "testing" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/documents/purchaseorder" - - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/gocelery" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -54,7 +49,7 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D func TestDefaultService(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil).Once() - srv := DefaultService(testRepo(), nil, nil, nil, nil, nil) + srv := DefaultService(nil, testRepo(), nil, nil) assert.NotNil(t, srv, "must be non-nil") } @@ -68,12 +63,12 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { repo := testRepo() mockAnchor := &mockAnchorRepo{} - genService := genericdoc.DefaultService(repo, mockAnchor, &idService) + docSrv := documents.DefaultService(repo, &idService, mockAnchor, documents.NewServiceRegistry()) return idService, DefaultService( + docSrv, repo, - mockAnchor, &idService, queueSrv, - ctx[transactions.BootstrappedService].(transactions.Service), genService) + ctx[transactions.BootstrappedService].(transactions.Service)) } func createMockDocument() (*Invoice, error) { diff --git a/documents/invoice/validator.go b/documents/invoice/validator.go index 37622f602..685f04633 100644 --- a/documents/invoice/validator.go +++ b/documents/invoice/validator.go @@ -1,7 +1,6 @@ package invoice import ( - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" @@ -80,6 +79,6 @@ func UpdateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), dataRootValidator(), - coredocument.UpdateVersionValidator(), + documents.UpdateVersionValidator(), } } diff --git a/documents/model.go b/documents/model.go index baa37f92e..66b9c8d35 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,10 +1,9 @@ package documents import ( + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/precise-proofs/proofs/proto" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" ) // Model is an interface to abstract away model specificness like invoice or purchaseOrder diff --git a/documents/model_test.go b/documents/model_test.go index a483b4df2..2dc922277 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -6,6 +6,9 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/anchors" + + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -20,10 +23,15 @@ import ( "github.com/centrifuge/go-centrifuge/transactions" ) -var ctx = map[string]interface{}{} +var ctx map[string]interface{} var ConfigService config.Service +var cfg config.Configuration func TestMain(m *testing.M) { + ctx = make(map[string]interface{}) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -31,11 +39,17 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, transactions.Bootstrapper{}, &queue.Bootstrapper{}, + &anchors.Bootstrapper{}, &Bootstrapper{}, } ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/coredocument/processor.go b/documents/processor.go similarity index 82% rename from coredocument/processor.go rename to documents/processor.go index 5a618c685..73250f3e0 100644 --- a/coredocument/processor.go +++ b/documents/processor.go @@ -1,59 +1,47 @@ -package coredocument +package documents import ( "context" "time" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" - "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" - logging "github.com/ipfs/go-log" ) -var log = logging.Logger("coredocument") - -// Config defines required methods required for the coredocument package. +// Config defines required methods required for the documents package. type Config interface { GetNetworkID() uint32 GetIdentityID() ([]byte, error) GetP2PConnectionTimeout() time.Duration } -// Processor identifies an implementation, which can do a bunch of things with a CoreDocument. -// E.g. send, anchor, etc. -type Processor interface { - Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) - PrepareForSignatureRequests(ctx context.Context, model documents.Model) error - RequestSignatures(ctx context.Context, model documents.Model) error - PrepareForAnchoring(model documents.Model) error - AnchorDocument(ctx context.Context, model documents.Model) error - SendDocument(ctx context.Context, model documents.Model) error -} +// Client defines methods that can be implemented by any type handling p2p communications. +type Client interface { -// client defines the methods for p2pclient -// we redefined it here so that we can avoid cyclic dependencies with p2p -type client interface { + // GetSignaturesForDocument gets the signatures for document GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + + // after all signatures are collected the sender sends the document including the signatures SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) } -// defaultProcessor implements Processor interface +// defaultProcessor implements AnchorProcessor interface type defaultProcessor struct { identityService identity.Service - p2pClient client + p2pClient Client anchorRepository anchors.AnchorRepository config Config } -// DefaultProcessor returns the default implementation of CoreDocument Processor -func DefaultProcessor(idService identity.Service, p2pClient client, repository anchors.AnchorRepository, config Config) Processor { +// DefaultProcessor returns the default implementation of CoreDocument AnchorProcessor +func DefaultProcessor(idService identity.Service, p2pClient Client, repository anchors.AnchorRepository, config Config) AnchorProcessor { return defaultProcessor{ identityService: idService, p2pClient: p2pClient, @@ -85,14 +73,14 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp } // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature -func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } // calculate the signing root - err = CalculateSigningRoot(cd) + err = coredocument.CalculateSigningRoot(cd) if err != nil { return errors.New("failed to calculate signing root: %v", err) } @@ -115,7 +103,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, mode // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, -func (dp defaultProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -151,7 +139,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model document } // PrepareForAnchoring validates the signatures and generates the document root -func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { +func (dp defaultProcessor) PrepareForAnchoring(model Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -163,7 +151,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { return errors.New("failed to validate signatures: %v", err) } - err = CalculateDocumentRoot(cd) + err = coredocument.CalculateDocumentRoot(cd) if err != nil { return errors.New("failed to generate document root: %v", err) } @@ -177,7 +165,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model documents.Model) error { } // AnchorDocument validates the model, and anchors the document -func (dp defaultProcessor) AnchorDocument(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -232,7 +220,7 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model documents.M } // SendDocument does post anchor validations and sends the document to collaborators -func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Model) error { +func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error { cd, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) @@ -249,7 +237,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model documents.Mod return err } - extCollaborators, err := GetExternalCollaborators(self.ID, cd) + extCollaborators, err := coredocument.GetExternalCollaborators(self.ID, cd) if err != nil { return errors.New("get external collaborators failed: %v", err) } diff --git a/coredocument/processor_test.go b/documents/processor_test.go similarity index 94% rename from coredocument/processor_test.go rename to documents/processor_test.go index 96484e352..cd3e21558 100644 --- a/coredocument/processor_test.go +++ b/documents/processor_test.go @@ -1,21 +1,19 @@ // +build unit -package coredocument +package documents import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" @@ -31,7 +29,7 @@ func TestCoreDocumentProcessor_SendNilDocument(t *testing.T) { type mockModel struct { mock.Mock - documents.Model + Model } func (m mockModel) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { @@ -63,13 +61,13 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // failed to get id pub, _ := cfg.GetSigningKeyPair() cfg.Set("keys.signing.publicKey", "wrong path") - cd = New() + cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, FillSalts(cd)) + assert.Nil(t, coredocument.FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() cfg.Set("keys.signing.publicKey", pub) @@ -80,9 +78,9 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() err = dp.PrepareForSignatureRequests(ctxh, model) - model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unpack the core document") + model.AssertExpectations(t) // success cd.Signatures = nil @@ -101,7 +99,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { type p2pClient struct { mock.Mock - client + Client } func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { @@ -131,13 +129,13 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { assert.Contains(t, err.Error(), "failed to validate model for signature request") // failed signature collection - cd = New() + cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, FillSalts(cd)) + assert.Nil(t, coredocument.FillSalts(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() @@ -202,14 +200,14 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { assert.Contains(t, err.Error(), "failed to validate signatures") // failed unpack - cd = New() + cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, FillSalts(cd)) - err = CalculateSigningRoot(cd) + assert.Nil(t, coredocument.FillSalts(cd)) + err = coredocument.CalculateSigningRoot(cd) assert.Nil(t, err) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) @@ -278,21 +276,21 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Contains(t, err.Error(), "pre anchor validation failed") // get ID failed - cd = New() + cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, FillSalts(cd)) - assert.Nil(t, CalculateSigningRoot(cd)) + assert.Nil(t, coredocument.FillSalts(cd)) + assert.Nil(t, coredocument.CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, CalculateDocumentRoot(cd)) + assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) assert.Nil(t, err) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() oldID := cfg.GetString("identityId") @@ -371,22 +369,22 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { assert.Contains(t, err.Error(), "post anchor validations failed") // failed send - cd = New() + cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } cd.Collaborators = [][]byte{[]byte("some id")} - assert.Nil(t, FillSalts(cd)) - assert.Nil(t, CalculateSigningRoot(cd)) + assert.Nil(t, coredocument.FillSalts(cd)) + assert.Nil(t, coredocument.CalculateSigningRoot(cd)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(6) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, CalculateDocumentRoot(cd)) + assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) assert.Nil(t, err) repo := mockRepo{} diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index a06d9ba9a..f2c10f89a 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -2,34 +2,32 @@ package purchaseorder import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" ) +const ( + // BootstrappedPOHandler maps to grc handler for PO + BootstrappedPOHandler = "BootstrappedPOHandler" +) + // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} // Bootstrap initialises required services for purchaseorder. func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - if !ok { - return errors.New("service registry not initialised") - } - - anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) + docSrv, ok := ctx[documents.BootstrappedDocumentService].(documents.Service) if !ok { - return errors.New("anchor repository not initialised") + return errors.New("document service not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) if !ok { - return errors.New("identity service not initialised") + return errors.New("service registry not initialised") } repo, ok := ctx[documents.BootstrappedDocumentRepository].(documents.Repository) @@ -48,17 +46,19 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transaction service not initialised") } - genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) + cfgSrv, ok := ctx[config.BootstrappedConfigStorage].(config.Service) if !ok { - return errors.New("generic service is not initialised") + return errors.New("config service not initialised") } // register service - srv := DefaultService(repo, anchorRepo, idService, queueSrv, txService, genService) + srv := DefaultService(docSrv, repo, queueSrv, txService) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") } + ctx[BootstrappedPOHandler] = GRPCHandler(cfgSrv, srv) + return nil } diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 7d550d834..72be3f60b 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -1,13 +1,9 @@ package purchaseorder import ( + "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/errors" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" @@ -24,16 +20,11 @@ type grpcHandler struct { } // GRPCHandler returns an implementation of the purchaseorder DocumentServiceServer -func GRPCHandler(config config.Service, registry *documents.ServiceRegistry) (clientpurchaseorderpb.DocumentServiceServer, error) { - srv, err := registry.LocateService(documenttypes.PurchaseOrderDataTypeUrl) - if err != nil { - return nil, errors.New("failed to fetch purchase order service") - } - +func GRPCHandler(config config.Service, srv Service) clientpurchaseorderpb.DocumentServiceServer { return grpcHandler{ - service: srv.(Service), + service: srv, config: config, - }, nil + } } // Create validates the purchase order, persists it to DB, and anchors it the chain diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 869eff2e2..d606a7fba 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -8,7 +8,6 @@ import ( "reflect" "testing" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -60,8 +59,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - &genericdoc.Bootstrapper{}, p2p.Bootstrapper{}, + documents.PostBootstrapper{}, &Bootstrapper{}, &queue.Starter{}, } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 38201a672..7165692ba 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -3,26 +3,19 @@ package purchaseorder import ( "context" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/notification" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" - logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" ) -var srvLog = logging.Logger("po-service") - // Service defines specific functions for purchase order type Service interface { documents.Service @@ -33,12 +26,6 @@ type Service interface { // DeriveFromUpdatePayload derives purchase order from update payload DeriveFromUpdatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderUpdatePayload) (documents.Model, error) - // Create validates and persists purchase order and returns a Updated model - Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) - - // Update validates and updates the purchase order and return the updated model - Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) - // DerivePurchaseOrderData returns the purchase order data as client data DerivePurchaseOrderData(po documents.Model) (*clientpopb.PurchaseOrderData, error) @@ -49,32 +36,24 @@ type Service interface { // service implements Service and handles all purchase order related persistence and validations // service always returns errors of type `errors.Error` or `errors.TypedError` type service struct { - repo documents.Repository - notifier notification.Sender - anchorRepository anchors.AnchorRepository - identityService identity.Service - queueSrv queue.TaskQueuer - txService transactions.Service - genericdoc.Service + documents.Service + repo documents.Repository + queueSrv queue.TaskQueuer + txService transactions.Service } // DefaultService returns the default implementation of the service func DefaultService( + srv documents.Service, repo documents.Repository, - anchorRepository anchors.AnchorRepository, - identityService identity.Service, queueSrv queue.TaskQueuer, txService transactions.Service, - genService genericdoc.Service, ) Service { return service{ - repo: repo, - notifier: notification.NewWebhookSender(), - anchorRepository: anchorRepository, - identityService: identityService, - queueSrv: queueSrv, - txService: txService, - Service: genService, + repo: repo, + queueSrv: queueSrv, + txService: txService, + Service: srv, } } @@ -283,42 +262,3 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P Data: data, }, nil } - -func (s service) checkType(model documents.Model) (documents.Model, error) { - _, ok := model.(*PurchaseOrder) - if !ok { - return nil, documents.ErrDocumentInvalidType - } - return model, nil -} - -// GetLastVersion returns the latest version of the document -func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (model documents.Model, err error) { - model, err = s.Service.GetCurrentVersion(ctx, documentID) - if err != nil { - return nil, err - } - return s.checkType(model) -} - -// GetVersion returns the specific version of the document -func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (model documents.Model, err error) { - model, err = s.Service.GetVersion(ctx, documentID, version) - if err != nil { - return nil, err - } - return s.checkType(model) - -} - -// Exists checks if an purchase order exists -func (s service) Exists(ctx context.Context, documentID []byte) bool { - if s.Service.Exists(ctx, documentID) { - // check if document is an po - _, err := s.Service.GetCurrentVersion(ctx, documentID) - if err == nil { - return true - } - } - return false -} diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 38bdcc29e..f06314017 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -5,20 +5,17 @@ package purchaseorder import ( "testing" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -35,8 +32,6 @@ var ( cid = identity.RandomCentID() accountID = cid[:] centIDBytes = cid[:] - key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) type mockAnchorRepo struct { @@ -58,9 +53,8 @@ func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { txService := ctx[transactions.BootstrappedService].(transactions.Service) repo := testRepo() mockAnchor := &mockAnchorRepo{} - genService := genericdoc.DefaultService(repo, mockAnchor, idService) - - return idService, DefaultService(repo, mockAnchor, idService, queueSrv, txService, genService) + docSrv := documents.DefaultService(repo, idService, mockAnchor, documents.NewServiceRegistry()) + return idService, DefaultService(docSrv, repo, queueSrv, txService) } func TestService_Update(t *testing.T) { diff --git a/documents/purchaseorder/validator.go b/documents/purchaseorder/validator.go index bba33373b..e821e1014 100644 --- a/documents/purchaseorder/validator.go +++ b/documents/purchaseorder/validator.go @@ -1,7 +1,6 @@ package purchaseorder import ( - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" @@ -80,6 +79,6 @@ func UpdateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), dataRootValidator(), - coredocument.UpdateVersionValidator(), + documents.UpdateVersionValidator(), } } diff --git a/documents/service.go b/documents/service.go index 1c60461da..3a1e14a35 100644 --- a/documents/service.go +++ b/documents/service.go @@ -1,10 +1,25 @@ package documents import ( + "bytes" "context" + "time" + + "github.com/satori/go.uuid" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/notification" + "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/ptypes" + logging "github.com/ipfs/go-log" ) // DocumentProof is a value to represent a document and its field proofs @@ -41,4 +56,263 @@ type Service interface { // ReceiveAnchoredDocument receives a new anchored document over the p2p layer, validates and updates the document in DB ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error + + // Create validates and persists Model and returns a Updated model + Create(ctx context.Context, model Model) (Model, uuid.UUID, error) + + // Update validates and updates the model and return the updated model + Update(ctx context.Context, model Model) (Model, uuid.UUID, error) +} + +// service implements Service +type service struct { + repo Repository + identityService identity.Service + notifier notification.Sender + anchorRepository anchors.AnchorRepository + registry *ServiceRegistry +} + +var srvLog = logging.Logger("document-service") + +// DefaultService returns the default implementation of the service +func DefaultService( + repo Repository, + idService identity.Service, + anchorRepo anchors.AnchorRepository, + registry *ServiceRegistry) Service { + return service{ + repo: repo, + anchorRepository: anchorRepo, + notifier: notification.NewWebhookSender(), + identityService: idService, + registry: registry, + } +} + +func getIDs(model Model) ([]byte, []byte, error) { + cd, err := model.PackCoreDocument() + if err != nil { + return nil, nil, err + } + + return cd.DocumentIdentifier, cd.NextVersion, nil +} + +func (s service) searchVersion(ctx context.Context, m Model) (Model, error) { + id, next, err := getIDs(m) + if err != nil { + return nil, err + } + + if s.Exists(ctx, next) { + nm, err := s.getVersion(ctx, id, next) + if err != nil { + + return nil, err + } + return s.searchVersion(ctx, nm) + } + + return m, nil + +} + +func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (Model, error) { + model, err := s.getVersion(ctx, documentID, documentID) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentNotFound, err) + } + return s.searchVersion(ctx, model) + +} + +func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (Model, error) { + return s.getVersion(ctx, documentID, version) +} + +func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []string) (*DocumentProof, error) { + model, err := s.GetCurrentVersion(ctx, documentID) + if err != nil { + return nil, err + } + return s.createProofs(model, fields) + +} + +func (s service) createProofs(model Model, fields []string) (*DocumentProof, error) { + if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + return nil, errors.NewTypedError(ErrDocumentInvalid, err) + } + coreDoc, proofs, err := model.CreateProofs(fields) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentProof, err) + } + return &DocumentProof{ + DocumentID: coreDoc.DocumentIdentifier, + VersionID: coreDoc.CurrentVersion, + FieldProofs: proofs, + }, nil + +} + +func (s service) CreateProofsForVersion(ctx context.Context, documentID, version []byte, fields []string) (*DocumentProof, error) { + model, err := s.getVersion(ctx, documentID, version) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentNotFound, err) + } + return s.createProofs(model, fields) +} + +func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*coredocumentpb.Signature, error) { + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, ErrDocumentConfigAccountID + } + + if err := SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { + return nil, errors.NewTypedError(ErrDocumentInvalid, err) + } + + doc, err := model.PackCoreDocument() + if err != nil { + return nil, errors.NewTypedError(ErrDocumentPackingCoreDocument, err) + } + + srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) + + idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] + if !ok { + return nil, errors.NewTypedError(ErrDocumentSigning, errors.New("missing signing key")) + } + sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) + doc.Signatures = append(doc.Signatures, sig) + err = model.UnpackCoreDocument(doc) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentUnPackingCoreDocument, err) + } + + tenantID := idConf.ID[:] + + // Logic for receiving version n (n > 1) of the document for the first time + if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { + err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentPersistence, err) + } + } + + err = s.repo.Create(tenantID, doc.CurrentVersion, model) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentPersistence, err) + } + + srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) + return sig, nil +} + +func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error { + idConf, err := contextutil.Self(ctx) + if err != nil { + return ErrDocumentConfigAccountID + } + + if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + return errors.NewTypedError(ErrDocumentInvalid, err) + } + + doc, err := model.PackCoreDocument() + if err != nil { + return errors.NewTypedError(ErrDocumentPackingCoreDocument, err) + } + + err = s.repo.Update(idConf.ID[:], doc.CurrentVersion, model) + if err != nil { + return errors.NewTypedError(ErrDocumentPersistence, err) + } + + ts, _ := ptypes.TimestampProto(time.Now().UTC()) + notificationMsg := ¬ificationpb.NotificationMessage{ + EventType: uint32(notification.ReceivedPayload), + AccountId: idConf.ID.String(), + FromId: hexutil.Encode(senderID), + ToId: idConf.ID.String(), + Recorded: ts, + DocumentType: doc.EmbeddedData.TypeUrl, + DocumentId: hexutil.Encode(doc.DocumentIdentifier), + } + + // Async until we add queuing + go s.notifier.Send(ctx, notificationMsg) + + return nil +} + +func (s service) Exists(ctx context.Context, documentID []byte) bool { + idConf, err := contextutil.Self(ctx) + if err != nil { + return false + } + return s.repo.Exists(idConf.ID[:], documentID) +} + +func (s service) getVersion(ctx context.Context, documentID, version []byte) (Model, error) { + idConf, err := contextutil.Self(ctx) + if err != nil { + return nil, ErrDocumentConfigAccountID + } + model, err := s.repo.Get(idConf.ID[:], version) + if err != nil { + return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + if !bytes.Equal(cd.DocumentIdentifier, documentID) { + return nil, errors.NewTypedError(ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) + } + return model, nil +} + +func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) { + if cd == nil || cd.EmbeddedData == nil { + return nil, errors.New("core document is nil") + } + + srv, err := s.registry.LocateService(cd.EmbeddedData.TypeUrl) + if err != nil { + return nil, err + } + + return srv.DeriveFromCoreDocument(cd) +} + +func (s service) Create(ctx context.Context, model Model) (Model, uuid.UUID, error) { + srv, err := s.getService(model) + if err != nil { + return nil, uuid.Nil, errors.New("failed to get service: %v", err) + } + + return srv.Create(ctx, model) +} + +func (s service) Update(ctx context.Context, model Model) (Model, uuid.UUID, error) { + srv, err := s.getService(model) + if err != nil { + return nil, uuid.Nil, errors.New("failed to get service: %v", err) + } + + return srv.Update(ctx, model) +} + +func (s service) getService(model Model) (Service, error) { + cd, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + return s.registry.LocateService(cd.EmbeddedData.TypeUrl) } diff --git a/documents/test_bootstrapper.go b/documents/test_bootstrapper.go index 78a113f9f..09514d8ef 100644 --- a/documents/test_bootstrapper.go +++ b/documents/test_bootstrapper.go @@ -7,14 +7,10 @@ import ( "github.com/centrifuge/go-centrifuge/storage" ) -// initialized ONLY for tests -var testLevelDB Repository - func (b Bootstrapper) TestBootstrap(context map[string]interface{}) error { if _, ok := context[storage.BootstrappedDB]; !ok { return errors.New("initializing LevelDB repository failed") } - testLevelDB = NewDBRepository(context[storage.BootstrappedDB].(storage.Repository)) return b.Bootstrap(context) } diff --git a/documents/validator.go b/documents/validator.go index d2256d06e..e01c1013d 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -1,8 +1,17 @@ package documents import ( + "fmt" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" ) // Validator is an interface every Validator (atomic or group) should implement @@ -39,3 +48,340 @@ type ValidatorFunc func(old, new Model) error func (vf ValidatorFunc) Validate(old, new Model) error { return vf(old, new) } + +// UpdateVersionValidator validates if the new core document is properly derived from old one +func UpdateVersionValidator() Validator { + return ValidatorFunc(func(old, new Model) error { + if old == nil || new == nil { + return errors.New("need both the old and new model") + } + + oldCD, err := old.PackCoreDocument() + if err != nil { + return errors.New("failed to fetch old core document: %v", err) + } + + newCD, err := new.PackCoreDocument() + if err != nil { + return errors.New("failed to fetch new core document: %v", err) + } + + checks := []struct { + name string + a, b []byte + }{ + { + name: "cd_document_identifier", + a: oldCD.DocumentIdentifier, + b: newCD.DocumentIdentifier, + }, + + { + name: "cd_previous_version", + a: oldCD.CurrentVersion, + b: newCD.PreviousVersion, + }, + + { + name: "cd_current_version", + a: oldCD.NextVersion, + b: newCD.CurrentVersion, + }, + + { + name: "cd_previous_version", + a: oldCD.DocumentRoot, + b: newCD.PreviousRoot, + }, + } + + for _, c := range checks { + if !utils.CheckMultiple32BytesFilled(c.a, c.b) { + err = errors.AppendError(err, NewError(c.name, "missing identifiers")) + continue + } + + if !utils.IsSameByteSlice(c.a, c.b) { + err = errors.AppendError(err, NewError(c.name, "mismatched")) + } + } + + if utils.IsEmptyByteSlice(newCD.NextVersion) { + err = errors.AppendError(err, NewError("cd_next_version", centerrors.RequiredField)) + } + + return err + }) +} + +// getCoreDocument takes an model and returns the core document of the model +func getCoreDocument(model Model) (*coredocumentpb.CoreDocument, error) { + if model == nil { + return nil, errors.New("nil model") + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, errors.New("failed to pack core document: %v", err) + } + + return cd, nil +} + +// baseValidator validates the core document basic fields like identifier, versions, and salts +func baseValidator() Validator { + return ValidatorFunc(func(_, model Model) error { + cd, err := getCoreDocument(model) + if err != nil { + return err + } + + if cd == nil { + return errors.New("nil document") + } + + if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { + err = errors.AppendError(err, NewError("cd_identifier", centerrors.RequiredField)) + } + + if utils.IsEmptyByteSlice(cd.CurrentVersion) { + err = errors.AppendError(err, NewError("cd_current_version", centerrors.RequiredField)) + } + + if utils.IsEmptyByteSlice(cd.NextVersion) { + err = errors.AppendError(err, NewError("cd_next_version", centerrors.RequiredField)) + } + + if utils.IsEmptyByteSlice(cd.DataRoot) { + err = errors.AppendError(err, NewError("cd_data_root", centerrors.RequiredField)) + } + + // double check the identifiers + isSameBytes := utils.IsSameByteSlice + + // Problem (re-using an old identifier for NextVersion): CurrentVersion or DocumentIdentifier same as NextVersion + if isSameBytes(cd.NextVersion, cd.DocumentIdentifier) || + isSameBytes(cd.NextVersion, cd.CurrentVersion) { + err = errors.AppendError(err, NewError("cd_overall", centerrors.IdentifierReUsed)) + } + + // lets not do verbose check like earlier since these will be + // generated by us mostly + salts := cd.CoredocumentSalts + if salts == nil || + !utils.CheckMultiple32BytesFilled( + salts.CurrentVersion, + salts.NextVersion, + salts.DocumentIdentifier, + salts.PreviousRoot) { + err = errors.AppendError(err, NewError("cd_salts", centerrors.RequiredField)) + } + + return err + }) +} + +// signingRootValidator checks the existence of signing root +// recalculates the signing root and compares with existing one +func signingRootValidator() Validator { + return ValidatorFunc(func(_, model Model) error { + cd, err := getCoreDocument(model) + if err != nil { + return err + } + + if utils.IsEmptyByteSlice(cd.SigningRoot) { + return errors.New("signing root missing") + } + + tree, err := coredocument.GetDocumentSigningTree(cd) + if err != nil { + return errors.New("failed to calculate signing root: %v", err) + } + + if !utils.IsSameByteSlice(cd.SigningRoot, tree.RootHash()) { + return errors.New("signing root mismatch") + } + + return nil + }) +} + +// documentRootValidator checks the existence of document root +// recalculates the document root and compares with existing one +func documentRootValidator() Validator { + return ValidatorFunc(func(_, model Model) error { + cd, err := getCoreDocument(model) + if err != nil { + return err + } + + if utils.IsEmptyByteSlice(cd.DocumentRoot) { + return errors.New("document root missing") + } + + tree, err := coredocument.GetDocumentRootTree(cd) + if err != nil { + return errors.New("failed to calculate document root: %v", err) + } + + if !utils.IsSameByteSlice(cd.DocumentRoot, tree.RootHash()) { + return errors.New("document root mismatch") + } + + return nil + }) +} + +// readyForSignaturesValidator validates self signature +// re-calculates the signature and compares with existing one +// assumes signing_root is already generated and verified +// Note: this needs to used only before document is sent for signatures from the collaborators +func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { + return ValidatorFunc(func(_, model Model) error { + cd, err := getCoreDocument(model) + if err != nil { + return err + } + + if len(cd.Signatures) != 1 { + return errors.New("expecting only one signature") + } + + s := crypto.Sign(centIDBytes, priv, pub, cd.SigningRoot) + sh := cd.Signatures[0] + if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { + err = errors.AppendError(err, NewError("cd_entity_id", "entity ID mismatch")) + } + + if !utils.IsSameByteSlice(s.PublicKey, sh.PublicKey) { + err = errors.AppendError(err, NewError("cd_public_key", "public key mismatch")) + } + + if !utils.IsSameByteSlice(s.Signature, sh.Signature) { + err = errors.AppendError(err, NewError("cd_signature", "signature mismatch")) + } + + return err + }) +} + +// signaturesValidator validates all the signatures in the core document +// assumes signing root is verified +// Note: can be used when during the signature request on collaborator side and post signature collection on sender side +// Note: this will break the current flow where we proceed to anchor even signatures verification fails +func signaturesValidator(idService identity.Service) Validator { + return ValidatorFunc(func(_, model Model) error { + cd, err := getCoreDocument(model) + if err != nil { + return err + } + + if len(cd.Signatures) < 1 { + return errors.New("atleast one signature expected") + } + + for _, sig := range cd.Signatures { + if erri := idService.ValidateSignature(sig, cd.SigningRoot); erri != nil { + err = errors.AppendError( + err, + NewError( + fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), + fmt.Sprintf("signature verification failed: %v", erri))) + } + } + + return err + }) +} + +// anchoredValidator checks if the document root matches the one on chain with specific anchorID +// assumes document root is generated and verified +func anchoredValidator(repo anchors.AnchorRepository) Validator { + return ValidatorFunc(func(_, new Model) error { + cd, err := getCoreDocument(new) + if err != nil { + return errors.New("failed to get core document: %v", err) + } + + anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) + if err != nil { + return errors.New("failed to get anchorID: %v", err) + } + + docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) + if err != nil { + return errors.New("failed to get document root: %v", err) + } + + gotRoot, err := repo.GetDocumentRootOf(anchorID) + if err != nil { + return errors.New("failed to get document root from chain: %v", err) + } + + if !utils.IsSameByteSlice(docRoot[:], gotRoot[:]) { + return errors.New("mismatched document roots") + } + + return nil + }) +} + +// SignatureRequestValidator returns a validator group with following validators +// base validator +// signing root validator +// signatures validator +// should be used when node receives a document requesting for signature +func SignatureRequestValidator(idService identity.Service) ValidatorGroup { + return PostSignatureRequestValidator(idService) +} + +// PreAnchorValidator is a validator group with following validators +// base validator +// signing root validator +// document root validator +// signatures validator +// should be called before pre anchoring +func PreAnchorValidator(idService identity.Service) ValidatorGroup { + return ValidatorGroup{ + PostSignatureRequestValidator(idService), + documentRootValidator(), + } +} + +// PostAnchoredValidator is a validator group with following validators +// PreAnchorValidator +// anchoredValidator +// should be called after anchoring the document/when received anchored document +func PostAnchoredValidator(idService identity.Service, repo anchors.AnchorRepository) ValidatorGroup { + return ValidatorGroup{ + PreAnchorValidator(idService), + anchoredValidator(repo), + } +} + +// PreSignatureRequestValidator is a validator group with following validators +// baseValidator +// signingRootValidator +// readyForSignaturesValidator +// should be called after sender signing the document and before requesting the document +func PreSignatureRequestValidator(centIDBytes, priv, pub []byte) ValidatorGroup { + return ValidatorGroup{ + baseValidator(), + signingRootValidator(), + readyForSignaturesValidator(centIDBytes, priv, pub), + } +} + +// PostSignatureRequestValidator is a validator group with following validators +// baseValidator +// signingRootValidator +// signaturesValidator +// should be called after the signature collection/before preparing for anchoring +func PostSignatureRequestValidator(idService identity.Service) ValidatorGroup { + return ValidatorGroup{ + baseValidator(), + signingRootValidator(), + signaturesValidator(idService), + } +} diff --git a/documents/validator_test.go b/documents/validator_test.go index 34b07e8f0..5e6a853f6 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -5,6 +5,19 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/coredocument" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/golang/protobuf/ptypes/any" + "github.com/stretchr/testify/mock" + "github.com/centrifuge/go-centrifuge/errors" "github.com/stretchr/testify/assert" ) @@ -111,3 +124,532 @@ func TestIsCurrencyValid(t *testing.T) { assert.Equal(t, c.valid, got, "result must match") } } + +func TestUpdateVersionValidator(t *testing.T) { + uvv := UpdateVersionValidator() + + // nil models + err := uvv.Validate(nil, nil) + assert.Error(t, err) + assert.Contains(t, err.Error(), "need both the old and new model") + + // old model pack core doc fail + old := mockModel{} + newM := mockModel{} + old.On("PackCoreDocument").Return(nil, errors.New("error")).Once() + err = uvv.Validate(old, newM) + old.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to fetch old core document") + + // newM model pack core doc fail + oldCD := coredocument.New() + oldCD.DocumentRoot = utils.RandomSlice(32) + old.On("PackCoreDocument").Return(oldCD, nil).Once() + newM.On("PackCoreDocument").Return(nil, errors.New("error")).Once() + err = uvv.Validate(old, newM) + old.AssertExpectations(t) + newM.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to fetch new core document") + + // mismatched identifiers + newCD := coredocument.New() + newCD.NextVersion = nil + old.On("PackCoreDocument").Return(oldCD, nil).Once() + newM.On("PackCoreDocument").Return(newCD, nil).Once() + err = uvv.Validate(old, newM) + old.AssertExpectations(t) + newM.AssertExpectations(t) + assert.Error(t, err) + assert.Equal(t, 5, errors.Len(err)) + + // success + newCD, err = coredocument.PrepareNewVersion(*oldCD, nil) + assert.Nil(t, err) + old.On("PackCoreDocument").Return(oldCD, nil).Once() + newM.On("PackCoreDocument").Return(newCD, nil).Once() + err = uvv.Validate(old, newM) + old.AssertExpectations(t) + newM.AssertExpectations(t) + assert.Nil(t, err) +} + +func Test_getCoreDocument(t *testing.T) { + // nil document + cd, err := getCoreDocument(nil) + assert.Error(t, err) + assert.Nil(t, cd) + + // pack core document fail + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + cd, err = getCoreDocument(model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Nil(t, cd) + + // success + model = mockModel{} + cd = coredocument.New() + model.On("PackCoreDocument").Return(cd, nil).Once() + got, err := getCoreDocument(model) + model.AssertExpectations(t) + assert.Nil(t, err) + assert.Equal(t, cd, got) +} + +func TestValidator_baseValidator(t *testing.T) { + bv := baseValidator() + + // fail getCoreDocument + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + err := bv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + + // failed validator + model = mockModel{} + cd := coredocument.New() + model.On("PackCoreDocument").Return(cd, nil).Once() + err = bv.Validate(nil, model) + assert.Error(t, err) + assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[1].Error()) + + // success + model = mockModel{} + cd.DataRoot = utils.RandomSlice(32) + assert.Nil(t, coredocument.FillSalts(cd)) + model.On("PackCoreDocument").Return(cd, nil).Once() + err = bv.Validate(nil, model) + assert.Nil(t, err) +} + +func TestValidator_signingRootValidator(t *testing.T) { + sv := signingRootValidator() + + // fail getCoreDoc + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + err := sv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + + // missing signing_root + cd := coredocument.New() + assert.Nil(t, coredocument.FillSalts(cd)) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = sv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "signing root missing") + + // mismatch signing roots + cd.SigningRoot = utils.RandomSlice(32) + cd.EmbeddedData = &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = sv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "signing root mismatch") + + // success + tree, err := coredocument.GetDocumentSigningTree(cd) + assert.Nil(t, err) + cd.SigningRoot = tree.RootHash() + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = sv.Validate(nil, model) + model.AssertExpectations(t) + assert.Nil(t, err) +} + +func TestValidator_documentRootValidator(t *testing.T) { + dv := documentRootValidator() + + // fail getCoreDoc + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + err := dv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + + // missing document root + cd := coredocument.New() + assert.Nil(t, coredocument.FillSalts(cd)) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = dv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "document root missing") + + // mismatch signing roots + cd.DocumentRoot = utils.RandomSlice(32) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = dv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "document root mismatch") + + // success + tree, err := coredocument.GetDocumentRootTree(cd) + assert.Nil(t, err) + cd.DocumentRoot = tree.RootHash() + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = dv.Validate(nil, model) + model.AssertExpectations(t) + assert.Nil(t, err) +} + +func TestValidator_selfSignatureValidator(t *testing.T) { + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + idKeys := self.Keys[identity.KeyPurposeSigning] + rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) + + // fail getCoreDoc + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + err := rfsv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + + // signature length mismatch + cd := coredocument.New() + assert.Nil(t, coredocument.FillSalts(cd)) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = rfsv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "expecting only one signature") + + // mismatch + cd.SigningRoot = utils.RandomSlice(32) + s := &coredocumentpb.Signature{ + Signature: utils.RandomSlice(32), + EntityId: utils.RandomSlice(6), + PublicKey: utils.RandomSlice(32), + } + cd.Signatures = append(cd.Signatures, s) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = rfsv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Equal(t, 3, errors.Len(err)) + + // success + cd.SigningRoot = utils.RandomSlice(32) + c, err := identity.GetIdentityConfig(cfg) + assert.Nil(t, err) + s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) + cd.Signatures = []*coredocumentpb.Signature{s} + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = rfsv.Validate(nil, model) + model.AssertExpectations(t) + assert.Nil(t, err) +} + +func TestValidator_signatureValidator(t *testing.T) { + srv := &testingcommons.MockIDService{} + ssv := signaturesValidator(srv) + + // fail getCoreDoc + model := mockModel{} + model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + err := ssv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + + // signature length mismatch + cd := coredocument.New() + assert.Nil(t, coredocument.FillSalts(cd)) + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = ssv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "atleast one signature expected") + + // failed validation + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("fail")).Once() + s := &coredocumentpb.Signature{EntityId: utils.RandomSlice(7)} + cd.Signatures = append(cd.Signatures, s) + err = ssv.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "signature verification failed") + + // success + model = mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() + cd.SigningRoot = utils.RandomSlice(32) + cd.Signatures = []*coredocumentpb.Signature{{}} + + err = ssv.Validate(nil, model) + model.AssertExpectations(t) + srv.AssertExpectations(t) + assert.Nil(t, err) +} + +func TestPreAnchorValidator(t *testing.T) { + pav := PreAnchorValidator(nil) + assert.Len(t, pav, 2) +} + +func TestValidator_anchoredValidator(t *testing.T) { + av := anchoredValidator(mockRepo{}) + + // fail get core document + err := av.Validate(nil, nil) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get core document") + + // failed anchorID + model := &mockModel{} + cd := &coredocumentpb.CoreDocument{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get anchorID") + + // failed docRoot + model = &mockModel{} + cd.CurrentVersion = utils.RandomSlice(32) + model.On("PackCoreDocument").Return(cd, nil).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get document root") + + // failed to get docRoot from chain + anchorID, err := anchors.ToAnchorID(utils.RandomSlice(32)) + assert.Nil(t, err) + r := &mockRepo{} + av = anchoredValidator(r) + cd.CurrentVersion = anchorID[:] + r.On("GetDocumentRootOf", anchorID).Return(nil, errors.New("error")).Once() + cd.DocumentRoot = utils.RandomSlice(32) + model = &mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + r.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get document root from chain") + + // mismatched doc roots + docRoot := anchors.RandomDocumentRoot() + r = &mockRepo{} + av = anchoredValidator(r) + r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() + cd.DocumentRoot = utils.RandomSlice(32) + model = &mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + r.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "mismatched document roots") + + // success + r = &mockRepo{} + av = anchoredValidator(r) + r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() + cd.DocumentRoot = docRoot[:] + model = &mockModel{} + model.On("PackCoreDocument").Return(cd, nil).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + r.AssertExpectations(t) + assert.Nil(t, err) +} + +var ( + id1 = utils.RandomSlice(32) + id2 = utils.RandomSlice(32) + id3 = utils.RandomSlice(32) + id4 = utils.RandomSlice(32) + id5 = utils.RandomSlice(32) +) + +func TestValidate_baseValidator(t *testing.T) { + tests := []struct { + doc *coredocumentpb.CoreDocument + key string + }{ + // empty salts in document + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id4, + DataRoot: id5, + }, + key: "[cd_salts : Required field]", + }, + + // salts missing previous root + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id4, + DataRoot: id5, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + }, + }, + key: "[cd_salts : Required field]", + }, + + // missing identifiers in core document + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id4, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + PreviousRoot: id5, + }, + }, + key: "[cd_data_root : Required field]", + }, + + // missing identifiers in core document and salts + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id4, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + }, + }, + key: "[cd_data_root : Required field; cd_salts : Required field]", + }, + + // repeated identifiers + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id3, + DataRoot: id5, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + PreviousRoot: id5, + }, + }, + key: "[cd_overall : Identifier re-used]", + }, + + // repeated identifiers + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id2, + DataRoot: id5, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + PreviousRoot: id5, + }, + }, + key: "[cd_overall : Identifier re-used]", + }, + + // All okay + { + doc: &coredocumentpb.CoreDocument{ + DocumentRoot: id1, + DocumentIdentifier: id2, + CurrentVersion: id3, + NextVersion: id4, + DataRoot: id5, + CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ + DocumentIdentifier: id1, + CurrentVersion: id2, + NextVersion: id3, + DataRoot: id4, + PreviousRoot: id5, + }, + }, + }, + } + + baseValidator := baseValidator() + + for _, c := range tests { + + model := mockModel{} + model.On("PackCoreDocument", mock.Anything).Return(c.doc, nil).Once() + + err := baseValidator.Validate(nil, &model) + if c.key == "" { + assert.Nil(t, err) + continue + } + + assert.Equal(t, c.key, err.Error()) + + } +} + +func TestPostAnchoredValidator(t *testing.T) { + pav := PostAnchoredValidator(nil, nil) + assert.Len(t, pav, 2) +} + +func TestPreSignatureRequestValidator(t *testing.T) { + self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + idKeys := self.Keys[identity.KeyPurposeSigning] + psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) + assert.Len(t, psv, 3) +} + +func TestPostSignatureRequestValidator(t *testing.T) { + psv := PostSignatureRequestValidator(nil) + assert.Len(t, psv, 3) +} + +func TestSignatureRequestValidator(t *testing.T) { + srv := SignatureRequestValidator(nil) + assert.Len(t, srv, 3) +} diff --git a/identity/identity_test.go b/identity/identity_test.go index d5eaa14a9..baaa92c7b 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -3,19 +3,15 @@ package identity import ( - "context" "os" "testing" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) var ctx = map[string]interface{}{} @@ -36,83 +32,6 @@ func TestMain(m *testing.M) { os.Exit(result) } -// mockID implements Identity -type mockID struct { - mock.Mock -} - -func (i *mockID) String() string { - args := i.Called() - return args.String(0) -} - -func (i *mockID) CentID() CentID { - args := i.Called() - return args.Get(0).(CentID) -} - -func (i *mockID) SetCentrifugeID(centId CentID) { - i.Called(centId) -} - -func (i *mockID) CurrentP2PKey() (ret string, err error) { - args := i.Called() - return args.String(0), args.Error(1) -} - -func (i *mockID) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { - args := i.Called(keyPurpose) - return args.Get(0).([]byte), args.Error(1) -} - -func (i *mockID) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) { - args := i.Called(ctx, keyPurpose, key) - return args.Get(0).(chan *WatchIdentity), args.Error(1) -} - -func (i *mockID) FetchKey(key []byte) (Key, error) { - args := i.Called(key) - idKey := args.Get(0) - if idKey != nil { - if k, ok := idKey.(Key); ok { - return k, args.Error(1) - } - } - return nil, args.Error(1) -} - -// mockIDService implements Service -type mockIDService struct { - mock.Mock -} - -func (srv *mockIDService) GetIdentityAddress(centID CentID) (common.Address, error) { - args := srv.Called(centID) - id := args.Get(0).(common.Address) - return id, args.Error(1) -} - -func (srv *mockIDService) LookupIdentityForID(centID CentID) (Identity, error) { - args := srv.Called(centID) - id := args.Get(0) - if id != nil { - return id.(Identity), args.Error(1) - } - return nil, args.Error(1) - -} - -func (srv *mockIDService) CreateIdentity(centID CentID) (Identity, chan *WatchIdentity, error) { - args := srv.Called(centID) - id := args.Get(0).(Identity) - return id, args.Get(1).(chan *WatchIdentity), args.Error(2) -} - -func (srv *mockIDService) CheckIdentityExists(centID CentID) (exists bool, err error) { - args := srv.Called(centID) - return args.Bool(0), args.Error(1) -} - func TestGetIdentityConfig_Success(t *testing.T) { idConfig, err := GetIdentityConfig(cfg) assert.Nil(t, err) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 6b30ba53a..906b02423 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -5,7 +5,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" @@ -27,9 +26,9 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("ethereum client hasn't been initialized") } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + docSrv, ok := ctx[documents.BootstrappedDocumentService].(documents.Service) if !ok { - return errors.New("service registry not initialised") + return errors.New("document service not initialised") } idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) @@ -47,18 +46,12 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("transactions repository not initialised") } - genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) - if !ok { - return errors.New("generic service is not initialised") - } - client := ethereum.GetClient() payOb := newEthereumPaymentObligation( - registry, idService, client, queueSrv, - genService, + docSrv, bindContract, txService, func() (uint64, error) { h, err := client.GetEthClient().HeaderByNumber(context.Background(), nil) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index a407d05c2..4b98f91c7 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -4,8 +4,6 @@ import ( "context" "math/big" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" @@ -41,7 +39,7 @@ type ethereumPaymentObligation struct { identityService identity.Service ethClient ethereum.Client queue queue.TaskQueuer - genService genericdoc.Service + docSrv documents.Service bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) txService transactions.Service blockHeightFunc func() (height uint64, err error) @@ -49,21 +47,19 @@ type ethereumPaymentObligation struct { // newEthereumPaymentObligation creates ethereumPaymentObligation given the parameters func newEthereumPaymentObligation( - registry *documents.ServiceRegistry, identityService identity.Service, ethClient ethereum.Client, queue queue.TaskQueuer, - genService genericdoc.Service, + docSrv documents.Service, bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error), txService transactions.Service, blockHeightFunc func() (uint64, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ - registry: registry, identityService: identityService, ethClient: ethClient, bindContract: bindContract, queue: queue, - genService: genService, + docSrv: docSrv, txService: txService, blockHeightFunc: blockHeightFunc, } @@ -71,7 +67,7 @@ func newEthereumPaymentObligation( func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { - model, err := s.genService.GetCurrentVersion(ctx, documentID) + model, err := s.docSrv.GetCurrentVersion(ctx, documentID) if err != nil { return nil, err } @@ -81,7 +77,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, docu return nil, err } - proofs, err := s.genService.CreateProofs(ctx, documentID, proofFields) + proofs, err := s.docSrv.CreateProofs(ctx, documentID, proofFields) if err != nil { return nil, err } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index ac7166c63..0e3957121 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -186,14 +186,12 @@ func TestPaymentObligationService(t *testing.T) { txService := ctx[transactions.BootstrappedService].(transactions.Service) - registry := documents.NewServiceRegistry() for _, test := range tests { t.Run(test.name, func(t *testing.T) { // get mocks docService, paymentOb, idService, ethClient, mockCfg, queueSrv := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton - registry.Register(test.name, &docService) - service := newEthereumPaymentObligation(registry, &idService, ðClient, queueSrv, &docService, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + service := newEthereumPaymentObligation(&idService, ðClient, queueSrv, &docService, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil }, txService, func() (uint64, error) { return 10, nil }) ctxh := testingconfig.CreateTenantContext(t, &mockCfg) diff --git a/node/bootstrapper.go b/node/bootstrapper.go index dd3098df5..de1a7fa4d 100644 --- a/node/bootstrapper.go +++ b/node/bootstrapper.go @@ -51,7 +51,7 @@ func cleanUp(c map[string]interface{}) { // GetServers gets the long running background services in the node as a list func GetServers(ctx map[string]interface{}) ([]Server, error) { - p2pSrv, ok := ctx[bootstrap.BootstrappedP2PServer] + p2pSrv, ok := ctx[bootstrap.BootstrappedPeer] if !ok { return nil, errors.New("p2p server not initialized") } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 0d58f5175..82f4d83f7 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -5,7 +5,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/receiver" @@ -26,9 +25,9 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("configstore not initialised") } - registry, ok := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + docSrv, ok := ctx[documents.BootstrappedDocumentService].(documents.Service) if !ok { - return errors.New("registry not initialised") + return errors.New("document service not initialised") } idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) @@ -36,15 +35,8 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("identity service not initialised") } - genService, ok := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) - if !ok { - return errors.New("generic service is not initialised") - } - - srv := &peer{config: cfgService, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), genService) + ctx[bootstrap.BootstrappedPeer] = &peer{config: cfgService, handlerCreator: func() *receiver.Handler { + return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) }} - ctx[bootstrap.BootstrappedP2PServer] = srv - ctx[bootstrap.BootstrappedP2PClient] = srv return nil } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 43c6a40b8..0c1541d07 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -5,15 +5,13 @@ package p2p import ( "testing" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/node" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/stretchr/testify/assert" ) @@ -31,19 +29,18 @@ func TestBootstrapper_Bootstrap(t *testing.T) { m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) - m[documents.BootstrappedRegistry] = documents.NewServiceRegistry() ids := new(testingcommons.MockIDService) m[identity.BootstrappedIDService] = ids - m[genericdoc.BootstrappedGenService] = genericdoc.DefaultService(nil, nil, nil) + m[documents.BootstrappedDocumentService] = documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) err = b.Bootstrap(m) assert.Nil(t, err) - assert.NotNil(t, m[bootstrap.BootstrappedP2PServer]) - _, ok := m[bootstrap.BootstrappedP2PServer].(node.Server) + assert.NotNil(t, m[bootstrap.BootstrappedPeer]) + _, ok := m[bootstrap.BootstrappedPeer].(node.Server) assert.True(t, ok) - assert.NotNil(t, m[bootstrap.BootstrappedP2PClient]) - _, ok = m[bootstrap.BootstrappedP2PClient].(Client) + assert.NotNil(t, m[bootstrap.BootstrappedPeer]) + _, ok = m[bootstrap.BootstrappedPeer].(documents.Client) assert.True(t, ok) } diff --git a/p2p/client.go b/p2p/client.go index c91ae233f..c4f9d9709 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -24,16 +24,6 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -// Client defines methods that can be implemented by any type handling p2p communications. -type Client interface { - - // GetSignaturesForDocument gets the signatures for document - GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error - - // after all signatures are collected the sender sends the document including the signatures - SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) -} - func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { nc, err := s.config.GetConfig() if err != nil { diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 9b3a8c9f1..7e54c13f5 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -15,8 +15,8 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" @@ -26,7 +26,7 @@ import ( ) var ( - client p2p.Client + client documents.Client cfg config.Configuration idService identity.Service cfgStore config.Service @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgStore = ctx[config.BootstrappedConfigStorage].(config.Service) idService = ctx[identity.BootstrappedIDService].(identity.Service) - client = ctx[bootstrap.BootstrappedP2PClient].(p2p.Client) + client = ctx[bootstrap.BootstrappedPeer].(documents.Client) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 8efefe95a..03aacdc71 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -3,61 +3,38 @@ package receiver import ( "context" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p/common" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/golang/protobuf/proto" - "github.com/libp2p/go-libp2p-peer" - "github.com/libp2p/go-libp2p-protocol" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/common" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/golang/protobuf/proto" + "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" ) -// getService looks up the specific registry, derives service from core document -func getServiceAndModel(registry *documents.ServiceRegistry, cd *coredocumentpb.CoreDocument) (documents.Service, documents.Model, error) { - if cd == nil { - return nil, nil, errors.New("nil core document") - } - docType, err := coredocument.GetTypeURL(cd) - if err != nil { - return nil, nil, errors.New("failed to get type of the document: %v", err) - } - - srv, err := registry.LocateService(docType) - if err != nil { - return nil, nil, errors.New("failed to locate the service: %v", err) - } - - model, err := srv.DeriveFromCoreDocument(cd) - if err != nil { - return nil, nil, errors.New("failed to derive model from core document: %v", err) - } - - return srv, model, nil -} - // Handler implements protocol message handlers type Handler struct { - registry *documents.ServiceRegistry config config.Service handshakeValidator ValidatorGroup - genericService genericdoc.Service + docSrv documents.Service } // New returns an implementation of P2PServiceServer -func New(config config.Service, registry *documents.ServiceRegistry, handshakeValidator ValidatorGroup, genericService genericdoc.Service) *Handler { - return &Handler{registry: registry, config: config, handshakeValidator: handshakeValidator, genericService: genericService} +func New( + config config.Service, + handshakeValidator ValidatorGroup, + docSrv documents.Service) *Handler { + return &Handler{ + config: config, + handshakeValidator: handshakeValidator, + docSrv: docSrv, + } } // HandleInterceptor acts as main entry point for all message types, routes the request to the correct handler @@ -139,12 +116,16 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - svc, model, err := getServiceAndModel(srv.registry, sigReq.Document) + if sigReq.Document == nil { + return nil, errors.New("nil core document") + } + + model, err := srv.docSrv.DeriveFromCoreDocument(sigReq.Document) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.New("failed to derive from core doc: %v", err) } - signature, err := svc.RequestDocumentSignature(ctx, model) + signature, err := srv.docSrv.RequestDocumentSignature(ctx, model) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -180,12 +161,12 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest, senderID []byte) (*p2ppb.AnchorDocumentResponse, error) { - svc, model, err := getServiceAndModel(srv.registry, docReq.Document) + model, err := srv.docSrv.DeriveFromCoreDocument(docReq.Document) if err != nil { - return nil, centerrors.New(code.DocumentInvalid, err.Error()) + return nil, errors.New("failed to derive from core doc: %v", err) } - err = svc.ReceiveAnchoredDocument(ctx, model, senderID) + err = srv.docSrv.ReceiveAnchoredDocument(ctx, model, senderID) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -221,7 +202,7 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc // GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest) (*p2ppb.GetDocumentResponse, error) { - model, err := srv.genericService.GetCurrentVersion(ctx, docReq.DocumentIdentifier) + model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) if err != nil { return nil, err } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index df70f08a1..279ca6ad5 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -5,38 +5,32 @@ package receiver_test import ( "context" "flag" - - "github.com/centrifuge/go-centrifuge/contextutil" - cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" - "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - "github.com/golang/protobuf/proto" - "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/bootstrap" - - "github.com/centrifuge/go-centrifuge/p2p/receiver" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" + cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/p2p/receiver" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" "golang.org/x/crypto/ed25519" @@ -55,11 +49,10 @@ func TestMain(m *testing.M) { ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService = ctx[config.BootstrappedConfigStorage].(config.Service) - registry := ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) + docSrv := ctx[documents.BootstrappedDocumentService].(documents.Service) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) - genService := ctx[genericdoc.BootstrappedGenService].(genericdoc.Service) - handler = receiver.New(cfgService, registry, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), genService) + handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() @@ -248,7 +241,8 @@ func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) req := getAnchoredRequest(doc) req.Document = nil - id, _ := cfg.GetIdentityID() + id, err := cfg.GetIdentityID() + assert.NoError(t, err) resp, err := handler.SendAnchoredDocument(ctxh, req, id) assert.NotNil(t, err) assert.Nil(t, resp, "must be nil") @@ -323,11 +317,13 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument if doc == nil { doc = testingcoredocument.GenerateCoreDocument() } - tree, _ := coredocument.GetDocumentSigningTree(doc) + tree, err := coredocument.GetDocumentSigningTree(doc) + assert.NoError(t, err) doc.SigningRoot = tree.RootHash() sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) - tree, _ = coredocument.GetDocumentRootTree(doc) + tree, err = coredocument.GetDocumentRootTree(doc) + assert.NoError(t, err) doc.DocumentRoot = tree.RootHash() return doc } diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 3845a1f76..a26cbf1c1 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -8,36 +8,32 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/version" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/proto" - "github.com/libp2p/go-libp2p-protocol" - - "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/config/configstore" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/golang/protobuf/ptypes/any" + "github.com/centrifuge/go-centrifuge/version" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-crypto" libp2pPeer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -45,13 +41,16 @@ import ( var ( handler *Handler registry *documents.ServiceRegistry - coreDoc = testingcoredocument.GenerateCoreDocument() cfg config.Configuration mockIDService *testingcommons.MockIDService defaultPID libp2pPeer.ID ) func TestMain(m *testing.M) { + ctx := make(map[string]interface{}) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -59,20 +58,20 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, + &anchors.Bootstrapper{}, documents.Bootstrapper{}, } - ctx := make(map[string]interface{}) ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - genService := genericdoc.DefaultService(nil, nil, nil) + docSrv := documents.DefaultService(nil, nil, nil, registry) mockIDService = &testingcommons.MockIDService{} _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil) - handler = New(cfgService, registry, HandshakeValidator(cfg.GetNetworkID(), mockIDService), genService) + handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -188,7 +187,7 @@ func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { id, _ := cfg.GetIdentityID() resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") - assert.Contains(t, err.Error(), "failed to get type of the document") + assert.Contains(t, err.Error(), "core document is nil") assert.Nil(t, resp, "must be nil") } @@ -225,70 +224,3 @@ func TestP2PService_basicChecks(t *testing.T) { } } - -type mockModel struct { - mock.Mock - documents.Model -} - -type mockService struct { - mock.Mock - documents.Service -} - -func (s mockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { - args := s.Called(cd) - m, _ := args.Get(0).(documents.Model) - return m, args.Error(1) -} - -func Test_getServiceAndModel(t *testing.T) { - // document nil fail - s, m, err := getServiceAndModel(registry, nil) - assert.Error(t, err) - - // docType fetch fail - cd := coredocument.New() - s, m, err = getServiceAndModel(registry, cd) - assert.Error(t, err) - assert.Nil(t, s) - assert.Nil(t, m) - assert.Contains(t, err.Error(), "failed to get type of the document") - - // missing service - cd.EmbeddedData = &any.Any{ - TypeUrl: "model_type_fail", - Value: []byte("some data"), - } - s, m, err = getServiceAndModel(registry, cd) - assert.Error(t, err) - assert.Nil(t, s) - assert.Nil(t, m) - assert.Contains(t, err.Error(), "failed to locate the service") - - // derive fails - srv := mockService{} - srv.On("DeriveFromCoreDocument", cd).Return(nil, errors.New("error")).Once() - err = registry.Register(cd.EmbeddedData.TypeUrl, srv) - assert.Nil(t, err) - s, m, err = getServiceAndModel(registry, cd) - srv.AssertExpectations(t) - assert.Error(t, err) - assert.Nil(t, s) - assert.Nil(t, m) - assert.Contains(t, err.Error(), "failed to derive model from core document") - - // success - model := &mockModel{} - cd.EmbeddedData.TypeUrl = "get_model_type" - srv = mockService{} - srv.On("DeriveFromCoreDocument", cd).Return(model, nil).Once() - err = registry.Register(cd.EmbeddedData.TypeUrl, srv) - assert.Nil(t, err) - s, m, err = getServiceAndModel(registry, cd) - srv.AssertExpectations(t) - assert.Nil(t, err) - assert.NotNil(t, s) - assert.NotNil(t, m) - assert.Equal(t, model, m) -} diff --git a/p2p/server_test.go b/p2p/server_test.go index ab80bed39..1694b54e1 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,34 +10,36 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/documents/genericdoc" + "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/utils" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" - - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/receiver" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" ) var ( - cfg config.Service - idService identity.Service - genericService genericdoc.Service + cfg config.Service + idService identity.Service ) func TestMain(m *testing.M) { + ctx := make(map[string]interface{}) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -45,9 +47,9 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, &queue.Bootstrapper{}, transactions.Bootstrapper{}, + &anchors.Bootstrapper{}, documents.Bootstrapper{}, } - ctx := make(map[string]interface{}) idService = &testingcommons.MockIDService{} ctx[identity.BootstrappedIDService] = idService bootstrap.RunTestBootstrappers(ibootstappers, ctx) @@ -66,7 +68,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { cfgMock := mockmockConfigStore(n) assert.NoError(t, err) cp2p := &peer{config: cfgMock, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgMock, nil, receiver.HandshakeValidator(n.NetworkID, idService), genericService) + return receiver.New(cfgMock, receiver.HandshakeValidator(n.NetworkID, idService), nil) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) diff --git a/testingutils/anchors/mock_anchor_repo.go b/testingutils/anchors/mock_anchor_repo.go new file mode 100644 index 000000000..46e376f85 --- /dev/null +++ b/testingutils/anchors/mock_anchor_repo.go @@ -0,0 +1,19 @@ +// +build unit integration + +package testinganchors + +import ( + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/stretchr/testify/mock" +) + +type MockAnchorRepo struct { + mock.Mock + anchors.AnchorRepository +} + +func (r *MockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.DocumentRoot, error) { + args := r.Called(anchorID) + docRoot, _ := args.Get(0).(anchors.DocumentRoot) + return docRoot, args.Error(1) +} diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index b00a166fb..b8a5a6989 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -3,16 +3,12 @@ package testingcoredocument import ( - "context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/mock" ) func GenerateCoreDocument() *coredocumentpb.CoreDocument { @@ -34,56 +30,3 @@ func GenerateCoreDocument() *coredocumentpb.CoreDocument { proofs.FillSalts(doc, salts) return doc } - -type MockCoreDocumentProcessor struct { - mock.Mock -} - -func (m *MockCoreDocumentProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { - args := m.Called(coreDocument, ctx, recipient) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) Anchor( - ctx context.Context, - coreDocument *coredocumentpb.CoreDocument, - saveState func(*coredocumentpb.CoreDocument) error) (err error) { - args := m.Called(ctx, coreDocument, saveState) - if saveState != nil { - err := saveState(coreDocument) - if err != nil { - return err - } - } - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) PrepareForSignatureRequests(ctx context.Context, model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) RequestSignatures(ctx context.Context, model documents.Model) error { - args := m.Called(ctx, model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) PrepareForAnchoring(model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) AnchorDocument(ctx context.Context, model documents.Model) error { - args := m.Called(model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) SendDocument(ctx context.Context, model documents.Model) error { - args := m.Called(ctx, model) - return args.Error(0) -} - -func (m *MockCoreDocumentProcessor) GetDataProofHashes(coreDocument *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { - args := m.Called(coreDocument) - return args.Get(0).([][]byte), args.Error(1) -} diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 09fd0c666..b3ab23e67 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -11,6 +11,7 @@ import ( ) type MockService struct { + documents.Service mock.Mock } From 151160e29596b5e9400060cc2a1f1015a6fb8064 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 18 Jan 2019 19:55:05 +0100 Subject: [PATCH 153/220] Client has access to idService (#667) --- documents/processor.go | 12 ++++-------- documents/processor_test.go | 2 +- p2p/bootstrapper.go | 2 +- p2p/client.go | 28 ++++++++++++++++------------ p2p/client_integration_test.go | 6 +++--- p2p/client_test.go | 20 ++++++++++---------- p2p/server.go | 1 + testingutils/setup.go | 2 +- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/documents/processor.go b/documents/processor.go index 73250f3e0..e479d729d 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -26,10 +26,10 @@ type Config interface { type Client interface { // GetSignaturesForDocument gets the signatures for document - GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error // after all signatures are collected the sender sends the document including the signatures - SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) + SendAnchoredDocument(ctx context.Context, receiverID identity.CentID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) } // defaultProcessor implements AnchorProcessor interface @@ -56,13 +56,9 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp return errors.New("passed coreDoc is nil") } log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) - id, err := dp.identityService.LookupIdentityForID(recipient) - if err != nil { - return errors.New("error fetching receiver identity: %v", err) - } c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) - resp, err := dp.p2pClient.SendAnchoredDocument(c, id, &p2ppb.AnchorDocumentRequest{Document: coreDocument}) + resp, err := dp.p2pClient.SendAnchoredDocument(c, recipient, &p2ppb.AnchorDocumentRequest{Document: coreDocument}) if err != nil || !resp.Accepted { return errors.New("failed to send document to the node: %v", err) } @@ -125,7 +121,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e return errors.New("failed to validate model for signature request: %v", err) } - err = dp.p2pClient.GetSignaturesForDocument(ctx, dp.identityService, cd) + err = dp.p2pClient.GetSignaturesForDocument(ctx, cd) if err != nil { return errors.New("failed to collect signatures from the collaborators: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index cd3e21558..431935880 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -102,7 +102,7 @@ type p2pClient struct { Client } -func (p p2pClient) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (p p2pClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { args := p.Called(ctx, doc) return args.Error(0) } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 82f4d83f7..e119a5fea 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -35,7 +35,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("identity service not initialised") } - ctx[bootstrap.BootstrappedPeer] = &peer{config: cfgService, handlerCreator: func() *receiver.Handler { + ctx[bootstrap.BootstrappedPeer] = &peer{config: cfgService, idService: idService, handlerCreator: func() *receiver.Handler { return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) }} return nil diff --git a/p2p/client.go b/p2p/client.go index c4f9d9709..7391bc64a 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -24,15 +24,14 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.CentID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err } peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) - cid := id.CentID() - tc, err := s.config.GetAccount(cid[:]) + tc, err := s.config.GetAccount(receiverID[:]) if err == nil { // this is a local account h := s.handlerCreator() @@ -41,7 +40,12 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i if err != nil { return nil, err } - return h.SendAnchoredDocument(localCtx, in, cid[:]) + return h.SendAnchoredDocument(localCtx, in, receiverID[:]) + } + + id, err := s.idService.LookupIdentityForID(receiverID) + if err != nil { + return nil, err } // this is a remote account @@ -58,7 +62,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, id identity.Identity, i recv, err := s.mes.sendMessage( ctx, pid, envelope, - p2pcommon.ProtocolForCID(id.CentID())) + p2pcommon.ProtocolForCID(receiverID)) if err != nil { return nil, err } @@ -123,7 +127,7 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, identityService identity.Service, doc coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err @@ -149,7 +153,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden header = &p2ppb.Header{NodeVersion: version.GetVersion().String()} } else { // this is a remote account - id, err := identityService.LookupIdentityForID(receiverCentID) + id, err := s.idService.LookupIdentityForID(receiverCentID) if err != nil { return nil, err } @@ -186,7 +190,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, identityService iden header = recvEnvelope.Header } - err = validateSignatureResp(identityService, receiverCentID, &doc, header, resp) + err = validateSignatureResp(s.idService, receiverCentID, &doc, header, resp) if err != nil { return nil, err } @@ -200,8 +204,8 @@ type signatureResponseWrap struct { err error } -func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, identityService, *doc, receiverCentID) +func (s *peer) getSignatureAsync(ctx context.Context, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, *doc, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, @@ -209,7 +213,7 @@ func (s *peer) getSignatureAsync(ctx context.Context, identityService identity.S } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService identity.Service, doc *coredocumentpb.CoreDocument) error { +func (s *peer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { in := make(chan signatureResponseWrap) defer close(in) @@ -236,7 +240,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, identityService ide return centerrors.Wrap(err, "failed to convert to CentID") } count++ - go s.getSignatureAsync(peerCtx, identityService, doc, collaboratorID, in) + go s.getSignatureAsync(peerCtx, doc, collaboratorID, in) } var responses []signatureResponseWrap diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 7e54c13f5..a91b41313 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -49,7 +49,7 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { tc, _, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - err = client.GetSignaturesForDocument(ctxh, idService, doc) + err = client.GetSignaturesForDocument(ctxh, doc) assert.NoError(t, err) assert.Equal(t, 2, len(doc.Signatures)) } @@ -58,7 +58,7 @@ func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - err = client.GetSignaturesForDocument(ctxh, idService, doc) + err = client.GetSignaturesForDocument(ctxh, doc) assert.NoError(t, err) // one signature would be missing assert.Equal(t, 1, len(doc.Signatures)) @@ -69,7 +69,7 @@ func TestClient_SendAnchoredDocument(t *testing.T) { ctxh := testingconfig.CreateTenantContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: doc}) + _, err = client.SendAnchoredDocument(ctxh, cid.CentID(), &p2ppb.AnchorDocumentRequest{Document: doc}) if assert.Error(t, err) { assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) } diff --git a/p2p/client_test.go b/p2p/client_test.go index 5d9dcec15..973d180c3 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -45,23 +45,23 @@ func (mm *MockMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes } func TestGetSignatureForDocument_fail_connect(t *testing.T) { + centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + idService := getIDMocks(centrifugeId) m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m, disablePeerStore: true} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) ctx := testingconfig.CreateTenantContext(t, c) - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) - resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -73,7 +73,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { idService := getIDMocks(centrifugeId) m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m, disablePeerStore: true} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) @@ -84,7 +84,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.NoError(t, err, "signature request could not be created") m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) - resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -92,16 +92,16 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { } func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { + centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) + idService := getIDMocks(centrifugeId) m := &MockMessenger{} - testClient := &peer{config: cfg, mes: m, disablePeerStore: true} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} coreDoc := testingcoredocument.GenerateCoreDocument() c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) ctx := testingconfig.CreateTenantContext(t, c) - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - idService := getIDMocks(centrifugeId) assert.Nil(t, err, "centrifugeId not initialized correctly ") _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) @@ -111,7 +111,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - resp, err := testClient.getSignatureForDocument(ctx, idService, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") diff --git a/p2p/server.go b/p2p/server.go index 7968f2838..387c57a11 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -46,6 +46,7 @@ type messenger interface { type peer struct { disablePeerStore bool config config.Service + idService identity.Service host host.Host handlerCreator func() *receiver.Handler mes messenger diff --git a/testingutils/setup.go b/testingutils/setup.go index 4c03a3689..78312b68d 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -135,7 +135,7 @@ func SetupSmartContractAddresses(cfg config.Configuration, sca *config.SmartCont func BuildIntegrationTestingContext() map[string]interface{} { projDir := getProjectDir() StartPOAGeth() - //RunSmartContractMigrations() + RunSmartContractMigrations() addresses := GetSmartContractAddresses() cfg := LoadTestConfig() cfg.Set("keys.signing.publicKey", fmt.Sprintf("%s/build/resources/signingKey.pub.pem", projDir)) From 744a11c6520699efdb1c001c939a7ad15d2401b2 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Sun, 20 Jan 2019 10:19:46 +0100 Subject: [PATCH 154/220] Added CMD tests (#668) * Added CMD tests * wrap in go file --- build/package-lock.json | 2 +- build/scripts/tests/run_cmd_tests.sh | 22 ++++++++++++++++ cmd/centrifuge_cmd_test.go | 38 ++++++++++++++++++++++++++++ config/configuration.go | 2 +- testingutils/setup.go | 20 ++++++++++----- 5 files changed, 75 insertions(+), 9 deletions(-) create mode 100755 build/scripts/tests/run_cmd_tests.sh create mode 100644 cmd/centrifuge_cmd_test.go diff --git a/build/package-lock.json b/build/package-lock.json index 58f0d65e4..b91f74db2 100644 --- a/build/package-lock.json +++ b/build/package-lock.json @@ -1,6 +1,6 @@ { "name": "go-centrifuge", - "version": "0.0.2", + "version": "0.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/build/scripts/tests/run_cmd_tests.sh b/build/scripts/tests/run_cmd_tests.sh new file mode 100755 index 000000000..0c6e95319 --- /dev/null +++ b/build/scripts/tests/run_cmd_tests.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -a + +################# Prepare for tests ######################## +echo "Running CMD Tests" + +status=$? +for d in $(go list -tags=cmd ./... | grep cmd | grep -v vendor); do + output="go test -coverprofile=profile.out -covermode=atomic -tags=cmd $d 2>&1" + eval "$output"| while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done + if [ ${PIPESTATUS[0]} -ne 0 ]; then + status=1 + fi + + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done + +exit $status \ No newline at end of file diff --git a/cmd/centrifuge_cmd_test.go b/cmd/centrifuge_cmd_test.go new file mode 100644 index 000000000..33bfe38ac --- /dev/null +++ b/cmd/centrifuge_cmd_test.go @@ -0,0 +1,38 @@ +// +build cmd + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "path" + "testing" + + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/version" + "github.com/stretchr/testify/assert" +) + +func TestVersion(t *testing.T) { + o, err := exec.Command(testingutils.GetBinaryPath(), "version").Output() + assert.NoError(t, err) + + assert.Contains(t, string(o), version.CentrifugeNodeVersion) +} + +func TestCreateConfig(t *testing.T) { + dataDir := path.Join(os.Getenv("HOME"), "datadir") + scAddrs := testingutils.GetSmartContractAddresses() + keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") + cmd := exec.Command(testingutils.GetBinaryPath(), "createconfig", "-n", "testing", "-t", dataDir, "-z", keyPath) + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_IDENTITYFACTORY=%s", scAddrs.IdentityFactoryAddr)) + cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_IDENTITYREGISTRY=%s", scAddrs.IdentityRegistryAddr)) + cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_ANCHORREPOSITORY=%s", scAddrs.AnchorRepositoryAddr)) + cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_PAYMENTOBLIGATION=%s", scAddrs.PaymentObligationAddr)) + o, err := cmd.Output() + assert.NoError(t, err) + + fmt.Printf("Output: %s\n", o) +} diff --git a/config/configuration.go b/config/configuration.go index df3533e75..61ce2cd1f 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -473,7 +473,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { } if _, err := os.Stat(accountKeyPath); os.IsNotExist(err) { - return nil, errors.New("account Key Path does not exist") + return nil, errors.New("account Key Path [%s] does not exist", accountKeyPath) } bfile, err := ioutil.ReadFile(accountKeyPath) diff --git a/testingutils/setup.go b/testingutils/setup.go index 78312b68d..5c71fce80 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -1,4 +1,4 @@ -// +build integration unit +// +build integration unit cmd package testingutils @@ -25,7 +25,7 @@ func StartPOAGeth() { if IsPOAGethRunning() { return } - projDir := getProjectDir() + projDir := GetProjectDir() gethRunScript := path.Join(projDir, "build", "scripts", "docker", "run.sh") o, err := exec.Command(gethRunScript, "dev").Output() if err != nil { @@ -39,7 +39,7 @@ func RunSmartContractMigrations() { if isRunningOnCI { return } - projDir := getProjectDir() + projDir := GetProjectDir() migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") _, err := exec.Command(migrationScript, projDir).Output() if err != nil { @@ -66,7 +66,7 @@ func GetSmartContractAddresses() *config.SmartContractAddresses { } func findContractDeployJSON() ([]byte, error) { - projDir := getProjectDir() + projDir := GetProjectDir() deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") dat, err := ioutil.ReadFile(deployJSONFile) if err != nil { @@ -100,12 +100,18 @@ func getOpForContract(selector string) jq.Op { return addrOp } -func getProjectDir() string { +func GetProjectDir() string { gp := os.Getenv("GOPATH") projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") return projDir } +func GetBinaryPath() string { + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "bin", "centrifuge") + return projDir +} + // IsPOAGethRunning checks if POA geth is running in the background func IsPOAGethRunning() bool { cmd := "docker ps -a --filter \"name=geth-node\" --filter \"status=running\" --quiet" @@ -119,7 +125,7 @@ func IsPOAGethRunning() bool { // LoadTestConfig loads configuration for integration tests func LoadTestConfig() config.Configuration { // To get the config location, we need to traverse the path to find the `go-centrifuge` folder - projDir := getProjectDir() + projDir := GetProjectDir() c := config.LoadConfiguration(fmt.Sprintf("%s/build/configs/testing_config.yaml", projDir)) return c } @@ -133,7 +139,7 @@ func SetupSmartContractAddresses(cfg config.Configuration, sca *config.SmartCont // BuildIntegrationTestingContext sets up configuration for integration tests func BuildIntegrationTestingContext() map[string]interface{} { - projDir := getProjectDir() + projDir := GetProjectDir() StartPOAGeth() RunSmartContractMigrations() addresses := GetSmartContractAddresses() From f68cc5a694b802c945bf14d5c9e4d81141441c3d Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 21 Jan 2019 17:26:56 +0100 Subject: [PATCH 155/220] Support custom local config and network switching for Testworld (#674) --- testworld/README.md | 39 +++++++++- testworld/config.go | 85 +++++++++++++++++++-- testworld/configs/.gitignore | 1 + testworld/configs/{local.json => base.json} | 3 + testworld/httputils.go | 2 + testworld/start_test.go | 18 +---- 6 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 testworld/configs/.gitignore rename testworld/configs/{local.json => base.json} (72%) diff --git a/testworld/README.md b/testworld/README.md index ed3c1e17a..82306a854 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -11,6 +11,40 @@ Here you can create, run and test nodes with various behaviours to observe how t - Bernard (`hostManager.bernard`) is a special host that serves as the libp2p bootnode for the test network. - `hostConfig` serves as the starting point for you to define new hosts. Please check whether an existing host can be reused for your scenario before adding new ones. - At the start of the each test run a test config is loaded for the required Ethereum network(eg: Rinkeby or local). The host configs are defined based on this. +- If you want to define a custom configuration(s) for your local testing copy `configs/base.json` to `configs/local/local.json` and modify the file the way you want. Testworld will automatically pick up the file. +- You could also replace local config depending you requirements without having to change code by changing `otherLocalConfig` field in `configs/local/local.json`, this is useful when you want to have multiple configs locally for different centrifuge/ethereum networks such as Kovan or Rinkeby. Example: + in `configs/local/local.json` add the following (please remove comments), + ``` + { + "otherLocalConfig": "configs/local/kovan.json", + + // following doesn't matter as those would be ignore because of first line + "runPOAGeth": true, + "createHostConfigs": true, + "runMigrations": false, + "ethNodeURL": "", + "accountKeyPath": "../build/scripts/test-dependencies/test-ethereum/migrateAccount.json", + "accountPassword": "", + "network" : "testing", + "txPoolAccess": true + } + ``` + in `configs/local/kovan.json` add the following (please remove comments), + ``` + { + "otherLocalConfig": "", + "runPOAGeth": true, + "createHostConfigs": true, + "runMigrations": false, + "ethNodeURL": "ws://127.0.0.1:9547", + "accountKeyPath": "", + "accountPassword": "", + + // bernalheights is the Centrifuge network on Kovan + "network" : "bernalheights", + "txPoolAccess": true + } + ``` - The test initialisation also ensures that geth is running in the background and required smart contracts are migrated for the network. - Refer `park_test.go` for a simple starting point to define your own simulations/tests. - Each test scenario must be defined in a `testworld/_test.go` file and the build tag `// +build testworld` must be included at the top. @@ -18,6 +52,7 @@ Here you can create, run and test nodes with various behaviours to observe how t ### Dev #### Speed improvements for local testing -- On `start_test.go` set `runMigrations` to `false` after the contracts are deployed once at the local geth node. -- On `start_test.go` set `createHostConfigs` to `false` after configs have been generated in `peerconfigs` dir, note that if you add new hosts using `hostConfig` you would need this to be set to `true` again to generate the config for the new host. +At `configs/local/local.json`, +- Set `runMigrations` to `false` after the contracts are deployed once at the local geth node. +- Set `createHostConfigs` to `false` after configs have been generated in `peerconfigs` dir, note that if you add new hosts using `hostConfig` you would need this to be set to `true` again to generate the config for the new host. diff --git a/testworld/config.go b/testworld/config.go index 40d5d50d1..207ca08f5 100644 --- a/testworld/config.go +++ b/testworld/config.go @@ -1,3 +1,5 @@ +// +build testworld + package testworld import ( @@ -6,7 +8,32 @@ import ( "os" ) +// configFile is the main configuration file, used mainly on CI +const configFile = "configs/base.json" + +// localConfigFile is the local configuration file, when running locally for the first time, +// copy the configFile above to this location so that you can customise for local. +const localConfigFile = "configs/local/local.json" + type testConfig struct { + + // following are env specific configs + + // OtherLocalConfig is used to direct running of Testworld with different config than local json, eg: for switching networks for local testing. + // Note that if you change this all other config fields in localConfigFile is ignored. + OtherLocalConfig string `json:"otherLocalConfig"` + + // RunPOAGeth flag, Adjust this based on local testing requirements in localConfigFile + RunPOAGeth bool `json:"runPOAGeth"` + + // CreateHostConfigs flag, make this true this when running for the first time in local env using localConfigFile + CreateHostConfigs bool `json:"createHostConfigs"` + + // RunMigrations flag, make this false if you want to make the tests run faster locally in localConfigFile + RunMigrations bool `json:"runMigrations"` + + // following are host(cent node) specific configs + EthNodeURL string `json:"ethNodeURL"` AccountKeyPath string `json:"accountKeyPath"` AccountPassword string `json:"accountPassword"` @@ -14,14 +41,62 @@ type testConfig struct { TxPoolAccess bool `json:"txPoolAccess"` } -func loadConfig(file string) (testConfig, error) { +func loadConfig(isLocal bool) (testConfig, error) { + c := configFile + if isLocal { + c = localConfigFile + } else { + fmt.Printf("Testworld using config %s\n", configFile) + } var config testConfig - configFile, err := os.Open(file) + conf, err := os.Open(c) + if err != nil { + if isLocal { + // load the base config if the local config is not available + return loadConfig(false) + } else { + fmt.Println(err.Error()) + return config, err + } + } + defer conf.Close() + jsonParser := json.NewDecoder(conf) + err = jsonParser.Decode(&config) + if err != nil { + fmt.Println(err.Error()) + return config, err + } + + // load custom config specified in OtherLocalConfig, if this is local + if isLocal && config.OtherLocalConfig != "" { + customConfig, err := loadCustomLocalConfig(config.OtherLocalConfig) + if err != nil { + // use the default local config + fmt.Printf("Testworld using config %s\n", localConfigFile) + return config, nil + } + fmt.Printf("Testworld using config %s\n", config.OtherLocalConfig) + return customConfig, nil + } else if isLocal { + // using the default local config + fmt.Printf("Testworld using config %s\n", localConfigFile) + } + return config, nil +} + +func loadCustomLocalConfig(customConfigFile string) (testConfig, error) { + var config testConfig + conf, err := os.Open(customConfigFile) + if err != nil { + fmt.Println(err.Error()) + return config, err + } + defer conf.Close() + jsonParser := json.NewDecoder(conf) + err = jsonParser.Decode(&config) if err != nil { fmt.Println(err.Error()) + return config, err } - defer configFile.Close() - jsonParser := json.NewDecoder(configFile) - jsonParser.Decode(&config) return config, nil } diff --git a/testworld/configs/.gitignore b/testworld/configs/.gitignore new file mode 100644 index 000000000..c2c027fec --- /dev/null +++ b/testworld/configs/.gitignore @@ -0,0 +1 @@ +local \ No newline at end of file diff --git a/testworld/configs/local.json b/testworld/configs/base.json similarity index 72% rename from testworld/configs/local.json rename to testworld/configs/base.json index 35f0215e9..eaa3fdd5a 100644 --- a/testworld/configs/local.json +++ b/testworld/configs/base.json @@ -1,4 +1,7 @@ { + "runPOAGeth": false, + "createHostConfigs": true, + "runMigrations": false, "ethNodeURL": "ws://127.0.0.1:9546", "accountKeyPath": "../build/scripts/test-dependencies/test-ethereum/migrateAccount.json", "accountPassword": "", diff --git a/testworld/httputils.go b/testworld/httputils.go index 1c9321a75..bb880ed42 100644 --- a/testworld/httputils.go +++ b/testworld/httputils.go @@ -1,3 +1,5 @@ +// +build testworld + package testworld import ( diff --git a/testworld/start_test.go b/testworld/start_test.go index 7cef275cb..3f2182946 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -21,29 +21,19 @@ const ( var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 -// Adjust these based on local testing requirments, please revert for CI server -var configFile = "configs/local.json" -var runPOAGeth = !isRunningOnCI - -// make this true this when running for the first time in local env -var createHostConfigs = isRunningOnCI - -// make this false if you want to make the tests run faster locally, but revert before committing to repo -var runMigrations = !isRunningOnCI - // doctorFord manages the hosts var doctorFord *hostManager func TestMain(m *testing.M) { - c, err := loadConfig(configFile) + c, err := loadConfig(!isRunningOnCI) if err != nil { panic(err) } - if runPOAGeth { + if c.RunPOAGeth { // NOTE that we don't bring down geth automatically right now because this must only be used for local testing purposes startPOAGeth() } - if runMigrations { + if c.RunMigrations { runSmartContractMigrations() } var contractAddresses *config.SmartContractAddresses @@ -51,7 +41,7 @@ func TestMain(m *testing.M) { contractAddresses = getSmartContractAddresses() } doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, c.TxPoolAccess, contractAddresses) - err = doctorFord.init(createHostConfigs) + err = doctorFord.init(c.CreateHostConfigs) if err != nil { panic(err) } From 88bd93e1bc9a1574f746f628ef5dbd54181773ee Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 22 Jan 2019 20:07:32 +0100 Subject: [PATCH 156/220] TW allow different network hostconfigs to co-exist without overwriting (#681) * Intermediate to keep testworld/hostconfigs/README.md and testworld/hostconfigs/.gitkeep * TW using hostconfigs * TW allow different network hostconfigs to co-exist without overwriting --- .gitignore | 2 +- config/configuration.go | 5 ++++- testworld/config.go | 21 +++++++++++++------ .../{peerconfigs => hostconfigs}/.gitkeep | 0 .../{peerconfigs => hostconfigs}/README.md | 0 testworld/park.go | 16 +++++++------- testworld/start_test.go | 4 ++-- 7 files changed, 31 insertions(+), 17 deletions(-) rename testworld/{peerconfigs => hostconfigs}/.gitkeep (100%) rename testworld/{peerconfigs => hostconfigs}/README.md (100%) diff --git a/.gitignore b/.gitignore index e16b3c59a..1827362cc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ coverage/ coverage.txt *.swp *.swo -testworld/peerconfigs/* \ No newline at end of file +testworld/hostconfigs/* \ No newline at end of file diff --git a/config/configuration.go b/config/configuration.go index 61ce2cd1f..f640574a5 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -469,7 +469,10 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { return nil, errors.New("targetDataDir not provided") } if _, err := os.Stat(targetDataDir); os.IsNotExist(err) { - os.Mkdir(targetDataDir, os.ModePerm) + err := os.MkdirAll(targetDataDir, os.ModePerm) + if err != nil { + return nil, err + } } if _, err := os.Stat(accountKeyPath); os.IsNotExist(err) { diff --git a/testworld/config.go b/testworld/config.go index 207ca08f5..4218d41ed 100644 --- a/testworld/config.go +++ b/testworld/config.go @@ -6,6 +6,8 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" + "strings" ) // configFile is the main configuration file, used mainly on CI @@ -41,7 +43,7 @@ type testConfig struct { TxPoolAccess bool `json:"txPoolAccess"` } -func loadConfig(isLocal bool) (testConfig, error) { +func loadConfig(isLocal bool) (testConfig, string, error) { c := configFile if isLocal { c = localConfigFile @@ -56,7 +58,7 @@ func loadConfig(isLocal bool) (testConfig, error) { return loadConfig(false) } else { fmt.Println(err.Error()) - return config, err + return config, "", err } } defer conf.Close() @@ -64,7 +66,7 @@ func loadConfig(isLocal bool) (testConfig, error) { err = jsonParser.Decode(&config) if err != nil { fmt.Println(err.Error()) - return config, err + return config, "", err } // load custom config specified in OtherLocalConfig, if this is local @@ -73,15 +75,16 @@ func loadConfig(isLocal bool) (testConfig, error) { if err != nil { // use the default local config fmt.Printf("Testworld using config %s\n", localConfigFile) - return config, nil + return config, extractConfigName(localConfigFile), nil } fmt.Printf("Testworld using config %s\n", config.OtherLocalConfig) - return customConfig, nil + return customConfig, extractConfigName(config.OtherLocalConfig), nil } else if isLocal { // using the default local config fmt.Printf("Testworld using config %s\n", localConfigFile) + return config, extractConfigName(localConfigFile), nil } - return config, nil + return config, extractConfigName(configFile), nil } func loadCustomLocalConfig(customConfigFile string) (testConfig, error) { @@ -100,3 +103,9 @@ func loadCustomLocalConfig(customConfigFile string) (testConfig, error) { } return config, nil } + +func extractConfigName(path string) string { + filename := filepath.Base(path) + parts := strings.Split(filename, ".") + return parts[0] +} diff --git a/testworld/peerconfigs/.gitkeep b/testworld/hostconfigs/.gitkeep similarity index 100% rename from testworld/peerconfigs/.gitkeep rename to testworld/hostconfigs/.gitkeep diff --git a/testworld/peerconfigs/README.md b/testworld/hostconfigs/README.md similarity index 100% rename from testworld/peerconfigs/README.md rename to testworld/hostconfigs/README.md diff --git a/testworld/park.go b/testworld/park.go index 958f60183..0baa5fd5f 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -53,7 +53,7 @@ type hostTestSuite struct { type hostManager struct { // network settings - ethNodeUrl, accountKeyPath, accountPassword, network string + ethNodeUrl, accountKeyPath, accountPassword, network, twConfigName string txPoolAccess bool @@ -78,13 +78,14 @@ type hostManager struct { } func newHostManager( - ethNodeUrl, accountKeyPath, accountPassword, network string, + ethNodeUrl, accountKeyPath, accountPassword, network, twConfigName string, txPoolAccess bool, smartContractAddrs *config.SmartContractAddresses) *hostManager { return &hostManager{ ethNodeUrl: ethNodeUrl, accountKeyPath: accountKeyPath, accountPassword: accountPassword, + twConfigName: twConfigName, network: network, txPoolAccess: txPoolAccess, contractAddresses: smartContractAddrs, @@ -109,7 +110,7 @@ func (r *hostManager) startHost(name string) { func (r *hostManager) init(createConfig bool) error { r.cancCtx, r.canc = context.WithCancel(context.Background()) - r.bernard = r.createHost("Bernard", defaultP2PTimeout, 8081, 38201, createConfig, false, nil) + r.bernard = r.createHost("Bernard", r.twConfigName, defaultP2PTimeout, 8081, 38201, createConfig, false, nil) err := r.bernard.init() if err != nil { return err @@ -129,7 +130,7 @@ func (r *hostManager) init(createConfig bool) error { // start hosts for _, h := range hostConfig { - r.niceHosts[h.name] = r.createHost(h.name, defaultP2PTimeout, h.apiPort, h.p2pPort, createConfig, h.multiAccount, []string{bootnode}) + r.niceHosts[h.name] = r.createHost(h.name, r.twConfigName, defaultP2PTimeout, h.apiPort, h.p2pPort, createConfig, h.multiAccount, []string{bootnode}) err := r.niceHosts[h.name].init() if err != nil { @@ -168,13 +169,14 @@ func (r *hostManager) stop() { r.canc() } -func (r *hostManager) createHost(name, p2pTimeout string, apiPort, p2pPort int64, createConfig, multiAccount bool, bootstraps []string) *host { +func (r *hostManager) createHost(name, twConfigName, p2pTimeout string, apiPort, p2pPort int64, createConfig, multiAccount bool, bootstraps []string) *host { return newHost( name, r.ethNodeUrl, r.accountKeyPath, r.accountPassword, r.network, + twConfigName, p2pTimeout, apiPort, p2pPort, bootstraps, r.txPoolAccess, @@ -213,7 +215,7 @@ type host struct { } func newHost( - name, ethNodeUrl, accountKeyPath, accountPassword, network, p2pTimeout string, + name, ethNodeUrl, accountKeyPath, accountPassword, network, twConfigName, p2pTimeout string, apiPort, p2pPort int64, bootstraps []string, txPoolAccess, createConfig, multiAccount bool, @@ -231,7 +233,7 @@ func newHost( bootstrapNodes: bootstraps, txPoolAccess: txPoolAccess, smartContractAddrs: smartContractAddrs, - dir: "peerconfigs/" + name, + dir: fmt.Sprintf("hostconfigs/%s/%s", twConfigName, name), createConfig: createConfig, multiAccount: multiAccount, } diff --git a/testworld/start_test.go b/testworld/start_test.go index 3f2182946..d141c1cb2 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -25,7 +25,7 @@ var isRunningOnCI = len(os.Getenv("TRAVIS")) != 0 var doctorFord *hostManager func TestMain(m *testing.M) { - c, err := loadConfig(!isRunningOnCI) + c, configName, err := loadConfig(!isRunningOnCI) if err != nil { panic(err) } @@ -40,7 +40,7 @@ func TestMain(m *testing.M) { if c.Network == "testing" { contractAddresses = getSmartContractAddresses() } - doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, c.TxPoolAccess, contractAddresses) + doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, configName, c.TxPoolAccess, contractAddresses) err = doctorFord.init(c.CreateHostConfigs) if err != nil { panic(err) From 8d5445a8de44a269405009125005097cfd63c77f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 23 Jan 2019 14:16:35 +0100 Subject: [PATCH 157/220] Ropsten (#683) * [WIP] Ropsten - waiting for contract addresses * Contract addresses --- build/configs/default_config.yaml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index ea8af48ca..77eb3d56a 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -15,7 +15,7 @@ networks: anchorRepository: "" paymentObligation: "" - # Main development testnet network + # Main development testnet network (Rinkeby) russianhill: # Numeric ID of the Centrifuge network id: 51 @@ -32,6 +32,7 @@ networks: anchorRepository: "0x7f854dfa98012d7fa55c803bba2260bcdee4b5ed" paymentObligation: "0xdb0581A9328664855328AdDb0E251184640f9e5D" + # Kovan test network bernalheights: ### # Kovan FAQ @@ -55,6 +56,23 @@ networks: anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" paymentObligation: "0x0417eb37941164368401D666984cED7694ABcBb1" + # Ropsten test network + dogpatch: + # Numeric ID of the Centrifuge network + id: 53 + # Bootstrap list of nodes that Centrifuge provides to the dogpatch (TODO create ropsten bootnodes) + bootstrapPeers: + - "/ip4/35.225.200.42/tcp/38202/ipfs/12D3KooWLiicQVwThTBY6xKcPoLf6RQYJFpwf1r75wLx2ZR3pCd1" + - "/ip4/35.225.86.210/tcp/38202/ipfs/12D3KooWQZMA8GPHrvEZB9wdkoUcAAmCZHp9eyyZ4SE8gFr3hTNX" + # Ethereum network ID - Ropsten + ethereumNetworkId: 3 + # Latest deployed Smart Contracts for the given testnet + contractAddresses: + identityFactory: "0x546EF82C503ef306e1fA4775f30068b4d9e20814" + identityRegistry: "0x55160B12091c41E7C41f0BA5Ae925a0426c4aAEA" + anchorRepository: "0x31f760e704F37755d1Ca4fB5eDA6D755E107Ae11" + paymentObligation: "0x3Ea32C24A525E7e8a6191C923793052F77b65936" + # Data Storage storage: # Path for levelDB file From 652d51bc213c2ca7fdba5931727298578c00e7a7 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 23 Jan 2019 14:22:49 +0100 Subject: [PATCH 158/220] identity: added initial code for new identity (#685) --- Gopkg.lock | 8 + Gopkg.toml | 10 +- identity/did/bootstrapper.go | 147 +++++ identity/did/bootstrapper_test.go | 14 + identity/did/factory_contract.go | 334 +++++++++++ identity/did/identity.go | 20 + identity/did/identity_contract.go | 689 +++++++++++++++++++++++ identity/did/service.go | 74 +++ identity/did/service_integration_test.go | 64 +++ identity/did/test_bootstrapper.go | 11 + 10 files changed, 1370 insertions(+), 1 deletion(-) create mode 100644 identity/did/bootstrapper.go create mode 100644 identity/did/bootstrapper_test.go create mode 100644 identity/did/factory_contract.go create mode 100644 identity/did/identity.go create mode 100644 identity/did/identity_contract.go create mode 100644 identity/did/service.go create mode 100644 identity/did/service_integration_test.go create mode 100644 identity/did/test_bootstrapper.go diff --git a/Gopkg.lock b/Gopkg.lock index b7b6a116f..aefe97ee2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -847,6 +847,13 @@ revision = "c2353362d570a7bfa228149c62842019201cfb71" version = "v1.8.0" +[[projects]] + digest = "1:bedc0b304fccce285e74ebae57d61c4b190b1a420b0c07afb1d4c2da56d164b8" + name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" + packages = ["."] + pruneopts = "T" + revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" + [[projects]] digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" name = "github.com/mattn/go-colorable" @@ -1536,6 +1543,7 @@ "github.com/libp2p/go-libp2p-peerstore", "github.com/libp2p/go-libp2p-protocol", "github.com/magiconair/properties/assert", + "github.com/manuelpolzhofer/centrifuge-ethereum-contracts", "github.com/mitchellh/go-homedir", "github.com/multiformats/go-multiaddr", "github.com/multiformats/go-multihash", diff --git a/Gopkg.toml b/Gopkg.toml index 57d7d1346..74626bde1 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -24,7 +24,7 @@ # go-tests = true # unused-packages = true -required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/roboll/go-vendorinstall", "github.com/golang/protobuf/protoc-gen-go", "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway", "golang.org/x/tools/cmd/goimports"] +required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/manuelpolzhofer/centrifuge-ethereum-contracts", "github.com/roboll/go-vendorinstall", "github.com/golang/protobuf/protoc-gen-go", "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway", "golang.org/x/tools/cmd/goimports"] [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" @@ -34,6 +34,10 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/centrifuge/centrifuge-ethereum-contracts" revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" +[[override]] + name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" + revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" + [[constraint]] name = "github.com/Masterminds/semver" version = "1.4.2" @@ -270,6 +274,10 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r name = "github.com/centrifuge/centrifuge-ethereum-contracts" unused-packages = false +[[prune.project]] + name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" + unused-packages = false + [[prune.project]] name = "github.com/ethereum/go-ethereum" unused-packages = false diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go new file mode 100644 index 000000000..0ae2882c1 --- /dev/null +++ b/identity/did/bootstrapper.go @@ -0,0 +1,147 @@ +package did + +import ( + "io/ioutil" + "os" + "os/exec" + "path" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/savaki/jq" +) + +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} + +// BootstrappedDIDService stores the id of the bootstrapper +const BootstrappedDIDService string = "BootstrappedDIDService" + +var smartContractAddresses *config.SmartContractAddresses + +// Bootstrap initializes the factory contract +func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + cfg, err := configstore.RetrieveConfig(false, context) + if err != nil { + return err + } + + if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { + return errors.New("ethereum client hasn't been initialized") + } + client := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + // TODO line will be removed after migration + migrateNewIdentityContracts() + + factoryContract, err := bindFactory(getFactoryAddress(), client) + if err != nil { + return err + } + + service := NewService(cfg, factoryContract, client) + + context[BootstrappedDIDService] = service + + return nil +} + +func bindFactory(factoryAddress common.Address, client ethereum.Client) (*FactoryContract, error) { + return NewFactoryContract(factoryAddress, client.GetEthClient()) +} + +func getFactoryAddress() common.Address { + return common.HexToAddress(smartContractAddresses.IdentityFactoryAddr) + +} + +// Note: this block will be removed after the identity migration is done +// currently we are using two versions of centrifuge contracts to not break the compatiblitiy +// --------------------------------------------------------------------------------------------------------------------- +func migrateNewIdentityContracts() { + runNewSmartContractMigrations() + smartContractAddresses = getSmartContractAddresses() + +} + +// RunNewSmartContractMigrations migrates smart contracts to localgeth +// TODO: func will be removed after migration +func runNewSmartContractMigrations() { + + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") + + smartContractDir := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts") + smartContractDirStandard := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts") + + os.Setenv("CENT_ETHEREUM_CONTRACTS_DIR", smartContractDir) + + migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") + _, err := exec.Command(migrationScript, projDir).Output() + if err != nil { + log.Fatal(err) + } + os.Setenv("CENT_ETHEREUM_CONTRACTS_DIR", smartContractDirStandard) + +} + +// GetSmartContractAddresses finds migrated smart contract addresses for localgeth +// TODO: func will be removed after migration +func getSmartContractAddresses() *config.SmartContractAddresses { + dat, err := findContractDeployJSON() + if err != nil { + panic(err) + } + idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") + anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") + payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") + return &config.SmartContractAddresses{ + IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), + AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), + PaymentObligationAddr: getOpAddr(payObAddrOp, dat), + } +} + +// TODO: func will be removed after migration +func findContractDeployJSON() ([]byte, error) { + gp := os.Getenv("GOPATH") + projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") + deployJSONFile := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + dat, err := ioutil.ReadFile(deployJSONFile) + if err != nil { + return nil, err + } + return dat, nil +} + +// TODO: func will be removed after migration +func getOpForContract(selector string) jq.Op { + addrOp, err := jq.Parse(selector) + if err != nil { + panic(err) + } + return addrOp +} + +// TODO: func will be removed after migration +func getOpAddr(addrOp jq.Op, dat []byte) string { + addr, err := addrOp.Apply(dat) + if err != nil { + panic(err) + } + + // remove extra quotes inside the string + addrStr := string(addr) + if len(addrStr) > 0 && addrStr[0] == '"' { + addrStr = addrStr[1:] + } + if len(addrStr) > 0 && addrStr[len(addrStr)-1] == '"' { + addrStr = addrStr[:len(addrStr)-1] + } + return addrStr +} + +// --------------------------------------------------------------------------------------------------------------------- diff --git a/identity/did/bootstrapper_test.go b/identity/did/bootstrapper_test.go new file mode 100644 index 000000000..56a374dfe --- /dev/null +++ b/identity/did/bootstrapper_test.go @@ -0,0 +1,14 @@ +// +build unit + +package did + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBootstrapper_Bootstrap(t *testing.T) { + err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) + assert.Error(t, err, "Should throw an error because of empty context") +} diff --git a/identity/did/factory_contract.go b/identity/did/factory_contract.go new file mode 100644 index 000000000..768dd282a --- /dev/null +++ b/identity/did/factory_contract.go @@ -0,0 +1,334 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package did + +import ( + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// FactoryContractABI is the input ABI used to generate the binding from. +const FactoryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\",\"signature\":\"0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0\"},{\"constant\":false,\"inputs\":[],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x59d21ad9\"},{\"constant\":false,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"createIdentityFor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa480f9f7\"}]" + +// FactoryContract is an auto generated Go binding around an Ethereum contract. +type FactoryContract struct { + FactoryContractCaller // Read-only binding to the contract + FactoryContractTransactor // Write-only binding to the contract + FactoryContractFilterer // Log filterer for contract events +} + +// FactoryContractCaller is an auto generated read-only Go binding around an Ethereum contract. +type FactoryContractCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FactoryContractTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FactoryContractTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FactoryContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FactoryContractFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FactoryContractSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FactoryContractSession struct { + Contract *FactoryContract // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FactoryContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FactoryContractCallerSession struct { + Contract *FactoryContractCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FactoryContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FactoryContractTransactorSession struct { + Contract *FactoryContractTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FactoryContractRaw is an auto generated low-level Go binding around an Ethereum contract. +type FactoryContractRaw struct { + Contract *FactoryContract // Generic contract binding to access the raw methods on +} + +// FactoryContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FactoryContractCallerRaw struct { + Contract *FactoryContractCaller // Generic read-only contract binding to access the raw methods on +} + +// FactoryContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FactoryContractTransactorRaw struct { + Contract *FactoryContractTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFactoryContract creates a new instance of FactoryContract, bound to a specific deployed contract. +func NewFactoryContract(address common.Address, backend bind.ContractBackend) (*FactoryContract, error) { + contract, err := bindFactoryContract(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FactoryContract{FactoryContractCaller: FactoryContractCaller{contract: contract}, FactoryContractTransactor: FactoryContractTransactor{contract: contract}, FactoryContractFilterer: FactoryContractFilterer{contract: contract}}, nil +} + +// NewFactoryContractCaller creates a new read-only instance of FactoryContract, bound to a specific deployed contract. +func NewFactoryContractCaller(address common.Address, caller bind.ContractCaller) (*FactoryContractCaller, error) { + contract, err := bindFactoryContract(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FactoryContractCaller{contract: contract}, nil +} + +// NewFactoryContractTransactor creates a new write-only instance of FactoryContract, bound to a specific deployed contract. +func NewFactoryContractTransactor(address common.Address, transactor bind.ContractTransactor) (*FactoryContractTransactor, error) { + contract, err := bindFactoryContract(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FactoryContractTransactor{contract: contract}, nil +} + +// NewFactoryContractFilterer creates a new log filterer instance of FactoryContract, bound to a specific deployed contract. +func NewFactoryContractFilterer(address common.Address, filterer bind.ContractFilterer) (*FactoryContractFilterer, error) { + contract, err := bindFactoryContract(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FactoryContractFilterer{contract: contract}, nil +} + +// bindFactoryContract binds a generic wrapper to an already deployed contract. +func bindFactoryContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(FactoryContractABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FactoryContract *FactoryContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _FactoryContract.Contract.FactoryContractCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FactoryContract *FactoryContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FactoryContract.Contract.FactoryContractTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FactoryContract *FactoryContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FactoryContract.Contract.FactoryContractTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FactoryContract *FactoryContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _FactoryContract.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FactoryContract *FactoryContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FactoryContract.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FactoryContract *FactoryContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FactoryContract.Contract.contract.Transact(opts, method, params...) +} + +// CreateIdentity is a paid mutator transaction binding the contract method 0x59d21ad9. +// +// Solidity: function createIdentity() returns() +func (_FactoryContract *FactoryContractTransactor) CreateIdentity(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FactoryContract.contract.Transact(opts, "createIdentity") +} + +// CreateIdentity is a paid mutator transaction binding the contract method 0x59d21ad9. +// +// Solidity: function createIdentity() returns() +func (_FactoryContract *FactoryContractSession) CreateIdentity() (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentity(&_FactoryContract.TransactOpts) +} + +// CreateIdentity is a paid mutator transaction binding the contract method 0x59d21ad9. +// +// Solidity: function createIdentity() returns() +func (_FactoryContract *FactoryContractTransactorSession) CreateIdentity() (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentity(&_FactoryContract.TransactOpts) +} + +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// +// Solidity: function createIdentityFor(owner address) returns() +func (_FactoryContract *FactoryContractTransactor) CreateIdentityFor(opts *bind.TransactOpts, owner common.Address) (*types.Transaction, error) { + return _FactoryContract.contract.Transact(opts, "createIdentityFor", owner) +} + +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// +// Solidity: function createIdentityFor(owner address) returns() +func (_FactoryContract *FactoryContractSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) +} + +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// +// Solidity: function createIdentityFor(owner address) returns() +func (_FactoryContract *FactoryContractTransactorSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) +} + +// FactoryContractIdentityCreatedIterator is returned from FilterIdentityCreated and is used to iterate over the raw logs and unpacked data for IdentityCreated events raised by the FactoryContract contract. +type FactoryContractIdentityCreatedIterator struct { + Event *FactoryContractIdentityCreated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FactoryContractIdentityCreatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FactoryContractIdentityCreated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FactoryContractIdentityCreated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FactoryContractIdentityCreatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FactoryContractIdentityCreatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FactoryContractIdentityCreated represents a IdentityCreated event raised by the FactoryContract contract. +type FactoryContractIdentityCreated struct { + Identity common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterIdentityCreated is a free log retrieval operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. +// +// Solidity: e IdentityCreated(identity indexed address) +func (_FactoryContract *FactoryContractFilterer) FilterIdentityCreated(opts *bind.FilterOpts, identity []common.Address) (*FactoryContractIdentityCreatedIterator, error) { + + var identityRule []interface{} + for _, identityItem := range identity { + identityRule = append(identityRule, identityItem) + } + + logs, sub, err := _FactoryContract.contract.FilterLogs(opts, "IdentityCreated", identityRule) + if err != nil { + return nil, err + } + return &FactoryContractIdentityCreatedIterator{contract: _FactoryContract.contract, event: "IdentityCreated", logs: logs, sub: sub}, nil +} + +// WatchIdentityCreated is a free log subscription operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. +// +// Solidity: e IdentityCreated(identity indexed address) +func (_FactoryContract *FactoryContractFilterer) WatchIdentityCreated(opts *bind.WatchOpts, sink chan<- *FactoryContractIdentityCreated, identity []common.Address) (event.Subscription, error) { + + var identityRule []interface{} + for _, identityItem := range identity { + identityRule = append(identityRule, identityItem) + } + + logs, sub, err := _FactoryContract.contract.WatchLogs(opts, "IdentityCreated", identityRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FactoryContractIdentityCreated) + if err := _FactoryContract.contract.UnpackLog(event, "IdentityCreated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} diff --git a/identity/did/identity.go b/identity/did/identity.go new file mode 100644 index 000000000..5af25e04d --- /dev/null +++ b/identity/did/identity.go @@ -0,0 +1,20 @@ +package did + +import "github.com/ethereum/go-ethereum/common" + +// DID stores the identity address of the user +type DID common.Address + +func (d DID) toAddress() common.Address { + return common.Address(d) +} + +// NewDID returns a DID based on a common.Address +func NewDID(address common.Address) DID { + return DID(address) +} + +// NewDIDFromString returns a DID based on a hex string +func NewDIDFromString(address string) DID { + return DID(common.HexToAddress(address)) +} diff --git a/identity/did/identity_contract.go b/identity/did/identity_contract.go new file mode 100644 index 000000000..624d4b9d6 --- /dev/null +++ b/identity/did/identity_contract.go @@ -0,0 +1,689 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package did + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// IdentityContractABI is the input ABI used to generate the binding from. +const IdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purposes\",\"type\":\"uint256[]\"},{\"name\":\"_keyType\",\"type\":\"uint256\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"},{\"name\":\"_keyType\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressToKey\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_toSign\",\"type\":\"bytes32\"},{\"name\":\"_signature\",\"type\":\"bytes\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"isSignedWithPurpose\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" + +// IdentityContract is an auto generated Go binding around an Ethereum contract. +type IdentityContract struct { + IdentityContractCaller // Read-only binding to the contract + IdentityContractTransactor // Write-only binding to the contract + IdentityContractFilterer // Log filterer for contract events +} + +// IdentityContractCaller is an auto generated read-only Go binding around an Ethereum contract. +type IdentityContractCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IdentityContractTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IdentityContractTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IdentityContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IdentityContractFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IdentityContractSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IdentityContractSession struct { + Contract *IdentityContract // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IdentityContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IdentityContractCallerSession struct { + Contract *IdentityContractCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IdentityContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IdentityContractTransactorSession struct { + Contract *IdentityContractTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IdentityContractRaw is an auto generated low-level Go binding around an Ethereum contract. +type IdentityContractRaw struct { + Contract *IdentityContract // Generic contract binding to access the raw methods on +} + +// IdentityContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IdentityContractCallerRaw struct { + Contract *IdentityContractCaller // Generic read-only contract binding to access the raw methods on +} + +// IdentityContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IdentityContractTransactorRaw struct { + Contract *IdentityContractTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIdentityContract creates a new instance of IdentityContract, bound to a specific deployed contract. +func NewIdentityContract(address common.Address, backend bind.ContractBackend) (*IdentityContract, error) { + contract, err := bindIdentityContract(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IdentityContract{IdentityContractCaller: IdentityContractCaller{contract: contract}, IdentityContractTransactor: IdentityContractTransactor{contract: contract}, IdentityContractFilterer: IdentityContractFilterer{contract: contract}}, nil +} + +// NewIdentityContractCaller creates a new read-only instance of IdentityContract, bound to a specific deployed contract. +func NewIdentityContractCaller(address common.Address, caller bind.ContractCaller) (*IdentityContractCaller, error) { + contract, err := bindIdentityContract(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IdentityContractCaller{contract: contract}, nil +} + +// NewIdentityContractTransactor creates a new write-only instance of IdentityContract, bound to a specific deployed contract. +func NewIdentityContractTransactor(address common.Address, transactor bind.ContractTransactor) (*IdentityContractTransactor, error) { + contract, err := bindIdentityContract(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IdentityContractTransactor{contract: contract}, nil +} + +// NewIdentityContractFilterer creates a new log filterer instance of IdentityContract, bound to a specific deployed contract. +func NewIdentityContractFilterer(address common.Address, filterer bind.ContractFilterer) (*IdentityContractFilterer, error) { + contract, err := bindIdentityContract(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IdentityContractFilterer{contract: contract}, nil +} + +// bindIdentityContract binds a generic wrapper to an already deployed contract. +func bindIdentityContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(IdentityContractABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IdentityContract *IdentityContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _IdentityContract.Contract.IdentityContractCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IdentityContract *IdentityContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IdentityContract.Contract.IdentityContractTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IdentityContract *IdentityContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IdentityContract.Contract.IdentityContractTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IdentityContract *IdentityContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _IdentityContract.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IdentityContract *IdentityContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IdentityContract.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IdentityContract *IdentityContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IdentityContract.Contract.contract.Transact(opts, method, params...) +} + +// AddressToKey is a free data retrieval call binding the contract method 0x574363c8. +// +// Solidity: function addressToKey(addr address) constant returns(bytes32) +func (_IdentityContract *IdentityContractCaller) AddressToKey(opts *bind.CallOpts, addr common.Address) ([32]byte, error) { + var ( + ret0 = new([32]byte) + ) + out := ret0 + err := _IdentityContract.contract.Call(opts, out, "addressToKey", addr) + return *ret0, err +} + +// AddressToKey is a free data retrieval call binding the contract method 0x574363c8. +// +// Solidity: function addressToKey(addr address) constant returns(bytes32) +func (_IdentityContract *IdentityContractSession) AddressToKey(addr common.Address) ([32]byte, error) { + return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) +} + +// AddressToKey is a free data retrieval call binding the contract method 0x574363c8. +// +// Solidity: function addressToKey(addr address) constant returns(bytes32) +func (_IdentityContract *IdentityContractCallerSession) AddressToKey(addr common.Address) ([32]byte, error) { + return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) +} + +// GetKey is a free data retrieval call binding the contract method 0x12aaac70. +// +// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) +func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, _key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +}, error) { + ret := new(struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }) + out := ret + err := _IdentityContract.contract.Call(opts, out, "getKey", _key) + return *ret, err +} + +// GetKey is a free data retrieval call binding the contract method 0x12aaac70. +// +// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) +func (_IdentityContract *IdentityContractSession) GetKey(_key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +}, error) { + return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, _key) +} + +// GetKey is a free data retrieval call binding the contract method 0x12aaac70. +// +// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) +func (_IdentityContract *IdentityContractCallerSession) GetKey(_key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +}, error) { + return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, _key) +} + +// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. +// +// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractCaller) GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) { + var ( + ret0 = new([][32]byte) + ) + out := ret0 + err := _IdentityContract.contract.Call(opts, out, "getKeysByPurpose", _purpose) + return *ret0, err +} + +// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. +// +// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { + return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, _purpose) +} + +// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. +// +// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractCallerSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { + return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, _purpose) +} + +// IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. +// +// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) +func (_IdentityContract *IdentityContractCaller) IsSignedWithPurpose(opts *bind.CallOpts, _toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _IdentityContract.contract.Call(opts, out, "isSignedWithPurpose", _toSign, _signature, _purpose) + return *ret0, err +} + +// IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. +// +// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) +func (_IdentityContract *IdentityContractSession) IsSignedWithPurpose(_toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, _toSign, _signature, _purpose) +} + +// IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. +// +// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) +func (_IdentityContract *IdentityContractCallerSession) IsSignedWithPurpose(_toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, _toSign, _signature, _purpose) +} + +// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. +// +// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) +func (_IdentityContract *IdentityContractCaller) KeyHasPurpose(opts *bind.CallOpts, _key [32]byte, _purpose *big.Int) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _IdentityContract.contract.Call(opts, out, "keyHasPurpose", _key, _purpose) + return *ret0, err +} + +// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. +// +// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) +func (_IdentityContract *IdentityContractSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, _key, _purpose) +} + +// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. +// +// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) +func (_IdentityContract *IdentityContractCallerSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, _key, _purpose) +} + +// AddKey is a paid mutator transaction binding the contract method 0x1d381240. +// +// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() +func (_IdentityContract *IdentityContractTransactor) AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "addKey", _key, _purpose, _keyType) +} + +// AddKey is a paid mutator transaction binding the contract method 0x1d381240. +// +// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() +func (_IdentityContract *IdentityContractSession) AddKey(_key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, _key, _purpose, _keyType) +} + +// AddKey is a paid mutator transaction binding the contract method 0x1d381240. +// +// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() +func (_IdentityContract *IdentityContractTransactorSession) AddKey(_key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, _key, _purpose, _keyType) +} + +// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. +// +// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() +func (_IdentityContract *IdentityContractTransactor) AddMultiPurposeKey(opts *bind.TransactOpts, _key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "addMultiPurposeKey", _key, _purposes, _keyType) +} + +// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. +// +// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() +func (_IdentityContract *IdentityContractSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, _key, _purposes, _keyType) +} + +// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. +// +// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() +func (_IdentityContract *IdentityContractTransactorSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, _key, _purposes, _keyType) +} + +// Execute is a paid mutator transaction binding the contract method 0xb61d27f6. +// +// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) +func (_IdentityContract *IdentityContractTransactor) Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "execute", _to, _value, _data) +} + +// Execute is a paid mutator transaction binding the contract method 0xb61d27f6. +// +// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) +func (_IdentityContract *IdentityContractSession) Execute(_to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { + return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, _to, _value, _data) +} + +// Execute is a paid mutator transaction binding the contract method 0xb61d27f6. +// +// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) +func (_IdentityContract *IdentityContractTransactorSession) Execute(_to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { + return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, _to, _value, _data) +} + +// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. +// +// Solidity: function revokeKey(_key bytes32) returns() +func (_IdentityContract *IdentityContractTransactor) RevokeKey(opts *bind.TransactOpts, _key [32]byte) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "revokeKey", _key) +} + +// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. +// +// Solidity: function revokeKey(_key bytes32) returns() +func (_IdentityContract *IdentityContractSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { + return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, _key) +} + +// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. +// +// Solidity: function revokeKey(_key bytes32) returns() +func (_IdentityContract *IdentityContractTransactorSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { + return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, _key) +} + +// IdentityContractKeyAddedIterator is returned from FilterKeyAdded and is used to iterate over the raw logs and unpacked data for KeyAdded events raised by the IdentityContract contract. +type IdentityContractKeyAddedIterator struct { + Event *IdentityContractKeyAdded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IdentityContractKeyAddedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IdentityContractKeyAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IdentityContractKeyAdded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IdentityContractKeyAddedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IdentityContractKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IdentityContractKeyAdded represents a KeyAdded event raised by the IdentityContract contract. +type IdentityContractKeyAdded struct { + Key [32]byte + Purpose *big.Int + KeyType *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterKeyAdded is a free log retrieval operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. +// +// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) +func (_IdentityContract *IdentityContractFilterer) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (*IdentityContractKeyAddedIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + var purposeRule []interface{} + for _, purposeItem := range purpose { + purposeRule = append(purposeRule, purposeItem) + } + var keyTypeRule []interface{} + for _, keyTypeItem := range keyType { + keyTypeRule = append(keyTypeRule, keyTypeItem) + } + + logs, sub, err := _IdentityContract.contract.FilterLogs(opts, "KeyAdded", keyRule, purposeRule, keyTypeRule) + if err != nil { + return nil, err + } + return &IdentityContractKeyAddedIterator{contract: _IdentityContract.contract, event: "KeyAdded", logs: logs, sub: sub}, nil +} + +// WatchKeyAdded is a free log subscription operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. +// +// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) +func (_IdentityContract *IdentityContractFilterer) WatchKeyAdded(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyAdded, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + var purposeRule []interface{} + for _, purposeItem := range purpose { + purposeRule = append(purposeRule, purposeItem) + } + var keyTypeRule []interface{} + for _, keyTypeItem := range keyType { + keyTypeRule = append(keyTypeRule, keyTypeItem) + } + + logs, sub, err := _IdentityContract.contract.WatchLogs(opts, "KeyAdded", keyRule, purposeRule, keyTypeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IdentityContractKeyAdded) + if err := _IdentityContract.contract.UnpackLog(event, "KeyAdded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// IdentityContractKeyRevokedIterator is returned from FilterKeyRevoked and is used to iterate over the raw logs and unpacked data for KeyRevoked events raised by the IdentityContract contract. +type IdentityContractKeyRevokedIterator struct { + Event *IdentityContractKeyRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IdentityContractKeyRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IdentityContractKeyRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IdentityContractKeyRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IdentityContractKeyRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IdentityContractKeyRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IdentityContractKeyRevoked represents a KeyRevoked event raised by the IdentityContract contract. +type IdentityContractKeyRevoked struct { + Key [32]byte + RevokedAt *big.Int + KeyType *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterKeyRevoked is a free log retrieval operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. +// +// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) +func (_IdentityContract *IdentityContractFilterer) FilterKeyRevoked(opts *bind.FilterOpts, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (*IdentityContractKeyRevokedIterator, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + var revokedAtRule []interface{} + for _, revokedAtItem := range revokedAt { + revokedAtRule = append(revokedAtRule, revokedAtItem) + } + var keyTypeRule []interface{} + for _, keyTypeItem := range keyType { + keyTypeRule = append(keyTypeRule, keyTypeItem) + } + + logs, sub, err := _IdentityContract.contract.FilterLogs(opts, "KeyRevoked", keyRule, revokedAtRule, keyTypeRule) + if err != nil { + return nil, err + } + return &IdentityContractKeyRevokedIterator{contract: _IdentityContract.contract, event: "KeyRevoked", logs: logs, sub: sub}, nil +} + +// WatchKeyRevoked is a free log subscription operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. +// +// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) +func (_IdentityContract *IdentityContractFilterer) WatchKeyRevoked(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyRevoked, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (event.Subscription, error) { + + var keyRule []interface{} + for _, keyItem := range key { + keyRule = append(keyRule, keyItem) + } + var revokedAtRule []interface{} + for _, revokedAtItem := range revokedAt { + revokedAtRule = append(revokedAtRule, revokedAtItem) + } + var keyTypeRule []interface{} + for _, keyTypeItem := range keyType { + keyTypeRule = append(keyTypeRule, keyTypeItem) + } + + logs, sub, err := _IdentityContract.contract.WatchLogs(opts, "KeyRevoked", keyRule, revokedAtRule, keyTypeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IdentityContractKeyRevoked) + if err := _IdentityContract.contract.UnpackLog(event, "KeyRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} diff --git a/identity/did/service.go b/identity/did/service.go new file mode 100644 index 000000000..c9550088f --- /dev/null +++ b/identity/did/service.go @@ -0,0 +1,74 @@ +package did + +import ( + "context" + + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + logging "github.com/ipfs/go-log" +) + +var log = logging.Logger("identity") + +// Service is the interface for identity related interactions +type Service interface { + CreateIdentity(ctx context.Context) (id *DID, confirmations chan *identity.WatchIdentity, err error) +} + +type service struct { + config identity.Config + factoryContract *FactoryContract + client ethereum.Client +} + +// NewService returns a new identity service +func NewService(config identity.Config, factoryContract *FactoryContract, client ethereum.Client) Service { + + return &service{config: config, factoryContract: factoryContract, client: client} +} + +func (s *service) getNonceAt(ctx context.Context, address common.Address) (uint64, error) { + // TODO: add blockNumber of the transaction which created the contract + return s.client.GetEthClient().NonceAt(ctx, getFactoryAddress(), nil) +} + +// CalculateCreatedAddress calculates the Ethereum address based on address and nonce +func CalculateCreatedAddress(address common.Address, nonce uint64) common.Address { + // How is a Ethereum address calculated: + // See https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed + return crypto.CreateAddress(address, nonce) +} + +func (s *service) CreateIdentity(ctx context.Context) (id *DID, confirmations chan *identity.WatchIdentity, err error) { + opts, err := s.client.GetTxOpts(s.config.GetEthereumDefaultAccountName()) + if err != nil { + log.Infof("Failed to get txOpts from Ethereum client: %v", err) + return nil, nil, err + } + + tx, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) + if err != nil { + log.Infof("Failed to send identity for creation [txHash: %s] : %v", tx.Hash(), err) + return nil, nil, err + } + + log.Infof("Sent off identity creation Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", tx.Hash(), tx.Nonce(), tx.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", tx.Hash()) + + // TODO use transactionStatusTask and following code as a statusHandler + + factoryAddress := getFactoryAddress() + nonce, err := s.getNonceAt(ctx, factoryAddress) + if err != nil { + return nil, nil, err + } + + identityAddress := CalculateCreatedAddress(factoryAddress, nonce) + log.Infof("Address of created identity contract: 0x%x\n", identityAddress) + + did := NewDID(identityAddress) + + return &did, nil, nil +} diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go new file mode 100644 index 000000000..3ed1242cd --- /dev/null +++ b/identity/did/service_integration_test.go @@ -0,0 +1,64 @@ +// +build integration + +package did + +import ( + "context" + "fmt" + "os" + "testing" + "time" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/stretchr/testify/assert" +) + +var cfg config.Configuration +var ctx = map[string]interface{}{} + +func TestMain(m *testing.M) { + var bootstappers = []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + transactions.Bootstrapper{}, + &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, + ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + &Bootstrapper{}, + &queue.Starter{}, + } + + bootstrap.RunTestBootstrappers(bootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(bootstappers) + os.Exit(result) +} + +func TestCreateIdentity_successful(t *testing.T) { + service := ctx[BootstrappedDIDService].(Service) + did, _, err := service.CreateIdentity(context.Background()) + assert.Nil(t, err, "create identity should be successful") + + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + time.Sleep(2000 * time.Millisecond) + + contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) + assert.Nil(t, err, "should be successful to get the contract code") + + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + + fmt.Println(did) + +} diff --git a/identity/did/test_bootstrapper.go b/identity/did/test_bootstrapper.go new file mode 100644 index 000000000..a88ae38c3 --- /dev/null +++ b/identity/did/test_bootstrapper.go @@ -0,0 +1,11 @@ +// +build integration unit + +package did + +func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { + return b.Bootstrap(context) +} + +func (*Bootstrapper) TestTearDown() error { + return nil +} From c0b07d42b0a8e177763d27aa6a8ec228f40fe650 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 23 Jan 2019 21:51:43 +0100 Subject: [PATCH 159/220] Fix for parity - This request is not supported because your node is running with state pruning. Run with --pruning=archive. - for GET rpc calls (#676) * Fix parity - This request is not supported because your node is running with state pruning. Run with --pruning=archive. - for GET rpc calls * Ropsten fixes --- anchors/ethereum_anchor_repository.go | 2 +- build/configs/default_config.yaml | 2 ++ cmd/common.go | 6 +++--- config/configstore/model.go | 6 ++++++ config/configstore/model_test.go | 6 ++++++ config/configuration.go | 6 ++++++ ethereum/geth_client.go | 6 +++--- ethereum/geth_client_test.go | 2 +- identity/ethid/ethereum_identity.go | 10 +++++----- nft/ethereum_payment_obligation.go | 2 +- queue/server.go | 8 +++++++- resources/data.go | 8 ++++---- testingutils/commons/mock_ethclient.go | 2 +- testworld/nft_test.go | 6 ++++-- 14 files changed, 50 insertions(+), 22 deletions(-) diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go index 709c826d8..e4f2a3f15 100644 --- a/anchors/ethereum_anchor_repository.go +++ b/anchors/ethereum_anchor_repository.go @@ -44,7 +44,7 @@ func newEthereumAnchorRepository(config Config, anchorRepositoryContract anchorR // GetDocumentRootOf takes an anchorID and returns the corresponding documentRoot from the chain. func (ethRepository *ethereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethRepository.gethClientFinder().GetGethCallOpts() + opts, _ := ethRepository.gethClientFinder().GetGethCallOpts(false) return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) } diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 77eb3d56a..0a20ccd14 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -107,6 +107,8 @@ queue: numWorkers: 2 # Frees up CPU cycles when worker is waiting for events workerWaitTimeMS: 1 + # Number of retries allowed for a task + taskRetries: 10 # Ethereum specific configuration ethereum: diff --git a/cmd/common.go b/cmd/common.go index beed5aba0..418803d6c 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -43,15 +43,15 @@ func generateKeys(config config.Configuration) { func addKeys(config config.Configuration, idService identity.Service) error { err := idService.AddKeyFromConfig(config, identity.KeyPurposeP2P) if err != nil { - panic(err) + return err } err = idService.AddKeyFromConfig(config, identity.KeyPurposeSigning) if err != nil { - panic(err) + return err } err = idService.AddKeyFromConfig(config, identity.KeyPurposeEthMsgAuth) if err != nil { - panic(err) + return err } return nil } diff --git a/config/configstore/model.go b/config/configstore/model.go index da425506e..5f03341e9 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -39,6 +39,7 @@ type NodeConfig struct { ServerPort int ServerAddress string NumWorkers int + TaskRetries int WorkerWaitTimeMS int EthereumNodeURL string EthereumContextReadWaitTimeout time.Duration @@ -145,6 +146,11 @@ func (nc *NodeConfig) GetNumWorkers() int { return nc.NumWorkers } +// GetTaskRetries returns the number of retries allowed for a queued task +func (nc *NodeConfig) GetTaskRetries() int { + return nc.TaskRetries +} + // GetWorkerWaitTimeMS refer the interface func (nc *NodeConfig) GetWorkerWaitTimeMS() int { return nc.WorkerWaitTimeMS diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 6a8b42d66..0f8561512 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -140,6 +140,12 @@ func (m *mockConfig) GetNumWorkers() int { return args.Get(0).(int) } +// GetTaskRetries returns the number of retries allowed for a queued task +func (m *mockConfig) GetTaskRetries() int { + args := m.Called() + return args.Get(0).(int) +} + func (m *mockConfig) GetWorkerWaitTimeMS() int { args := m.Called() return args.Get(0).(int) diff --git a/config/configuration.go b/config/configuration.go index f640574a5..77496cedb 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -81,6 +81,7 @@ type Configuration interface { GetServerAddress() string GetNumWorkers() int GetWorkerWaitTimeMS() int + GetTaskRetries() int GetEthereumNodeURL() string GetEthereumContextReadWaitTimeout() time.Duration GetEthereumContextWaitTimeout() time.Duration @@ -271,6 +272,11 @@ func (c *configuration) GetNumWorkers() int { return c.GetInt("queue.numWorkers") } +// GetTaskRetries returns the number of retries allowed for a queued task +func (c *configuration) GetTaskRetries() int { + return c.GetInt("queue.taskRetries") +} + // GetWorkerWaitTimeMS returns the queue worker sleep time between cycles. func (c *configuration) GetWorkerWaitTimeMS() int { return c.GetInt("queue.workerWaitTimeMS") diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 79870b2c4..7cd1304f3 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -75,7 +75,7 @@ type Client interface { SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (tx *types.Transaction, err error) // GetGethCallOpts returns the Call options with default - GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) + GetGethCallOpts(pending bool) (*bind.CallOpts, context.CancelFunc) // TransactionByHash returns a Ethereum transaction TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) @@ -303,12 +303,12 @@ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, o } // GetGethCallOpts returns the Call options with default -func (gc *gethClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { +func (gc *gethClient) GetGethCallOpts(pending bool) (*bind.CallOpts, context.CancelFunc) { // Assuring that pending transactions are taken into account by go-ethereum when asking for things like // specific transactions and client's nonce // with timeout context, in case eth node is not in sync ctx, cancel := gc.defaultReadContext() - return &bind.CallOpts{Pending: true, Context: ctx}, cancel + return &bind.CallOpts{Pending: pending, Context: ctx}, cancel } // noncer defines functions to get the next nonce diff --git a/ethereum/geth_client_test.go b/ethereum/geth_client_test.go index eda9c0271..dfcfe48d3 100644 --- a/ethereum/geth_client_test.go +++ b/ethereum/geth_client_test.go @@ -96,7 +96,7 @@ func TestInitTransactionWithRetries(t *testing.T) { } func TestGetGethCallOpts(t *testing.T) { - opts, cancel := GetClient().GetGethCallOpts() + opts, cancel := GetClient().GetGethCallOpts(true) assert.NotNil(t, opts) assert.True(t, opts.Pending) assert.NotNil(t, cancel) diff --git a/identity/ethid/ethereum_identity.go b/identity/ethid/ethereum_identity.go index c8f5c0247..a35295fb3 100644 --- a/identity/ethid/ethereum_identity.go +++ b/identity/ethid/ethereum_identity.go @@ -131,7 +131,7 @@ func (id *ethereumIdentity) FetchKey(key []byte) (identity.Key, error) { return nil, err } // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := id.gethClientFinder().GetGethCallOpts() + opts, _ := id.gethClientFinder().GetGethCallOpts(false) key32, _ := utils.SliceToByte32(key) keyInstance, err := contract.GetKey(opts, key32) if err != nil { @@ -168,7 +168,7 @@ func (id *ethereumIdentity) findContract() (exists bool, err error) { client := id.gethClientFinder() // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := client.GetGethCallOpts() + opts, _ := client.GetGethCallOpts(false) idAddress, err := id.registryContract.GetIdentityByCentrifugeId(opts, id.centID.BigInt()) if err != nil { return false, err @@ -249,7 +249,7 @@ func (id *ethereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdenti return nil, err } // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := id.gethClientFinder().GetGethCallOpts() + opts, _ := id.gethClientFinder().GetGethCallOpts(false) bigInt := big.NewInt(int64(keyPurpose)) keys, err := contract.GetKeysByPurpose(opts, bigInt) if err != nil { @@ -371,7 +371,7 @@ func NewEthereumIdentityService(config identity.Config, factoryContract factory, func (ids *ethereumIdentityService) CheckIdentityExists(centrifugeID identity.CentID) (exists bool, err error) { client := ids.gethClientFinder() // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := client.GetGethCallOpts() + opts, _ := client.GetGethCallOpts(false) idAddress, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centrifugeID.BigInt()) if err != nil { return false, err @@ -430,7 +430,7 @@ func (ids *ethereumIdentityService) CreateIdentity(ctx context.Context, centrifu // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID func (ids *ethereumIdentityService) GetIdentityAddress(centID identity.CentID) (common.Address, error) { // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetClient().GetGethCallOpts() + opts, _ := ethereum.GetClient().GetGethCallOpts(false) address, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centID.BigInt()) if err != nil { return common.Address{}, err diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 4b98f91c7..b07179843 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -153,7 +153,7 @@ func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []b return owner, errors.New("failed to bind the registry contract: %v", err) } - opts, cancF := s.ethClient.GetGethCallOpts() + opts, cancF := s.ethClient.GetGethCallOpts(false) defer cancF() return contract.OwnerOf(opts, utils.ByteSliceToBigInt(tokenID)) diff --git a/queue/server.go b/queue/server.go index 9edf7b94d..e92947c12 100644 --- a/queue/server.go +++ b/queue/server.go @@ -25,6 +25,9 @@ type Config interface { // GetNumWorkers gets the number of background workers to initiate GetNumWorkers() int + // GetTaskRetries returns the number of retries allowed for a queued task + GetTaskRetries() int + // GetWorkerWaitTime gets the worker wait time for a task to be available while polling // increasing this may slow down task execution while reducing it may consume a lot of CPU cycles GetWorkerWaitTimeMS() int @@ -96,7 +99,10 @@ func (qs *Server) EnqueueJob(taskName string, params map[string]interface{}) (Ta qs.lock.RLock() defer qs.lock.RUnlock() - return qs.enqueueJob(taskName, params, gocelery.DefaultSettings()) + return qs.enqueueJob(taskName, params, &gocelery.TaskSettings{ + MaxTries: uint(qs.config.GetTaskRetries()), + Delay: time.Now().UTC(), + }) } func (qs *Server) enqueueJob(name string, params map[string]interface{}, settings *gocelery.TaskSettings) (TaskResult, error) { diff --git a/resources/data.go b/resources/data.go index e7a32be2e..57ba6f9d7 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\x59\x73\xdb\xba\x15\x7e\xd7\xaf\x38\x23\xbf\xb4\x33\xa5\xcc\x7d\xd1\xcc\x9d\x8e\xbc\x25\xb9\x71\x5c\xd9\x96\xe3\x1b\xbf\x34\x20\x70\x28\x22\xa6\x00\x06\x00\xb5\xe4\xd7\x77\x00\x52\x8e\x1d\x2f\xb7\xcb\x34\x2f\xa6\x00\x9c\xfd\x3b\x1f\x0e\x72\x00\x27\x58\x91\xae\x31\xc0\x70\x8d\x8d\x6c\x57\x28\x0c\x18\xd4\x46\xa0\x01\xb2\x24\x5c\x68\x03\x8a\x8b\x7b\x2c\x77\x23\x8a\xc2\x28\x5e\x75\x4b\xbc\x40\xb3\x91\xea\x7e\x0a\xaa\xd3\x9a\x13\x51\xf3\xa6\x19\x39\x65\x5c\x20\x98\x1a\x81\x0d\x7a\x45\x7f\x52\x83\xa9\x89\x81\xe3\x07\x0d\xb0\x22\x5c\x18\xab\x7f\xb4\x3f\x32\x1d\x01\x1c\xc0\xb9\xa4\xa4\x71\x2e\x70\xb1\x04\x2a\x85\x51\x84\x1a\x20\x8c\x29\xd4\x1a\x35\x08\x44\x06\x46\x42\x89\xa0\xd1\xc0\x86\x9b\x1a\x50\xac\x61\x4d\x14\x27\x65\x83\x7a\x32\x82\xbd\xbc\x55\x09\xc0\xd9\x14\xa2\x28\x72\xdf\x68\x6a\x54\xd8\xad\x86\x08\x3e\xb0\x29\xe4\x51\xde\xef\x95\x52\x1a\x6d\x14\x69\xe7\x88\x4a\xf7\xb2\x1e\x8c\x0f\x79\x1b\x1f\x06\x61\x36\xf1\x27\xfe\x24\x38\x34\xb4\x3d\x8c\xf2\xd0\x0f\x0f\x79\x5b\xe9\xc3\xcb\xd5\xe2\x72\x5b\x6e\xee\xbb\xbb\x2f\x5f\x4e\xaa\xee\xc7\xa2\xdc\x9e\xce\xae\x70\x71\x71\x7c\x2e\x7f\xec\x76\x49\x92\xaf\x2f\xc5\xf2\xf3\x7a\xfe\xe9\xdb\xf9\x97\xfb\xf1\x9f\x28\x8d\xf6\x4a\x3f\x57\xe9\xe9\x45\xba\xba\xff\x7e\x8b\xdf\x6e\x3f\xde\x86\xdf\xe7\x5d\x90\xfe\xd1\xb2\x77\xd1\xfd\xef\x32\x58\x44\xab\x9a\xd4\xf3\xa3\xe4\x1a\x13\x11\xf4\x4a\xf7\xa9\x9a\xed\x33\xd5\x07\x60\xc3\x47\x61\xb8\xd9\x9d\x11\x6a\xa4\xda\x4d\x61\x3c\xfe\x65\xe7\x0a\x97\x5c\x9b\x27\x5b\x44\xd0\x5a\xaa\x2b\x6c\xa5\xe6\xbf\x48\xb5\x64\x67\x61\xf2\x8f\xb2\xe1\x4b\x62\xb8\x14\x6e\xcf\x15\xef\x13\xe1\xe2\x45\x28\x0d\x35\x1e\xc1\x63\xc4\xf4\x0e\x1e\xc0\x45\xb7\x42\xc5\x29\x7c\x38\x01\x59\x39\xf4\x3c\xc2\xc9\x4f\xc9\xbe\x90\x49\x30\x48\x1d\xed\xab\x05\x0d\xd7\xc6\x4a\x0a\xc9\xf0\x39\xd0\x5a\x25\xd7\xdc\x6d\x48\xa7\xfb\x91\x03\x7b\xf7\xfe\xb4\xfa\x51\x32\x09\xc3\x64\x12\xfa\xfe\x24\x0e\x7f\x45\x40\x10\x9e\x44\x1f\xa5\xbc\x3d\xe7\x9c\x5e\x7e\xde\x2c\xea\xc5\xd1\x97\x74\xfb\x91\xce\xe5\x79\x95\x5e\x5d\x7e\xf9\xfd\xac\xdd\x54\x81\xca\x92\xcd\xf9\x36\xbc\xbb\x8a\xda\x63\x16\x8c\x5f\x52\x9f\xa7\x93\x30\xf0\x5f\x53\x7f\x79\xf7\x69\x96\xbf\x9b\xbf\x57\xeb\xd3\xbb\xa3\x62\xc3\xee\xe5\x0d\x9d\xcd\x56\xc7\x77\xef\xdb\x02\x77\xbb\xbb\xf8\xfa\x34\x5f\x9e\xa9\xa8\x5e\x5c\xfc\x31\x1e\x72\x74\x3a\xa0\x7d\x9f\x45\x9b\x62\x0f\xae\x86\x7e\x7e\xa5\x1f\xe2\x41\xf8\x9c\xd8\xf4\x00\xc3\xb6\x91\x3b\x64\x70\xbd\x22\xca\xc0\xf1\x00\x33\x0d\x95\x54\x2e\xa1\x4b\xbe\x46\xf1\x24\x95\xcf\xa1\x08\xaf\x62\xd1\xdf\x16\x3e\x0b\x8b\x38\xc9\x02\xcc\xa2\x3c\x0e\xd3\x22\x23\x69\x5a\x66\xa4\x28\x88\x5f\x30\x96\xd2\x2c\x62\x51\x92\xb2\x37\x50\xeb\x6f\x8b\x34\xf5\xa9\x1f\x15\x2c\x0a\x82\x38\x89\x48\xe5\xb3\x24\xa7\x49\x9a\xa6\x59\x18\xb1\x82\x86\x15\xc9\x58\x8a\xf4\x0d\x7c\xfb\xdb\xac\xca\x93\x98\x55\xa4\xc8\xfd\x20\x64\x59\x45\x92\x84\xe6\x7e\x54\x96\x24\x0c\x53\xbf\xa4\x0c\x31\x2e\x13\x64\x6f\x75\x82\xbf\x65\xa5\x9f\xe4\xc1\xac\x88\xc2\x3c\x4d\xe3\x3c\x49\xa2\x30\x9f\xb1\x93\xd2\x3f\x0d\x93\x20\xc8\xe3\x34\xf6\xab\x02\x93\x13\xd7\x33\x25\x2a\x41\x9a\x1a\xf9\xb2\x36\x03\xe8\x0e\x0e\x0e\x86\x0a\x7c\x94\x6b\x22\xe0\x6c\x76\x39\xfc\xf6\xe0\xd6\xb2\x1d\x17\x55\xa7\x08\xec\x64\x07\x4b\x4b\xd3\x02\x50\x29\xa9\x2c\x9c\x16\x35\xd7\xa0\xf0\x7b\x67\x2b\xc7\x35\x08\x69\x40\x77\x6d\x2b\x95\x41\x06\x25\x52\xd2\x69\xb4\x92\xca\x75\x8b\x3d\xa2\x3a\x21\x2c\xd5\x3a\x22\xd5\x86\x18\xdb\x32\x9d\x5d\x9a\xc0\x55\x27\xfa\x75\xcf\x1b\xd6\x7e\x23\x8a\xd6\x7c\x8d\x93\xf1\xdf\x06\xa7\x00\x36\xb6\xe3\x8c\x04\x26\xff\xee\x24\x08\x34\x8e\xc4\x5b\xa2\xb8\xd9\xf5\x86\x9c\x96\x7b\x17\x0f\x2e\xa7\xfd\xcf\xaf\xc3\x01\xcf\xa3\x35\xe1\xe2\xb7\x7e\xdb\xf3\xac\xb7\xbf\x45\x7e\xe4\xc7\xe0\x79\x1b\xa2\xda\xe1\x8f\x57\x12\xa5\x38\x2a\x48\xd2\xdc\xf7\x7d\x1f\x3c\x4f\x48\x8f\x08\xca\x51\x18\xaf\x6c\x24\xbd\xd7\xfd\x9a\x46\xb5\x46\xaf\xb1\x49\x05\xcf\x5b\x91\xad\xd7\xda\xa6\x86\x30\xb1\x42\x5a\x90\x56\xd7\xd2\x0c\x8b\x6e\x6d\xc5\xc5\x93\x9f\xd6\x67\x42\x0d\x5f\x23\x78\x9e\x05\xb3\x4d\x91\xac\xaa\xe7\x99\x00\xcf\x63\xa5\x47\xe5\xaa\xb5\xe7\xa5\x00\xad\x99\x0d\x89\xd0\x1a\x3d\xcd\x7f\x20\xc4\x7e\x91\x82\xe7\x7d\xd3\x52\xa8\x96\x7a\xb5\xd4\x46\x03\x69\x9a\x47\x6b\x5c\x18\x54\x15\xa1\x68\xd7\xbf\x3e\x2d\xf7\xf3\x64\xbe\x54\xf9\x23\x1b\x3e\x32\xdb\x7b\x02\x7b\x47\x8c\x84\x5b\x2c\xaf\xed\xba\xd1\xe0\x72\xa2\xa0\x52\x72\x05\x9d\x30\xaa\xd3\x16\x12\x52\xf1\x25\x17\x53\x98\x4c\xc6\xaf\xd6\xd3\x36\xf9\xb3\x5a\x7e\xf5\xbc\x4e\x68\x52\xa1\x87\xdb\x56\x6a\xfc\x0a\x55\x43\x96\xbf\x00\xf8\x3f\x63\xf6\xf0\x7f\x64\xf6\x27\xbd\xf4\x6f\x73\x7b\xe0\xc7\x93\x20\x89\x27\x41\x3e\x49\x9e\xdd\xee\x7b\xf2\x9d\xeb\x94\x13\xbc\xe9\xce\xee\x2e\xba\xe0\xdd\x76\xad\x77\x47\x8b\x6b\xb5\xd0\xc5\xda\x1c\xa5\xa5\xf9\x34\x13\xef\xcf\xe4\xf9\xb7\xf2\xfe\xc7\x31\x19\xbf\xa0\x3e\x99\x04\x79\x32\x09\xa3\xec\x55\x03\xc7\xef\xe8\x86\x2f\xbe\xc9\x8f\xb7\xef\xab\x23\x12\xe7\xe1\xcd\xdc\x10\xbc\xd9\x5e\x9c\x6f\x58\xfe\xa3\x14\x47\xc1\x75\xb6\xc1\xd9\xdd\xcd\xf6\xee\x6d\x76\x77\xa4\xf1\x2a\xb7\x87\xff\x07\x72\x7f\x83\xdb\xf3\xa4\x8c\xc2\x2a\x23\x51\x15\xfb\x71\x1e\x54\x41\x18\x45\xb1\x1f\x07\x69\xe6\xd3\x9c\x96\xe8\x67\x55\xc6\xb2\x82\xbe\xc9\xed\x49\x4c\x30\xca\xa2\xca\x2f\xd2\x8a\x54\x21\x2b\xd3\x32\x27\x71\x9a\x05\x19\xf5\xcb\x22\x47\x5a\x11\x3f\x4b\x18\x7b\x93\xdb\xe3\x38\xae\xd2\xb8\xc0\xc8\xcf\xe2\x38\xc4\x2c\xa5\xb4\xca\xa2\x2c\x4e\x53\x4c\xc2\x2a\x48\xfd\xa2\x2c\xf2\x30\xf5\xdf\xe6\x76\x3f\x0e\x32\x2c\xa3\xac\x88\x83\x20\x8d\xa3\x34\x8f\xfd\xe0\x24\x4d\xd3\x22\x8f\xe9\xe9\x49\x96\x16\xf1\xec\x88\x1e\x95\xc1\x78\x64\xc7\x61\x62\x08\x5c\x1b\xa9\xc8\x12\x47\xba\xff\xdb\x0f\xb9\x73\x62\x6a\x97\xe2\xc6\xce\x4a\x27\x47\x50\xf1\x06\x47\xd6\xa8\xa9\xa7\x70\x68\x56\xed\xe1\xcf\x61\xfb\x9f\x8c\x18\x32\x71\x27\x59\x69\xf5\x1e\x4b\x51\xf1\x65\xa7\x9c\x5b\x0f\x06\xa8\x5b\xbd\xfe\xef\xcd\xf4\x0a\x9e\x59\x9b\x51\x2a\x3b\x61\x34\xdc\xe3\x0e\x86\x28\x46\x64\x58\xb4\x76\xee\x71\x67\x97\x71\xd0\xb8\xdf\xb2\xb2\x1f\x1e\x68\x6d\x63\xa1\xe8\x10\x35\x9b\x7f\x00\x22\x18\xcc\xc3\x39\x5c\xf7\x9c\x64\xdb\x1c\x85\xed\xe3\x91\xed\xf4\xf7\x52\x1b\x41\x56\x38\x05\xdf\x8d\xc7\xfe\xe8\x00\xe6\x52\x99\x41\x89\x55\xf0\xb2\xa0\x3d\x34\x85\xdc\xcf\x43\x6b\xdc\xf6\xba\x67\xa4\xa3\x75\xa0\x8f\x73\xa6\x47\x6d\xd8\xf6\x29\xba\x6e\x91\xf2\x6a\x07\xa7\x5b\xe3\xd8\x03\x3e\xcc\x1f\xf9\xea\xe8\x8e\x12\x61\x1f\x1b\x0a\x2d\xa3\x33\x20\x06\x78\x05\x25\xd6\x5c\x30\xb8\x98\x2d\xac\x1a\x1c\xa4\x3f\xcc\xa7\xb0\x99\x6c\x27\xbb\xc9\x8f\xbe\x00\xd6\xeb\x4e\x23\x7b\xe8\x27\x1b\x75\x43\x76\xa8\x6c\x19\x9c\xbb\x8e\x0c\xdc\xe9\x05\x5f\xa1\xec\x5c\x98\x02\x64\x8b\x62\x78\x01\x0d\x7c\xee\x78\xce\xdd\x51\x23\xd8\x2f\x0f\x22\x53\x18\x47\xbe\x76\xa0\xbb\xec\xb0\xc3\x5f\xc2\x75\xd6\x89\xde\x09\x5a\x2b\x29\x64\xa7\x2d\x75\x52\xd4\x9a\x8b\xe5\xe8\xbb\x15\xe8\x93\xd1\xbf\xdf\x74\x1f\x7a\xb7\x2a\x51\x59\xf2\xb5\xdc\x81\x4a\x1f\x52\x29\xb4\xe5\xf3\x81\x88\x37\x76\x80\x2e\xdd\x85\x25\x29\x31\x7d\x66\xb4\x21\xca\x74\xed\x08\xac\xfc\x6d\x2f\x38\x85\x3e\xbc\x33\x85\xa8\xa1\x6b\xe1\x78\x7e\x03\x74\x47\x1b\xd4\x7d\xa8\xbd\x01\x3b\x8b\x6c\x08\x77\xcf\x3e\xeb\x2f\xae\xd1\xa2\x08\x86\xed\x5b\xc2\x5d\xb4\x9f\xae\xa7\x10\xd8\x40\x1f\xd8\x4f\xbb\x12\x72\xfa\x34\xe8\xd1\x9e\xfd\x86\x3a\x63\x83\x96\xd7\x36\x35\xa7\xf5\x03\x33\xc2\x00\x56\x9b\x59\x3b\x18\x0d\x97\x94\xb4\x49\x18\x6e\x17\x06\xbc\xbf\x01\x69\xa7\x8d\x5c\x0d\x46\xf6\x9d\x34\x3c\x73\x87\x1e\xb9\x70\xa0\x1d\xdb\xa7\xed\xf8\xe1\x31\xeb\x9a\x74\x50\xfc\x60\x97\x36\x76\x66\xe9\xf1\xf5\x97\x0d\xba\x91\x8d\x2b\x84\x8d\x06\xa9\x80\xb7\x74\x78\xe1\xda\x07\xad\xfd\xa4\xc4\x58\xb7\x5d\x4a\xfe\x6a\xb3\x2b\x19\xde\x5c\x9d\x4f\xa1\x36\xa6\x9d\x1e\x1e\xba\x19\xc1\x0e\x16\xd3\x22\x89\x93\x7d\x31\xdd\x0b\x7c\x49\x6c\x2c\x9c\x5a\x77\x97\x44\xcf\xed\xe7\x14\x02\x7f\xff\xef\xd9\xe1\x86\xaf\xb8\xe9\x0f\x9f\xdb\xcf\x29\xc4\x59\x10\x46\x79\xfe\x04\xa4\x46\xba\x6a\xf5\xd0\x12\x3f\x23\x33\x8a\x08\x4d\x1e\x06\x10\x1b\x03\x63\xfd\x8b\x9d\x80\x9b\xd1\x5c\xf7\xf7\xa1\x80\x51\x7c\xb9\x44\x85\xac\x87\xb4\xc1\xad\xd9\x17\xba\x87\x75\xea\x5b\x5c\xbf\x66\x58\x21\x61\x20\x45\xb3\xb3\xed\xb2\x07\xfb\xfe\xbf\x2d\xf6\x2e\xfd\x54\x7d\x85\x84\x3d\x55\x1f\x24\x83\xf6\x0b\x5b\x89\xc7\xbe\xb7\x52\x36\xb0\x22\x5b\x50\x68\x14\xef\x87\x0c\x8d\x82\x01\x79\x72\x4c\xae\x5d\x2b\xaf\xc8\xf6\xaa\x3f\x37\x85\x70\xc8\xe9\xcb\x2a\xdd\xa4\xb7\x26\x8d\xd3\xbb\xeb\x1b\x80\x58\x07\x69\xa7\x94\x7b\x32\x3f\x92\xa8\x89\x86\x12\xd1\xbe\xa9\x0d\x52\xe3\xd2\xb4\x57\x60\xed\xd9\xab\x2d\x1c\x22\x38\xe1\xda\xa1\xc5\x69\xd4\x72\xf5\x0c\x6d\x1a\x98\x7c\xfc\x20\x00\xb3\x75\x1e\x91\x96\x8f\x00\xcc\x76\x2e\x65\x33\xa3\x96\x16\x4e\x85\xd5\xc4\xa6\x60\x54\x87\xb6\xd7\x88\xd8\x01\xc3\xb2\x5b\x2e\x07\x4a\xb2\x2d\xe0\x08\x60\x29\xc1\x1a\x19\xb9\xdd\xbe\xd5\xda\x56\xc9\xca\x95\xe7\x41\xc4\x92\x9d\x5d\x9d\x42\x45\x1a\x8d\xa3\x7f\x05\x00\x00\xff\xff\x80\x6a\xa2\xe3\x78\x12\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x5b\x73\xdb\x36\x16\x7e\xd7\xaf\x38\xe3\xbc\xb4\x33\x4b\x19\xbc\x93\x9a\xe9\xec\xc8\xb6\x9c\xa4\x71\x5c\xf9\x92\xba\xf1\xcb\x06\x04\x0e\x25\xc4\x14\xc0\x00\xa0\x2e\xf9\xf5\x3b\x00\x29\xd7\x8e\x63\x77\xb7\x9d\xee\xfa\xc5\x14\x88\x73\x70\x2e\xdf\xf7\x11\xc0\x2b\x38\xc1\x9a\x76\x8d\x05\x8e\x6b\x6c\x54\xbb\x42\x69\xc1\xa2\xb1\x12\x2d\xd0\x05\x15\xd2\x58\xd0\x42\xde\x61\xb5\x1b\x31\x94\x56\x8b\xba\x5b\xe0\x39\xda\x8d\xd2\x77\x13\xd0\x9d\x31\x82\xca\xa5\x68\x9a\x91\x77\x26\x24\x82\x5d\x22\xf0\xc1\xaf\xec\x67\x1a\xb0\x4b\x6a\xe1\xf8\xde\x03\xac\xa8\x90\xd6\xf9\x1f\xed\xa7\x4c\x46\x00\xaf\xe0\x4c\x31\xda\xf8\x10\x84\x5c\x00\x53\xd2\x6a\xca\x2c\x50\xce\x35\x1a\x83\x06\x24\x22\x07\xab\xa0\x42\x30\x68\x61\x23\xec\x12\x50\xae\x61\x4d\xb5\xa0\x55\x83\x66\x3c\x82\xbd\xbd\x73\x09\x20\xf8\x04\xe2\x38\xf6\xcf\x68\x97\xa8\xb1\x5b\x0d\x19\xbc\xe5\x13\x28\xe2\xa2\x7f\x57\x29\x65\x8d\xd5\xb4\x9d\x23\x6a\xd3\xdb\x06\x70\x70\x28\xda\xe4\x30\x8c\xf2\x31\x19\x93\x71\x78\x68\x59\x7b\x18\x17\x11\x89\x0e\x45\x5b\x9b\xc3\x8b\xd5\xf5\xc5\xb6\xda\xdc\x75\xb7\x1f\x3f\x9e\xd4\xdd\xd7\xeb\x6a\x3b\x9b\x5e\xe2\xf5\xf9\xf1\x99\xfa\xba\xdb\xa5\x69\xb1\xbe\x90\x8b\x5f\xd7\xf3\xf7\x9f\xcf\x3e\xde\x1d\xfc\x81\xd3\x78\xef\xf4\xd7\x3a\x9b\x9d\x67\xab\xbb\x2f\x37\xf8\xf9\xe6\xdd\x4d\xf4\x65\xde\x85\xd9\x6f\x2d\x7f\x1d\xdf\xfd\xac\xc2\xeb\x78\xb5\xa4\xcb\xf9\x51\x7a\x85\xa9\x0c\x7b\xa7\xfb\x52\x4d\xf7\x95\xea\x13\x70\xe9\xa3\xb4\xc2\xee\x4e\x29\xb3\x4a\xef\x26\x70\x70\xf0\xcd\x9b\x4b\x5c\x08\x63\x1f\xbd\xa2\x92\x2d\x95\xbe\xc4\x56\x19\xf1\x8d\x55\x4b\x77\x0e\x26\xbf\x54\x8d\x58\x50\x2b\x94\xf4\xef\x7c\xf3\xde\x53\x21\xbf\x0b\xa5\xa1\xc7\xf0\xc3\x65\x8f\xa5\x1f\x47\xf0\x10\x3b\x7d\xa8\xaf\xe0\xbc\x5b\xa1\x16\x0c\xde\x9e\x80\xaa\x3d\x8e\x1e\x20\x66\xf0\x71\xdf\xd2\x34\x1c\xac\x8e\xf6\x7d\x83\x46\x18\xeb\x2c\xa5\xe2\xf8\x14\x72\xad\x56\x6b\xe1\x5f\x28\xef\xfb\x41\x00\xfb\x40\xff\x10\x07\x71\x3a\x8e\xa2\x74\x1c\x11\x32\x4e\xa2\x6f\xb1\x10\x46\x27\xf1\x3b\xa5\x6e\xce\x84\x60\x17\xbf\x6e\xae\x97\xd7\x47\x1f\xb3\xed\x3b\x36\x57\x67\x75\x76\x79\xf1\xf1\xe7\xd3\x76\x53\x87\x3a\x4f\x37\x67\xdb\xe8\xf6\x32\x6e\x8f\x79\x78\xf0\x3d\xf7\x45\x36\x8e\x42\xf2\x9c\xfb\x8b\xdb\xf7\xd3\xe2\xf5\xfc\x8d\x5e\xcf\x6e\x8f\xca\x0d\xbf\x53\x1f\xd8\x74\xba\x3a\xbe\x7d\xd3\x96\xb8\xdb\xdd\x26\x57\xb3\x62\x71\xaa\xe3\xe5\xf5\xf9\x6f\x07\x43\x8d\x66\x03\xee\xef\x3b\xf1\xf6\x04\x02\x18\xba\xf1\x1c\x33\x92\xc1\xf8\x8c\xba\xf2\x00\xc7\xb6\x51\x3b\xe4\x70\xb5\xa2\xda\xc2\xf1\x00\x38\x03\xb5\xd2\xbe\xa0\x0b\xb1\x46\xf9\xa8\x94\x4f\x41\x09\xcf\xa2\x92\x6c\x4b\xc2\xa3\x32\x49\xf3\x10\xf3\xb8\x48\xa2\xac\xcc\x69\x96\x55\x39\x2d\x4b\x4a\x4a\xce\x33\x96\xc7\x3c\x4e\x33\xfe\x02\x7e\xc9\xb6\xcc\x32\xc2\x48\x5c\xf2\x38\x0c\x93\x34\xa6\x35\xe1\x69\xc1\xd2\x2c\xcb\xf2\x28\xe6\x25\x8b\x6a\x9a\xf3\x0c\xd9\x0b\x48\x27\xdb\xbc\x2e\xd2\x84\xd7\xb4\x2c\x48\x18\xf1\xbc\xa6\x69\xca\x0a\x12\x57\x15\x8d\xa2\x8c\x54\x8c\x23\x26\x55\x8a\xfc\x25\x4e\x90\x2d\xaf\x48\x5a\x84\xd3\x32\x8e\x8a\x2c\x4b\x8a\x34\x8d\xa3\x62\xca\x4f\x2a\x32\x8b\xd2\x30\x2c\x92\x2c\x21\x75\x89\xe9\xc9\xc0\x9e\x77\x6a\x4d\xfb\xf2\x3d\xc0\x7a\x85\x5a\xd2\x66\x89\x62\xb1\xb4\x03\x16\x5f\xbd\x7a\x35\x34\xa6\xb7\x38\x9d\x5e\x0c\xbf\x03\xb8\x71\x72\x28\x64\xdd\x69\x0a\x3b\xd5\xc1\xc2\xe9\xb8\x04\xd4\x5a\x69\x87\xb2\xeb\xa5\x30\xa0\xf1\x4b\xe7\x56\x11\x06\xa4\xb2\x60\xba\xb6\x55\xda\x22\x87\x0a\x19\xed\x0c\x3a\x4b\xed\x49\xe4\xa6\xe8\x4e\x4a\xa7\xc5\x5e\x69\x8d\xa5\xd6\x31\xa9\x73\x43\x63\xb8\xec\x64\x3f\x1e\x04\xc3\xd8\x4f\x54\xb3\xa5\x58\xe3\xf8\xe0\x1f\x43\x50\x00\x1b\x47\x44\xab\x80\xab\x7f\x7a\x0b\x0a\x8d\x57\xf9\x96\x6a\x61\x77\xfd\x42\xde\xcb\x9d\xcf\x07\x17\x93\xfe\xe7\xa7\x61\x42\x10\xb0\x25\x15\xf2\xa7\xfe\x75\x10\xb8\x68\x7f\x8a\x49\x4c\x12\x08\x82\x0d\xd5\xed\xf0\x2f\xa8\xa8\xd6\x02\x35\xa4\x59\x41\x08\x21\x10\x04\x52\x05\x54\x32\x81\xd2\x06\x55\xa3\xd8\x9d\xe9\xc7\x0c\xea\x35\x06\x8d\x2b\x2a\x04\xc1\x8a\x6e\x83\xd6\x71\x1d\xa2\xd4\x19\x19\x49\x5b\xb3\x54\x76\x18\xf4\x63\x2b\x21\x1f\xfd\x74\x31\x53\x66\xc5\x1a\x21\x08\x1c\xc6\x5d\x89\x54\x5d\x3f\xad\x04\x04\x01\xaf\x02\xa6\x56\xad\x9b\xaf\x24\x18\xc3\x5d\x4a\x94\x2d\x31\x30\xe2\x2b\x42\x42\xca\x0c\x82\xe0\xb3\x51\x52\xb7\x2c\x58\x2a\x63\x0d\xd0\xa6\x79\x30\x26\xa4\x45\x5d\x53\x86\x6e\xfc\xd3\xe3\x76\x3f\x2d\xe6\xf7\x3a\x7f\xe4\xd2\x47\xee\x28\x29\xb1\x0f\xc4\x2a\xb8\xc1\xea\xca\x8d\x5b\x03\xbe\x26\x1a\x6a\xad\x56\xd0\x49\xab\x3b\xe3\x20\xa1\xb4\x58\x08\x39\x81\xf1\xf8\xe0\xd9\x7e\x3a\xee\x3f\xe9\xe5\xa7\x20\xe8\xa4\xa1\x35\x06\xb8\x6d\x95\xc1\x4f\x50\x37\x74\xf1\x0d\x80\xff\x3b\xc1\x8f\xfe\xa2\xe0\x3f\xe2\xd2\x7f\x2c\xf9\x21\x49\xc6\x61\x9a\x8c\xc3\x62\x9c\x3e\xf9\xfc\xef\x35\x79\x6e\x32\x41\xf1\x43\x77\x7a\x7b\xde\x85\xaf\xb7\x6b\xb3\x3b\xba\xbe\xd2\xd7\xa6\x5c\xdb\xa3\xac\xb2\xef\xa7\xf2\xcd\xa9\x3a\xfb\x5c\xdd\x7d\x3d\xa6\x07\xdf\x71\x9f\x8e\xc3\x22\x1d\x47\x71\xfe\xec\x02\xc7\xaf\xd9\x46\x5c\x7f\x56\xef\x6e\xde\xd4\x47\x34\x29\xa2\x0f\x73\x4b\xf1\xc3\xf6\xfc\x6c\xc3\x8b\xaf\x95\x3c\x0a\xaf\xf2\x0d\x4e\x6f\x3f\x6c\x6f\x5f\x16\x7d\x2f\x1a\xcf\x4a\x7e\xf4\x37\x68\xfe\x0b\x92\x5f\xa4\x55\x1c\xd5\x39\x8d\xeb\x84\x24\x45\x58\x87\x51\x1c\x27\x24\x09\xb3\x9c\xb0\x82\x55\x48\xf2\x3a\xe7\x79\xc9\x5e\x94\xfc\x34\xa1\x18\xe7\x71\x4d\xca\xac\xa6\x75\xc4\xab\xac\x2a\x68\x92\xe5\x61\xce\x48\x55\x16\xc8\x6a\x4a\xf2\x94\xf3\x17\x25\x3f\x49\x92\x3a\x4b\x4a\x8c\x49\x9e\x24\x11\xe6\x19\x63\x75\x1e\xe7\x49\x96\x61\x1a\xd5\x61\x46\xca\xaa\x2c\xa2\x8c\xbc\x2c\xf9\x24\x09\x73\xac\xe2\xbc\x4c\xc2\x30\x4b\xe2\xac\x48\x48\x78\x92\x65\x59\x59\x24\x6c\x76\x92\x67\x65\x32\x3d\x62\x47\x55\x38\x48\xfe\xa5\x6a\x8d\xc5\x27\xa2\xcf\xd5\xa2\xa5\x96\x2d\xff\xdc\xbe\x28\xfe\x8b\x34\xd9\xaf\x0e\x3f\x5c\xff\x72\xf2\x0b\x30\x8d\x4e\xf3\xf5\x10\xaa\xa3\x8a\xf7\xf3\xe3\xb3\xcc\xf9\xdb\xb7\x4b\xff\xbf\x0d\x53\x5f\x84\xe7\xd8\x13\xff\x6f\xc9\x93\x26\xd9\xec\xb4\x88\x8e\x53\x12\x63\x1d\x93\x0c\xc3\x7a\x9a\xe4\x79\x5a\xc7\x84\x64\x45\x95\xf0\x12\x23\x52\x84\xc9\xcb\xe4\x49\xc3\x8c\x1c\x85\x11\x29\x43\x96\x84\xb3\xfc\x38\x09\x6b\x72\x34\x4d\xa7\x58\x46\x29\x25\x49\x94\xb1\x84\x4e\x67\xd3\x17\xc9\x13\x87\x75\x9e\x11\xcc\x49\x72\x1a\xe7\x79\x9a\xf2\xf0\x98\x26\xf5\x51\x8a\x27\xd3\xec\x24\x4f\xd3\x59\x48\xf2\x29\x86\xe1\xcb\xe4\x89\x67\x34\x8e\x8e\xa3\x64\x9a\x46\xe9\x2c\xc7\x82\x66\x61\x19\x1e\x97\x51\x9c\x97\x31\x49\xa3\xd3\x3c\xaf\xb2\xb4\x8c\xb3\x83\x91\x3b\x6c\x52\x4b\xe1\xca\x2a\x4d\x17\x38\x32\xfd\xff\xfe\x08\x39\xa7\x76\xe9\x4b\xdc\xb8\x93\xc8\xc9\x11\xd4\xa2\xc1\x91\x5b\xd4\x2e\x27\x70\x68\x57\xed\xe1\xef\x47\xd9\x7f\x71\x6a\xe9\xd8\xcf\xe4\x95\xf3\x7b\xac\x64\x2d\x16\x9d\xf6\x61\xdd\x2f\xc0\xfc\xe8\xd5\x9f\x5f\xa6\x77\xf0\x64\xb5\x29\x63\xaa\x93\xd6\xc0\x1d\xee\x60\xc8\x62\x44\x87\x41\xb7\xce\x1d\xee\xdc\x30\x0e\x1e\xf7\xaf\x9c\xed\xdb\xfb\x3d\xc1\xc6\x21\xd1\x23\x6a\x3a\x7f\x0b\x54\x72\x98\x47\x73\xb8\xea\x3f\xe8\x8e\xfc\x28\x1d\xbb\x47\x8e\xb7\x6f\x94\xb1\x92\xae\x70\x02\xc4\x1f\x3e\xc9\xe8\x15\xcc\x95\xb6\x83\x13\xe7\xe0\xfb\x86\x6e\xd2\x04\x0a\x52\x44\x6e\x71\x47\xf7\xc0\x2a\xbf\x27\x02\xf6\xb0\x66\x66\xd4\x46\x6d\x5f\xa2\xab\x16\x99\xa8\x77\x30\xdb\x5a\xff\xe9\x85\xb7\xf3\x07\xb1\xfa\xbd\x02\xa3\xd2\x1d\xe5\x35\xba\xed\x10\x07\x6a\x41\xd4\x50\xe1\x52\x48\x0e\xe7\xd3\x6b\xe7\x06\x07\xeb\xb7\xf3\x09\x6c\xc6\xdb\xf1\x6e\xfc\xb5\x6f\x80\x8b\xba\x33\xc8\xef\xf9\xe4\xb2\x6e\xe8\x0e\xb5\x6b\x83\x0f\xd7\xab\x81\x9f\x7d\x2d\x56\xa8\x3a\x9f\xa6\x04\xd5\xa2\x1c\xee\x17\x86\xcd\x90\x57\x3f\xbf\xc1\x1b\xc1\x7e\x78\x30\x99\xc0\x41\x4c\x8c\x07\xdd\x45\x87\x1d\x7e\x93\xae\x5f\x9d\x9a\x9d\x64\x4b\xad\xa4\xea\x8c\x13\x54\x86\xc6\x08\xb9\x18\x7d\x71\x06\x7d\x31\xfa\xdb\x11\xd3\xa7\xde\xad\x2a\xd4\x4e\x92\x9d\x74\xa0\x36\x87\x4c\x49\xe3\x54\x7e\x90\xe7\x8d\x3b\x94\x56\x7e\xb7\xa7\x18\xb5\x7d\x65\x8c\xa5\xda\x76\xed\x08\x9c\xfd\x4d\x6f\x38\x81\x3e\xbd\x53\x8d\x68\xa0\x6b\xe1\x78\xfe\x01\xd8\x8e\x35\x68\xfa\x54\xfb\x05\xdc\x46\x7e\x43\x85\xbf\x54\x71\xf1\xe2\x1a\x1d\x8a\x60\x78\x7d\x43\x85\xcf\xf6\xfd\xd5\x04\xc2\xd1\xf0\xc9\x19\x22\xd4\x68\xb5\x40\xbf\x21\x55\x9b\xa1\xd8\x14\x2c\x35\xee\x93\xe3\xfe\x5d\xf6\x13\x26\x10\x12\x57\xa3\x7b\xe5\x34\xbe\xfb\x82\x3d\xae\xd7\x68\xaf\x9b\x03\x44\xb0\x41\x27\x89\x9b\xa5\x60\xcb\x7b\x4d\x85\x01\xe7\xae\x29\xee\x40\x32\x7c\xf5\x94\xab\xdf\xf0\xb9\xe2\x20\xfa\x9d\x27\xeb\x8c\x55\xab\x61\x91\x3d\x09\x87\xfb\xa7\x81\x5e\xe7\x1e\xef\x07\x2b\x2a\xe4\xc1\xfd\x2d\x93\xe7\xf7\xe0\xf8\x7e\x5d\xd6\xb8\xb3\x42\x0f\xcd\x1f\x36\xe8\x8f\x4a\x42\x23\x6c\x0c\x28\x0d\xa2\x65\xc3\xd5\x13\xad\x1a\x74\x8f\xcc\x7f\x28\xfb\x6a\xba\x0f\xa2\x33\xfc\x70\x79\x36\x81\xa5\xb5\xed\xe4\xf0\xd0\xef\xcd\xdd\x86\x7e\x52\xa6\x49\xba\xc7\x81\xbf\x1a\x5b\x50\x97\x8b\x60\x2e\xdc\x05\x35\x73\xf7\xe8\x6a\xb8\xff\x7b\x32\xb9\x11\x2b\x61\xfb\xc9\x67\xee\x71\x02\x49\x1e\x46\x71\x51\x3c\xc2\xb7\x55\xbe\xd1\x7d\x9b\xe4\xef\x99\x59\x4d\xa5\xa1\xf7\x1b\x7f\x97\x03\xe7\xfd\x55\x1a\x05\x7f\x36\xf2\xc2\xd1\xa7\x02\x56\x8b\xc5\x02\x35\xf2\x9e\x0d\x16\xb7\x76\x8f\x91\x9e\x11\x19\x71\x94\x78\x6e\x61\x8d\x94\x83\x92\xcd\xce\x31\x6d\xcf\x93\xfd\x7d\xe2\x3e\xa4\xdf\x5d\x5f\x22\xe5\x8f\xdd\x87\xe9\xe0\xfd\xdc\x75\xe2\x61\xec\xad\x52\x0d\xac\xe8\xf6\x1e\x97\x56\x81\x41\xc9\x1d\x26\x1f\x4c\x53\x6b\xaf\x02\x2b\xba\xbd\x87\x67\x34\xd4\xf4\xfb\x2e\xfd\x09\x6b\x4d\x1b\xef\x77\xd7\x73\x87\xba\x00\x59\xa7\xb5\xbf\xcb\x7a\x60\xb1\xa4\x06\x2a\x44\x09\x1c\x2d\x32\xeb\xcb\xb4\x77\xe0\xd6\x73\x5f\xc5\x68\xc8\xe0\x44\x18\x8f\x16\xef\xd1\xa8\xd5\x13\xb4\x19\xe0\xea\xe1\x41\x1c\xec\xd6\x47\x44\x5b\xe1\x18\xb6\x9d\x2b\xd5\x4c\x99\x53\x94\x99\x74\x9e\xf8\x04\xac\xee\xd0\x71\x8d\xca\x1d\x70\xac\xba\xc5\x62\x50\x33\x47\x01\xaf\x1d\x0b\x05\x6e\x91\x91\x7f\xdb\x53\xad\x6d\xb5\xaa\x7d\x7b\xee\x4d\x9c\x4e\xba\xd1\x09\xd4\xb4\x31\x38\xfa\x77\x00\x00\x00\xff\xff\x55\x54\xf7\xc0\x11\x16\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 4728, mode: os.FileMode(420), modTime: time.Unix(1547653425, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1548259859, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547653425, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547821748, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index b9eb3bd41..793d4f295 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -22,7 +22,7 @@ type MockEthClient struct { mock.Mock } -func (m *MockEthClient) GetGethCallOpts() (*bind.CallOpts, context.CancelFunc) { +func (m *MockEthClient) GetGethCallOpts(pending bool) (*bind.CallOpts, context.CancelFunc) { args := m.Called() c, _ := args.Get(0).(*bind.CallOpts) return c, func() {} diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 6fb8803ea..fb25d4c03 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -6,6 +6,8 @@ import ( "net/http" "testing" + "github.com/centrifuge/go-centrifuge/config" + "github.com/stretchr/testify/assert" ) @@ -57,8 +59,8 @@ func paymentObligationMint(t *testing.T, documentType string) { map[string]interface{}{ "identifier": docIdentifier, - "registryAddress": doctorFord.contractAddresses.PaymentObligationAddr, - "depositAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", // dummy address + "registryAddress": doctorFord.getHost("Alice").config.GetContractAddress(config.PaymentObligation).String(), + "depositAddress": "0x44a0579754d6c94e7bb2c26bfa7394311cc50ccb", // Centrifuge address "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", "collaborators[0]"}, }, } From 04ed5d27bf238a1a6117b538268e934634566b19 Mon Sep 17 00:00:00 2001 From: Charly Date: Fri, 25 Jan 2019 10:47:49 +0100 Subject: [PATCH 160/220] naming (#693) --- coredocument/read_acls.go | 34 +++++++++++++++++----------------- coredocument/read_acls_test.go | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index 9b364631e..aae65d45b 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -97,14 +97,14 @@ func constructNFT(registry common.Address, tokenID []byte) ([]byte, error) { return nft, nil } -// ReadAccessValidator defines validator functions for peer. +// ReadAccessValidator defines validator functions for account . type ReadAccessValidator interface { - PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool + AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool NFTOwnerCanRead( cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte, - peer identity.CentID) error + account identity.CentID) error } // readAccessValidator implements ReadAccessValidator. @@ -112,12 +112,12 @@ type readAccessValidator struct { tokenRegistry TokenRegistry } -// PeerCanRead validate if the core document can be read by the peer. +// AccountCanRead validate if the core document can be read by the account . // Returns an error if not. -func (r readAccessValidator) PeerCanRead(cd *coredocumentpb.CoreDocument, peer identity.CentID) bool { +func (r readAccessValidator) AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool { // loop though read rules return findRole(cd, coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { - return isPeerInRole(role, peer) + return isAccountInRole(role, account) }) } @@ -131,10 +131,10 @@ func getRole(key uint32, roles []*coredocumentpb.RoleEntry) (*coredocumentpb.Rol return nil, errors.New("role %d not found", key) } -// isPeerInRole returns true if peer is in the given role as collaborators. -func isPeerInRole(role *coredocumentpb.Role, peer identity.CentID) bool { +// isAccountInRole returns true if account is in the given role as collaborators. +func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { for _, id := range role.Collaborators { - if bytes.Equal(id, peer[:]) { + if bytes.Equal(id, account[:]) { return true } } @@ -142,8 +142,8 @@ func isPeerInRole(role *coredocumentpb.Role, peer identity.CentID) bool { return false } -// peerValidator returns the ReadAccessValidator tp verify peer. -func peerValidator() ReadAccessValidator { +// account returns the ReadAccessValidator tp verify account . +func accountValidator() ReadAccessValidator { return readAccessValidator{} } @@ -152,17 +152,17 @@ func nftValidator(tr TokenRegistry) ReadAccessValidator { return readAccessValidator{tokenRegistry: tr} } -// NFTOwnerCanRead checks if the nft owner/peer can read the document +// NFTOwnerCanRead checks if the nft owner/account can read the document // Note: signature should be calculated from the hash which is calculated as // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). func (r readAccessValidator) NFTOwnerCanRead( cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte, - peer identity.CentID) error { + account identity.CentID) error { - // check if the peer can read the doc - if r.PeerCanRead(cd, peer) { + // check if the account can read the doc + if r.AccountCanRead(cd, account) { return nil } @@ -182,8 +182,8 @@ func (r readAccessValidator) NFTOwnerCanRead( } // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address - if !bytes.Equal(owner.Bytes(), peer[:]) { - return errors.New("peer(%v) not owner of the NFT", peer.String()) + if !bytes.Equal(owner.Bytes(), account[:]) { + return errors.New("account (%v) not owner of the NFT", account.String()) } return nil diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index 241d789f7..fc990e9b8 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -32,22 +32,22 @@ func TestReadACLs_initReadRules(t *testing.T) { assert.Len(t, cd.Roles, 1) } -func TestReadAccessValidator_PeerCanRead(t *testing.T) { - pv := peerValidator() - peer, err := identity.CentIDFromString("0x010203040506") +func TestReadAccessValidator_AccountCanRead(t *testing.T) { + pv := accountValidator() + account, err := identity.CentIDFromString("0x010203040506") assert.NoError(t, err) - cd, err := NewWithCollaborators([]string{peer.String()}) + cd, err := NewWithCollaborators([]string{account.String()}) assert.NoError(t, err) assert.NotNil(t, cd.ReadRules) assert.NotNil(t, cd.Roles) - // peer who cant access + // account who cant access rcid := identity.RandomCentID() - assert.False(t, pv.PeerCanRead(cd, rcid)) + assert.False(t, pv.AccountCanRead(cd, rcid)) - // peer can access - assert.True(t, pv.PeerCanRead(cd, peer)) + // account can access + assert.True(t, pv.AccountCanRead(cd, account)) } func Test_addNFTToReadRules(t *testing.T) { @@ -83,31 +83,31 @@ func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.A } func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { - peer, err := identity.CentIDFromString("0x010203040506") + account, err := identity.CentIDFromString("0x010203040506") assert.NoError(t, err) - cd, err := NewWithCollaborators([]string{peer.String()}) + cd, err := NewWithCollaborators([]string{account.String()}) assert.NoError(t, err) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - // peer can read + // account can read validator := nftValidator(nil) - err = validator.NFTOwnerCanRead(cd, registry, nil, peer) + err = validator.NFTOwnerCanRead(cd, registry, nil, account) assert.NoError(t, err) - // peer not in read rules and nft missing - peer, err = identity.CentIDFromString("0x010203040505") + // account not in read rules and nft missing + account, err = identity.CentIDFromString("0x010203040505") assert.NoError(t, err) tokenID := utils.RandomSlice(32) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) tr := mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() addNFTToReadRules(cd, registry, tokenID) validator = nftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) assert.Contains(t, err, "failed to get owner of") tr.AssertExpectations(t) @@ -117,7 +117,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { tr = mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() validator = nftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, peer) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) tr.AssertExpectations(t) } From 4e4e955efac47ce255153e27793888e8947ecfde Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Fri, 25 Jan 2019 16:59:22 +0000 Subject: [PATCH 161/220] adapt go-cent to proto (#694) * adapt go-cent to proto * remove fmt * bigendian --- Gopkg.lock | 4 ++-- Gopkg.toml | 2 +- coredocument/coredocument_test.go | 10 +++++----- coredocument/read_acls.go | 32 +++++++++++++++++-------------- documents/invoice/model.go | 1 - resources/data.go | 2 +- utils/tools.go | 13 +++++++++++++ utils/tools_test.go | 8 ++++++++ 8 files changed, 48 insertions(+), 24 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index aefe97ee2..8115aec07 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:55060176e56680808b3d9be771d0baa31512b7743ffbaea4f61471dbba649be7" + digest = "1:5616d244073fc94efbff79cd244cb3553a8bcf130f97e0e84d94ee6a68073fc1" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "f93686ceaf40283c7dc496c62fcc69b1c1a272e3" + revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 74626bde1..406068c3d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "f93686ceaf40283c7dc496c62fcc69b1c1a272e3" + revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 25f5b03a4..77be13963 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -311,7 +311,7 @@ func TestPrepareNewVersion_read_rules(t *testing.T) { assert.NoError(t, err) assert.Len(t, cd.ReadRules, 1) assert.Len(t, cd.Roles, 1) - assert.Equal(t, cd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + assert.Equal(t, cd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) cd.DocumentRoot = utils.RandomSlice(32) // prepare with zero collaborators @@ -320,7 +320,7 @@ func TestPrepareNewVersion_read_rules(t *testing.T) { assert.NotNil(t, ncd) assert.Len(t, ncd.ReadRules, 1) assert.Len(t, ncd.Roles, 1) - assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) // prepare with no unique one ncd, err = PrepareNewVersion(*cd, []string{"0x010203040506"}) @@ -328,7 +328,7 @@ func TestPrepareNewVersion_read_rules(t *testing.T) { assert.NotNil(t, ncd) assert.Len(t, ncd.ReadRules, 1) assert.Len(t, ncd.Roles, 1) - assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) // prepare with unique collaborators ncd, err = PrepareNewVersion(*cd, []string{"0x010202030203", "0x020301020304"}) @@ -337,6 +337,6 @@ func TestPrepareNewVersion_read_rules(t *testing.T) { assert.Len(t, ncd.ReadRules, 2) assert.Len(t, ncd.Roles, 2) assert.Equal(t, ncd.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}, {1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) - assert.Equal(t, ncd.Roles[0].Role.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) - assert.Equal(t, ncd.Roles[1].Role.Collaborators, [][]byte{{1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) + assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) + assert.Equal(t, ncd.Roles[1].Collaborators, [][]byte{{1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) } diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index aae65d45b..ae578b05a 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -3,6 +3,8 @@ package coredocument import ( "bytes" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -35,35 +37,37 @@ func initReadRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) e return ErrZeroCollaborators } - addCollaboratorsToReadSignRules(cd, collabs) - return nil + return addCollaboratorsToReadSignRules(cd, collabs) } -func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) { +func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { if len(collabs) == 0 { - return + return nil } // create a role for given collaborators role := new(coredocumentpb.Role) + rk, err := utils.ConvertIntToByte32(len(cd.Roles)) + if err != nil { + return err + } + role.RoleKey = rk[:] for _, c := range collabs { c := c role.Collaborators = append(role.Collaborators, c[:]) } addNewRule(cd, role, coredocumentpb.Action_ACTION_READ_SIGN) + + return nil } // addNewRule creates a new rule as per the role and action. func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, action coredocumentpb.Action) { - roleKey := uint32(len(cd.Roles)) - cd.Roles = append(cd.Roles, &coredocumentpb.RoleEntry{ - RoleKey: roleKey, - Role: role, - }) + cd.Roles = append(cd.Roles, role) rule := new(coredocumentpb.ReadRule) - rule.Roles = append(rule.Roles, roleKey) + rule.Roles = append(rule.Roles, role.RoleKey) rule.Action = action cd.ReadRules = append(cd.ReadRules, rule) } @@ -121,10 +125,10 @@ func (r readAccessValidator) AccountCanRead(cd *coredocumentpb.CoreDocument, acc }) } -func getRole(key uint32, roles []*coredocumentpb.RoleEntry) (*coredocumentpb.Role, error) { - for _, roleEntry := range roles { - if roleEntry.RoleKey == key { - return roleEntry.Role, nil +func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { + for _, role := range roles { + if utils.IsSameByteSlice(role.RoleKey, key) { + return role, nil } } diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 3eaed570e..b9b4f0773 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -104,7 +104,6 @@ func (i *Invoice) getClientData() *clientinvoicepb.InvoiceData { // createP2PProtobuf returns centrifuge protobuf specific invoiceData func (i *Invoice) createP2PProtobuf() *invoicepb.InvoiceData { - var recipient, sender, payee []byte if i.Recipient != nil { recipient = i.Recipient[:] diff --git a/resources/data.go b/resources/data.go index 57ba6f9d7..13234473e 100644 --- a/resources/data.go +++ b/resources/data.go @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/utils/tools.go b/utils/tools.go index 530004747..ca768b842 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -2,6 +2,7 @@ package utils import ( "crypto/rand" + "encoding/binary" "math/big" "github.com/centrifuge/go-centrifuge/errors" @@ -158,3 +159,15 @@ func SimulateJSONDecodeForGocelery(kwargs map[string]interface{}) (map[string]in func IsValidByteSliceForLength(slice []byte, length int) bool { return len(slice) == length } + +// ConvertIntToByte32 converts an integer into a fixed length byte array with BigEndian order +func ConvertIntToByte32(n int) ([32]byte, error) { + buf := make([]byte, 32) + binary.BigEndian.PutUint64(buf, uint64(n)) + return SliceToByte32(buf) +} + +// ConvertByte32ToInt converts a fixed length byte array into int with BigEndian order +func ConvertByte32ToInt(nb [32]byte) int { + return int(binary.BigEndian.Uint64(nb[:])) +} diff --git a/utils/tools_test.go b/utils/tools_test.go index f43b47edf..6094feac2 100644 --- a/utils/tools_test.go +++ b/utils/tools_test.go @@ -225,6 +225,14 @@ func TestSliceOfByteSlicesToHexStringSlice(t *testing.T) { } } +func TestConvertIntToBytes(t *testing.T) { + n := 5 + nb, err := ConvertIntToByte32(n) + assert.NoError(t, err) + ni := ConvertByte32ToInt(nb) + assert.Equal(t, n, ni) +} + func verifyHex(t *testing.T, val string) { _, err := hexutil.Decode(val) assert.Nil(t, err) From 57b3547fda8195733a5f638b4c9fe3f9dee85a1b Mon Sep 17 00:00:00 2001 From: Charly Date: Sun, 27 Jan 2019 19:28:45 +0100 Subject: [PATCH 162/220] [WIP] validate GetDocumentRequest (#684) * restructured AccessValidator * added test for collaborators --- Gopkg.toml | 1 + coredocument/read_acls.go | 8 +++---- coredocument/read_acls_test.go | 8 +++---- p2p/receiver/handler.go | 18 +++++++++++---- p2p/receiver/handler_integration_test.go | 5 +++-- p2p/receiver/validator.go | 28 ++++++++++++++++++++++++ p2p/receiver/validator_test.go | 27 +++++++++++++++++++---- 7 files changed, 77 insertions(+), 18 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index 406068c3d..30f1fb29f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,6 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" + revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" [[override]] diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index ae578b05a..41c031587 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -146,13 +146,13 @@ func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { return false } -// account returns the ReadAccessValidator tp verify account . -func accountValidator() ReadAccessValidator { +// AccountValidator returns the ReadAccessValidator to verify account . +func AccountValidator() ReadAccessValidator { return readAccessValidator{} } -// nftValidator returns the ReadAccessValidator for nft owner verification. -func nftValidator(tr TokenRegistry) ReadAccessValidator { +// NftValidator returns the ReadAccessValidator for nft owner verification. +func NftValidator(tr TokenRegistry) ReadAccessValidator { return readAccessValidator{tokenRegistry: tr} } diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index fc990e9b8..369023f1b 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -33,7 +33,7 @@ func TestReadACLs_initReadRules(t *testing.T) { } func TestReadAccessValidator_AccountCanRead(t *testing.T) { - pv := accountValidator() + pv := AccountValidator() account, err := identity.CentIDFromString("0x010203040506") assert.NoError(t, err) @@ -92,7 +92,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") // account can read - validator := nftValidator(nil) + validator := NftValidator(nil) err = validator.NFTOwnerCanRead(cd, registry, nil, account) assert.NoError(t, err) @@ -106,7 +106,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { tr := mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() addNFTToReadRules(cd, registry, tokenID) - validator = nftValidator(tr) + validator = NftValidator(tr) err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) assert.Contains(t, err, "failed to get owner of") @@ -116,7 +116,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { owner := common.BytesToAddress(utils.RandomSlice(20)) tr = mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() - validator = nftValidator(tr) + validator = NftValidator(tr) err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) tr.AssertExpectations(t) diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 03aacdc71..305ae3476 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -61,7 +61,6 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc if err != nil { return convertToErrorEnvelop(err) } - fromID, err := identity.ToCentID(envelope.Header.SenderId) if err != nil { return convertToErrorEnvelop(err) @@ -182,7 +181,12 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - res, err := srv.GetDocument(ctx, m) + requesterCentID, err := identity.ToCentID(msg.Header.SenderId) + if err != nil { + return convertToErrorEnvelop(err) + } + + res, err := srv.GetDocument(ctx, m, requesterCentID) if err != nil { return convertToErrorEnvelop(err) } @@ -201,8 +205,9 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc } // GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository -func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest) (*p2ppb.GetDocumentResponse, error) { +func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) (*p2ppb.GetDocumentResponse, error) { model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) + if err != nil { return nil, err } @@ -211,7 +216,12 @@ func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRe return nil, err } - return &p2ppb.GetDocumentResponse{Document: doc}, nil + err = DocumentAccessValidator(doc, docReq, requesterCentID) + if err != nil { + return &p2ppb.GetDocumentResponse{Document: doc}, nil + } + + return nil, err } func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 279ca6ad5..2f234a895 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -61,8 +61,9 @@ func TestMain(m *testing.M) { func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { b := utils.RandomSlice(32) + centrifugeId := createIdentity(t) req := &p2ppb.GetDocumentRequest{DocumentIdentifier: b} - resp, err := handler.GetDocument(context.Background(), req) + resp, err := handler.GetDocument(context.Background(), req, centrifugeId) assert.Error(t, err, "must return error") assert.Nil(t, resp, "must be nil") } @@ -101,7 +102,7 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { // Retrieve document from anchor repository with document_identifier getReq := getGetDocumentRequest(doc) - getDocResp, err := handler.GetDocument(ctxh, getReq) + getDocResp, err := handler.GetDocument(ctxh, getReq, centrifugeId) assert.Nil(t, err) assert.ObjectsAreEqual(getDocResp.Document, doc) } diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 8d4d6a001..83dd35ea4 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -3,6 +3,10 @@ package receiver import ( "fmt" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -101,6 +105,30 @@ func HandshakeValidator(networkID uint32, idService identity.Service) ValidatorG } } +// DocumentAccessValidator validates the GetDocument request against the AccessType indicated in the request +func DocumentAccessValidator(doc *coredocumentpb.CoreDocument, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) error { + av := coredocument.AccountValidator() + // checks which access type is relevant for the request + switch docReq.GetAccessType() { + case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: + if !av.AccountCanRead(doc, requesterCentID) { + return errors.New("requester does not have access") + } + case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: + registry := common.BytesToAddress(docReq.NftRegistryAddress) + if av.NFTOwnerCanRead(doc, registry, docReq.NftTokenId, requesterCentID) != nil { + return errors.New("requester does not have access") + } + //// case AccessTokenValidation + // case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: + // + // case p2ppb.AccessType_ACCESS_TYPE_INVALID: + default: + return errors.New("invalid access type ") + } + return nil +} + func incompatibleNetworkError(configNetwork uint32, nodeNetwork uint32) error { return centerrors.New(code.NetworkMismatch, fmt.Sprintf("Incompatible network id: node network: %d, client network: %d", configNetwork, nodeNetwork)) } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 777adc41d..5dca6b7bf 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -5,15 +5,18 @@ package receiver import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/stretchr/testify/mock" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/version" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" ) var ( @@ -138,3 +141,19 @@ func TestValidate_handshakeValidator(t *testing.T) { err = hv.Validate(header, &cID, &defaultPID) assert.NoError(t, err) } + +func TestDocumentAccessValidator_Collaborator(t *testing.T) { + account1, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + cd, err := coredocument.NewWithCollaborators([]string{account1.String()}) + assert.NotNil(t, cd.Collaborators) + + docId := cd.DocumentIdentifier + req := &p2ppb.GetDocumentRequest{DocumentIdentifier: docId, AccessType: p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION} + err = DocumentAccessValidator(cd, req, account1) + assert.NoError(t, err) + + account2, err := identity.CentIDFromString("0x012345678910") + err = DocumentAccessValidator(cd, req, account2) + assert.Error(t, err, "requester does not have access") +} From f1e2a3310f68d2ca7c680be3058bc94bb08c3251 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Mon, 28 Jan 2019 11:28:08 +0100 Subject: [PATCH 163/220] identity: AddKey and GetKey support added (#690) * added initial code for new identity * initial identity interfaces * added GetKey and AddKey to identity * formmatting logs --- ethereum/transaction_status_task.go | 14 ++- identity/did/bootstrapper.go | 9 +- identity/did/identity.go | 136 +++++++++++++++++++++- identity/did/identity_integration_test.go | 69 +++++++++++ identity/did/key.go | 57 +++++++++ identity/did/service.go | 10 +- 6 files changed, 284 insertions(+), 11 deletions(-) create mode 100644 identity/did/identity_integration_test.go create mode 100644 identity/did/key.go diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 74a57ee15..0bf974140 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -20,13 +20,21 @@ const ( // TransactionTxHashParam contains the name of the parameter TransactionTxHashParam string = "TxHashParam" // TransactionAccountParam contains the name of the account - TransactionAccountParam string = "Account ID" - transactionStatusSuccess uint64 = 1 + TransactionAccountParam string = "Account ID" + // TransactionStatusSuccess contains the flag for a successful receipt.status + TransactionStatusSuccess uint64 = 1 // ErrTransactionFailed error when transaction failed ErrTransactionFailed = errors.Error("Transaction failed") ) +// WatchTransaction holds the transaction status received form chain event +type WatchTransaction struct { + Status uint64 + txHash string + Error error +} + // TransactionStatusTask is struct for the task to check an Ethereum transaction type TransactionStatusTask struct { transactions.BaseTask @@ -123,7 +131,7 @@ func (nftc *TransactionStatusTask) isTransactionSuccessful(ctx context.Context, return err } - if receipt.Status != transactionStatusSuccess { + if receipt.Status != TransactionStatusSuccess { return ErrTransactionFailed } diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index 0ae2882c1..24437e8e1 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -17,9 +17,12 @@ import ( // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} -// BootstrappedDIDService stores the id of the bootstrapper +// BootstrappedDIDService stores the id of the service const BootstrappedDIDService string = "BootstrappedDIDService" +// BootstrappedDID stores the id of the identity +const BootstrappedDID string = "BootstrappedDID" + var smartContractAddresses *config.SmartContractAddresses // Bootstrap initializes the factory contract @@ -43,9 +46,11 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { } service := NewService(cfg, factoryContract, client) - context[BootstrappedDIDService] = service + identity := NewIdentity(cfg, client) + context[BootstrappedDID] = identity + return nil } diff --git a/identity/did/identity.go b/identity/did/identity.go index 5af25e04d..05b7d7cde 100644 --- a/identity/did/identity.go +++ b/identity/did/identity.go @@ -1,6 +1,17 @@ package did -import "github.com/ethereum/go-ethereum/common" +import ( + "context" + "math/big" + "time" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + id "github.com/centrifuge/go-centrifuge/identity" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) // DID stores the identity address of the user type DID common.Address @@ -18,3 +29,126 @@ func NewDID(address common.Address) DID { func NewDIDFromString(address string) DID { return DID(common.HexToAddress(address)) } + +// Identity interface contains the methods to interact with the identity contract +type Identity interface { + // AddKey adds a key to identity contract + AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, error) + // GetKey return a key from the identity contract + GetKey(did *DID, key [32]byte) (*KeyResponse, error) +} + +type contract interface { + + // calls + GetKey(opts *bind.CallOpts, _key [32]byte) (struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int + }, error) + + // transactions + AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) +} + +type identity struct { + config id.Config + client ethereum.Client +} + +func (i identity) prepareTransaction(did DID) (contract, *bind.TransactOpts, error) { + opts, err := i.client.GetTxOpts(i.config.GetEthereumDefaultAccountName()) + if err != nil { + log.Infof("Failed to get txOpts from Ethereum client: %v", err) + return nil, nil, err + } + + contract, err := i.bindContract(did) + if err != nil { + return nil, nil, err + } + + return contract, opts, nil + +} + +func (i identity) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelFunc, error) { + opts, cancelFunc := i.client.GetGethCallOpts(false) + + contract, err := i.bindContract(did) + if err != nil { + return nil, nil, nil, err + } + + return contract, opts, cancelFunc, nil + +} + +func (i identity) bindContract(did DID) (contract, error) { + contract, err := NewIdentityContract(did.toAddress(), i.client.GetEthClient()) + if err != nil { + return nil, errors.New("Could not bind identity contract: %v", err) + } + + return contract, nil + +} + +// NewIdentity creates a instance of an identity +func NewIdentity(config id.Config, client ethereum.Client) Identity { + return identity{config: config, client: client} +} + +// TODO: will be replaced with statusTask +func waitForTransaction(client ethereum.Client, txHash common.Hash, txStatus chan *ethereum.WatchTransaction) { + time.Sleep(3000 * time.Millisecond) + receipt, err := client.TransactionReceipt(context.Background(), txHash) + if err != nil { + txStatus <- ðereum.WatchTransaction{Error: err} + } + txStatus <- ðereum.WatchTransaction{Status: receipt.Status} + +} + +func logTxHash(tx *types.Transaction) { + log.Infof("Ethereum transaction created. Hash [%x] and Nonce [%v] and Check [%v]", tx.Hash(), tx.Nonce(), tx.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", tx.Hash()) +} + +func (i identity) AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, error) { + contract, opts, err := i.prepareTransaction(*did) + if err != nil { + return nil, err + } + + tx, err := i.client.SubmitTransactionWithRetries(contract.AddKey, opts, key.GetKey(), key.GetPurpose(), key.GetType()) + if err != nil { + log.Infof("could not addKey to identity contract: %v[txHash: %s] : %v", tx.Hash(), err) + return nil, errors.New("could not addKey to identity contract: %v", err) + } + logTxHash(tx) + + txStatus := make(chan *ethereum.WatchTransaction) + + // TODO will be replaced with transaction Status task + go waitForTransaction(i.client, tx.Hash(), txStatus) + + return txStatus, nil + +} + +func (i identity) GetKey(did *DID, key [32]byte) (*KeyResponse, error) { + contract, opts, _, err := i.prepareCall(*did) + if err != nil { + return nil, err + } + + result, err := contract.GetKey(opts, key) + + if err != nil { + return nil, errors.New("Could not call identity contract: %v", err) + } + + return &KeyResponse{result.Key, result.Purposes, result.RevokedAt}, nil + +} diff --git a/identity/did/identity_integration_test.go b/identity/did/identity_integration_test.go new file mode 100644 index 000000000..d46930cd7 --- /dev/null +++ b/identity/did/identity_integration_test.go @@ -0,0 +1,69 @@ +// +build integration + +package did + +import ( + "context" + "testing" + "time" + + "github.com/centrifuge/go-centrifuge/utils" + + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/stretchr/testify/assert" +) + +func getTestKey() Key { + return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} +} + +func deployIdentityContract(t *testing.T) *DID { + service := ctx[BootstrappedDIDService].(Service) + did, _, err := service.CreateIdentity(context.Background()) + assert.Nil(t, err, "create identity should be successful") + + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + time.Sleep(2000 * time.Millisecond) + + contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) + assert.Nil(t, err, "should be successful to get the contract code") + + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + return did + +} + +func TestAddKey_successful(t *testing.T) { + idSrv := ctx[BootstrappedDID].(Identity) + did := deployIdentityContract(t) + testKey := getTestKey() + + watchTrans, err := idSrv.AddKey(did, testKey) + assert.Nil(t, err, "add key should be successful") + + txStatus := <-watchTrans + assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions should be successful") + + response, err := idSrv.GetKey(did, testKey.GetKey()) + assert.Nil(t, err, "get Key should be successful") + + assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") +} + +func TestAddKey_fail(t *testing.T) { + did := NewDIDFromString("0x1234") + testKey := getTestKey() + idSrv := ctx[BootstrappedDID].(Identity) + + watchTrans, err := idSrv.AddKey(&did, testKey) + assert.Nil(t, err, "add key should be successful") + + txStatus := <-watchTrans + // contract is not existing but status is successful + assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions") + + _, err = idSrv.GetKey(&did, testKey.GetKey()) + assert.Error(t, err, "no contract code at given address") + +} diff --git a/identity/did/key.go b/identity/did/key.go new file mode 100644 index 000000000..e71ac3d43 --- /dev/null +++ b/identity/did/key.go @@ -0,0 +1,57 @@ +package did + +import ( + "fmt" + "math/big" + + "github.com/centrifuge/go-centrifuge/crypto/ed25519" +) + +// Key defines a single ERC725 identity key +type Key interface { + GetKey() [32]byte + GetPurpose() *big.Int + GetRevokedAt() *big.Int + GetType() *big.Int +} + +// KeyResponse contains the needed fields of the GetKey response +type KeyResponse struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +} + +// Key holds the identity related details +type key struct { + Key [32]byte + Purpose *big.Int + RevokedAt *big.Int + Type *big.Int +} + +// GetKey returns the public key +func (idk *key) GetKey() [32]byte { + return idk.Key +} + +// GetPurposes returns the purposes intended for the key +func (idk *key) GetPurpose() *big.Int { + return idk.Purpose +} + +// GetRevokedAt returns the block at which the identity is revoked +func (idk *key) GetRevokedAt() *big.Int { + return idk.RevokedAt +} + +// GetType returns the type of the key +func (idk *key) GetType() *big.Int { + return idk.Type +} + +// String prints the peerID extracted from the key +func (idk *key) String() string { + peerID, _ := ed25519.PublicKeyToP2PKey(idk.Key) + return fmt.Sprintf("%s", peerID.Pretty()) +} diff --git a/identity/did/service.go b/identity/did/service.go index c9550088f..34f48f1c5 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -4,7 +4,7 @@ import ( "context" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" + id "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" logging "github.com/ipfs/go-log" @@ -14,17 +14,17 @@ var log = logging.Logger("identity") // Service is the interface for identity related interactions type Service interface { - CreateIdentity(ctx context.Context) (id *DID, confirmations chan *identity.WatchIdentity, err error) + CreateIdentity(ctx context.Context) (id *DID, confirmations chan *id.WatchIdentity, err error) } type service struct { - config identity.Config + config id.Config factoryContract *FactoryContract client ethereum.Client } // NewService returns a new identity service -func NewService(config identity.Config, factoryContract *FactoryContract, client ethereum.Client) Service { +func NewService(config id.Config, factoryContract *FactoryContract, client ethereum.Client) Service { return &service{config: config, factoryContract: factoryContract, client: client} } @@ -41,7 +41,7 @@ func CalculateCreatedAddress(address common.Address, nonce uint64) common.Addres return crypto.CreateAddress(address, nonce) } -func (s *service) CreateIdentity(ctx context.Context) (id *DID, confirmations chan *identity.WatchIdentity, err error) { +func (s *service) CreateIdentity(ctx context.Context) (id *DID, confirmations chan *id.WatchIdentity, err error) { opts, err := s.client.GetTxOpts(s.config.GetEthereumDefaultAccountName()) if err != nil { log.Infof("Failed to get txOpts from Ethereum client: %v", err) From c2674f2c130d0f6ab39c77bf352b2b795afc7355 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 28 Jan 2019 12:35:04 +0100 Subject: [PATCH 164/220] Documentation with doc.go (#695) * Documentation with doc.go * Fix some problems with model --- bootstrap/doc.go | 62 ++++++ documents/doc.go | 179 ++++++++++++++++ p2p/client.go | 4 +- p2p/client_test.go | 10 +- p2p/doc.go | 57 ++++++ p2p/{ => messenger}/messenger.go | 40 ++-- p2p/messenger/messenger_test.go | 339 +++++++++++++++++++++++++++++++ p2p/messenger_test.go | 162 --------------- p2p/server.go | 25 ++- 9 files changed, 677 insertions(+), 201 deletions(-) create mode 100644 bootstrap/doc.go create mode 100644 documents/doc.go create mode 100644 p2p/doc.go rename p2p/{ => messenger}/messenger.go (90%) create mode 100644 p2p/messenger/messenger_test.go delete mode 100644 p2p/messenger_test.go diff --git a/bootstrap/doc.go b/bootstrap/doc.go new file mode 100644 index 000000000..6ecb26cb6 --- /dev/null +++ b/bootstrap/doc.go @@ -0,0 +1,62 @@ +/* + +Package bootstrap maintains the bootstrapping interface design for go-centrifuge. +These interfaces are defined to enable decoupling between implementation of various implementation packages of +go-centrifuge and their runtime instantiation logic. + +Why Bootstrapper interface was needed + +Unlike a regular library, process runtime code has certain dependencies on a central instantiation +point in the software for it to be initialised properly. For go-centrifuge this made it difficult to +change instantiation logic based on the need(eg: commands vs daemon) because of cyclic dependencies or to reuse that logic for purposes of testing. +The use of global variables to access already initialised implementations meant that it was hard to identify the dependencies needed for each module to function properly. +Also this meant that instantiation logic got coupled to a particular implementation of a package interface. For example leveldb implementation of storage +was being used even for unit tests because there was no way to mock it out individually. + +Other than solving those problems while allowing the code to slowly evolve, Bootstrappers satisfies the need for inversion of control(IOC) +where modules of code get injected with their dependencies based on a requirement defined by each package in the bootstrapper.go. +This convention of defining a boostrapper.go in each package also serves as a good documentation source as well as to reduce +complexity in understanding the code base at a global level. The package level bootstrapper also helps in implementing runtime +behavior modifications based on IOC, that are very useful in simulations. + +How Bootstrappers work + +The interface is simple it has a simple function, + + Bootstrap(context map[string]interface{}) error + +This can be implemented by each package that needs runtime instantiation based on some dependencies that are already defined in the runtime. +The bootstrapper calling sequence is hard coded in for the particular scenario(with mocks if needed in a test) and called by the central instantiation point(main). +The context map contains objects already defined in the runtime keyed by well known names defined with constants in each package that exposes those objects interfaces. + +Eg: +First storage package defines an interface and a key for the implementation in the context map in storage/repo.go + + type Repository { + Get(key []byte) []byte + } + + const BootstrappedDB string = "BootstrappedDB" + +Then the leveldb implementation of the above interface in leveldb package injects the instantiated leveldb implementation in storage/leveldb/bootstrapper.go + + // .. + func Bootstrap(context map[string]interface{}) error { + // ... + + context[storage.BootstrappedDB] = NewLevelDB(..) + } + +After this a downstream package bootstrapped can use the context[storage.BootstrappedDB] object to for its own instantiation, in document/bootstrapper.go + + // .. + ldb, ok := ctx[storage.BootstrappedDB].(storage.Repository) + if !ok { + return ErrDocumentBootstrap + } + + repo := NewDocRepository(ldb) + +Check go-centrifuge/cmd package to see how the Bootstrapper interfaces are used to bootstrap go-centrifuge. +*/ +package bootstrap diff --git a/documents/doc.go b/documents/doc.go new file mode 100644 index 000000000..f815a0c71 --- /dev/null +++ b/documents/doc.go @@ -0,0 +1,179 @@ +/* +Package documents implements Centrifuge document models. + +Models + +The idea of having a model is to make the business functions of the document clearer and more readable. This also enables proper types and validations on the fields that require them. When an API call is received, the following list of transformations/steps needs to be executed on the request object. + +1. Model conversion: this would ensure that proper types are created for each of the fields of the input document plus handling basic level validations that does not require business level understanding of the document. eg: telephone numbers, IDs + +2. The converted model is updated using the existing document. After this there would be two versions of the document in the system old and the new + +3. The two versions of the document are passed through a purpose specific validator chain that implements the following interface. (see chapter on validation) + +Model Storage + +A model objects must support storage in DB as a JSON serialized object. The rationale behind this is that JSON format enables easier inter-operability between systems that +would depend on database access such as BI (Although we do NOT recommend directly accessing the db eventually when we have proper APIs for accessing all data). + + // example of an implementation + type InvoiceModel struct { + // all invoice fields with proper types here + } + + func (i *InvoiceModel) PackCoreDocument() *coredocumentpb.CoreDocument { + panic("implement me") + } + + func (i *InvoiceModel) UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error { + panic("implement me") + } + + func (i *InvoiceModel) JSON() ([]byte, error) { + panic("implement me") + } + + func (i *InvoiceModel) Type() reflect.Type { + return reflect.TypeOf(i) + } + + +Model Package Hierarchy Specification + +In the new package structure the package `documents` includes all model relevant implementations and interfaces. +The actual implementation can be found at the package `invoice` or `purchaseorder`. +The package `documents` should not include any of the actual implementations to avoid cycle dependencies. + +Validation + +Validations should be done depending on the situation. The below table is an example that shows a few examples of validations that should only depending on context of the validation. + + | | Verify SigningRoot | Verify DocumentRoot | Check Invoice State Transition | Node must be in collaborators | + |---------------------------|---------------------|---------------------|--------------------------------|-------------------------------| + | Client Submission | | | yes | yes | + | Signature Request | yes | | | | + | Receive Anchored Document | yes | yes | | yes | + | Store in DB | yes | only if set | | yes | + + +Validations are implemented in individual checks. These individual checks can be nested in different grouped set of validations. Validators all implement the Validator interface to allow simple nesting of checks. + +There are three types of validators: + +1. **Atomic Validators:** they validate an individual field or several fields and contain actual checking of certain values, checking of an anchor etc. Atomic validators are never split up. Anything an atomic validator validates would always be validated as one block. + +2. **Internal Group Validations:** contain a collection of atomic validators but these are not grouped by purpose but elements that are reused in other validators (group or purpose validators) + +3. **Purpose Validators:** these validators are public and used by the application logic to validate a document. They should never be used inside of other validators. Code performing validation should always call a purpose validator but never an internal group directly. + + + type interface Validator { + // Validate validates the updates to the model in newState. errors returned must always be centerrors + Validate(oldState Model, newState Model) []error + } + + + // ValidatorGroup implements Validator for executing a set of validators. + type ValidatorGroup struct { + []Validator validators + } + func (group *ValidatorGroup) Validate(oldState Model, newState Model) (validationErrors []error) { + + for v, i := range group.validators { + validationErrors = append(validationErrors, v.Validate(oldState, newState)) + } + } + + // An implementation of ValidatorGroup as an example. + // Note that this is not a public validator but merely a private variable that can be reused in validators. + var invoiceHeaderValidators = ValidatorGroup{ + validators: []Validator{ + Field1Validator, + Field2Validator, + Field3Validator + } + } + + // An implementation of a Validator that is used by other services + // Note that this is public + var ValidateOnSignatureRequest = ValidatorGroup{ + validators: []Validator{ + invoiceHeaderValidator, ... + } + } + + +Controllers, Services and Their Relationship with Models + +1. Controllers + +Controllers are generally the first contact point between an external request and the application logic. The implementations would just pass control over to a request specific `Service` layer call. + +2. Services + +Services in the CentNode must deal with only specific Model object plus its related objects. Eg: InvoiceService would only deal with InvoiceModel. Since in many cases a model object may need to be created based on some external input such as a coredocument, the following are some good base interfaces for a service to implement, + + // Implementation of deriving model objects + type InvoiceService struct { } + + func (srv *InvoiceService) DeriveFromCoreDocument(cd *coredocument.CoreDocument) (*InvoiceModel, error) { + panic("Implement me"); + } + + func (srv *InvoiceService) DeriveWithCreateInvoiceInput(*CreateInvoiceInput) (*InvoiceModel, error) { + panic("Implement me"); + } + + + +Service Registry + +To locate a service that could handle operations for a given CoreDocument object a service registry needs to be developed. This would use the `coreDocument.EmbeddedData.TypeUrl` to map the document to the relevant service. + + + // in documents/registry.go + + func LocateService(cd *coredocument.CoreDocument) (ModelDeriver, error) { + .... + } + +Every service should be able to `register` itself at the `ServiceRegistry` if it implements the `ModelDeriver` interface. + + func (s *ServiceRegistry) Register(serviceID string, service ModelDeriver) error + + +The registry should be thread safe. + + +A Sample Flow for Handling Document Signature Requests + +The following is an example modification of `Handler.RequestDocumentSignature` to show the usage of `Registry`, `Service` and `Model` interactions. + + func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { + service, err := registry.LocateService(sigReq.Document) + if err != nil { + return nil, err + } + + model, err := service.DeriveWithCD(sigReq.Document) + if err != nil { + return nil, err + } + + if p2pService, ok := service.(P2PSignatureRequestHandler); ok { + sig, errors := p2pService.Sign(model) + if len(errs) != 0 { + return nil, centerrors.NewWithErrors(errs) + } + return &p2ppb.SignatureResponse{ + CentNodeVersion: version.GetVersion().String(), + Signature: sig, + }, nil + } + + return nil, someerrorThatcausedServiceMismatch + + } + +*/ +package documents diff --git a/p2p/client.go b/p2p/client.go index 7391bc64a..e98ec9dab 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -59,7 +59,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.Cen return nil, err } - recv, err := s.mes.sendMessage( + recv, err := s.mes.SendMessage( ctx, pid, envelope, p2pcommon.ProtocolForCID(receiverID)) @@ -167,7 +167,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.C return nil, err } log.Infof("Requesting signature from %s\n", receiverPeer) - recv, err := s.mes.sendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForCID(receiverCentID)) + recv, err := s.mes.SendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForCID(receiverCentID)) if err != nil { return nil, err } diff --git a/p2p/client_test.go b/p2p/client_test.go index 973d180c3..3a6d0c50c 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -34,11 +34,11 @@ type MockMessenger struct { mock.Mock } -func (mm *MockMessenger) init(id ...protocol.ID) { +func (mm *MockMessenger) Init(id ...protocol.ID) { mm.Called(id) } -func (mm *MockMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *protocolpb.P2PEnvelope, protoc protocol.ID) (*protocolpb.P2PEnvelope, error) { +func (mm *MockMessenger) SendMessage(ctx context.Context, p libp2pPeer.ID, pmes *protocolpb.P2PEnvelope, protoc protocol.ID) (*protocolpb.P2PEnvelope, error) { args := mm.Called(ctx, p, pmes, protoc) resp, _ := args.Get(0).(*protocolpb.P2PEnvelope) return resp, args.Error(1) @@ -60,7 +60,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -83,7 +83,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -109,7 +109,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("sendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) diff --git a/p2p/doc.go b/p2p/doc.go new file mode 100644 index 000000000..f80d26ba5 --- /dev/null +++ b/p2p/doc.go @@ -0,0 +1,57 @@ +/* +Package p2p implements the Centrifuge wire protocol. Centrifuge wire protocol is used by p2p clients in the centrifuge +network to communicate about various protocol activities such as document consensus. This document is a specification of this wire protocol. + +Background + +In order to understand the design decisions behind the protocol one needs a quick background on libp2p and protobufs the tech stack used by the initial implementation of the protocol - `go-centrifuge`, though the wire protocol it self is independant of this stack. + +- Libp2p protocol multiplexing + +Libp2p can multiplex messages from multiple protocols in to the same `inet` stream. The protocols identifiers can be something like `/centrifuge/0.1` and `/http/v2`, one can register handlers for each of these protocols in the libp2p host and it will take care of routing the messages to the appropriate handler. + +Further reading - https://github.com/libp2p/specs/blob/master/6-interfaces.md + +- Protobufs + +Centrifuge wire protocol uses google protobufs to encode the message envelopes used in the network. Its an efficient format for encoding/decoding as well as having good multi language support. + +Further reading - https://developers.google.com/protocol-buffers/ + + +The Protocol + +1. Protocol Identifier + +Centrifuge wire protocol uses libp2p protocol multiplexing as a way to differenciate protocol versions as well as the centrifuge ID that a particular message is targetted at in the centrifuge node. +i.e. at the start of the node protocol handlers are registered for each protocol version for each `centrifugeID` configured in the system. Given this requirement a centrifuge protocol identifier string must comply to the following format, +`/centrifuge//` +Eg: `/centrifuge/0.0.1/0xf71876181dce` + + +2. Centrifuge Protocol Envelope + + +----------------------------------------------------+------------------------------+ + |Envelope length in varint |predefined centrifuge | message bytes | + | |message type | (encoding depends on type) | + +----------------------------------------------------+------------------------------+ + + +Once a message is forwarded to the stream handler registered for a particular protocol ID, The illustrated envelope needs to be decoded by the handler in order to process the message. + +2.1 The message envelope is encoded as a protobuf. + + message P2PEnvelope { + // defines what type of message it is. (if we modify centrifuge-protobufs we can use type any with typeURL here) + MessageType type = 1; + // serialized (could be a protobuf) for the actual message + bytes body = 2; + } + +2.2 The encoded envelope is written to the stream using a `byte length delimited` encoding which allows stream decoder to iterate the number of bytes in the following stream that are relevant to the current message. A Length varint of 2 means that the value is 2 byte length followed by the specified number of bytes of data. + +2.3 Once the message has been decoded(unmarshalled) in to `MessageEnvelope` the handler(router) can identify the message type and forward to the relevant specific handler for the given message type. The message type in this case is also serves as a protocol multiplexer. + +2.4 The actual message byte encoding depends on the message type as well, which the router can decide to decode or forward as is. +*/ +package p2p diff --git a/p2p/messenger.go b/p2p/messenger/messenger.go similarity index 90% rename from p2p/messenger.go rename to p2p/messenger/messenger.go index 89105cc93..8f6cea0e2 100644 --- a/p2p/messenger.go +++ b/p2p/messenger/messenger.go @@ -1,4 +1,4 @@ -package p2p +package messenger import ( "bufio" @@ -7,18 +7,16 @@ import ( "sync" "time" - "github.com/golang/protobuf/proto" - "github.com/centrifuge/go-centrifuge/errors" - - "github.com/libp2p/go-libp2p-host" - "github.com/libp2p/go-libp2p-protocol" - pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" ggio "github.com/gogo/protobuf/io" + "github.com/golang/protobuf/proto" + logging "github.com/ipfs/go-log" "github.com/jbenet/go-context/io" + "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" libp2pPeer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" ) const ( @@ -33,6 +31,8 @@ const ( ErrInvalidatedMessageSender = errors.Error("message sender has been invalidated") ) +var log = logging.Logger("p2p-messenger") + type bufferedWriteCloser interface { ggio.WriteCloser Flush() error @@ -58,7 +58,8 @@ func (w *bufferedDelimitedWriter) Flush() error { return w.Writer.Flush() } -type p2pMessenger struct { +// P2PMessenger is a libp2p messenger using protobufs and length delimited encoding +type P2PMessenger struct { host host.Host // the network services we need self libp2pPeer.ID // Local peer (yourself) @@ -73,9 +74,10 @@ type p2pMessenger struct { handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error) } -func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration, - handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) *p2pMessenger { - return &p2pMessenger{ +// NewP2PMessenger returns a libp2p-messenger +func NewP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Duration, + handler func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (*pb.P2PEnvelope, error)) *P2PMessenger { + return &P2PMessenger{ ctx: ctx, host: host, self: host.ID(), @@ -85,19 +87,19 @@ func newP2PMessenger(ctx context.Context, host host.Host, p2pTimeout time.Durati } } -// init initiates listening to given set of protocol streams -func (mes *p2pMessenger) init(protocols ...protocol.ID) { +// Init initiates listening to given set of protocol streams +func (mes *P2PMessenger) Init(protocols ...protocol.ID) { for _, p := range protocols { mes.host.SetStreamHandler(p, mes.handleNewStream) } } // handleNewStream implements the inet.StreamHandler -func (mes *p2pMessenger) handleNewStream(s inet.Stream) { +func (mes *P2PMessenger) handleNewStream(s inet.Stream) { go mes.handleNewMessage(s) } -func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { +func (mes *P2PMessenger) handleNewMessage(s inet.Stream) { ctx := mes.ctx // ok to use. we defer close stream in this func cr := ctxio.NewReader(ctx, s) @@ -155,8 +157,8 @@ func (mes *p2pMessenger) handleNewMessage(s inet.Stream) { } } -// sendMessage sends out a request -func (mes *p2pMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) { +// SendMessage sends out a request +func (mes *P2PMessenger) SendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) { ms, err := mes.messageSenderForPeerAndProto(p, protoc) if err != nil { return nil, err @@ -170,7 +172,7 @@ func (mes *p2pMessenger) sendMessage(ctx context.Context, p libp2pPeer.ID, pmes return rpmes, nil } -func (mes *p2pMessenger) messageSenderForPeerAndProto(p libp2pPeer.ID, protoc protocol.ID) (*messageSender, error) { +func (mes *P2PMessenger) messageSenderForPeerAndProto(p libp2pPeer.ID, protoc protocol.ID) (*messageSender, error) { mes.smlk.Lock() ms, ok := mes.strmap[p][protoc] if ok { @@ -214,7 +216,7 @@ type messageSender struct { lk sync.Mutex p libp2pPeer.ID protoc protocol.ID - mes *p2pMessenger + mes *P2PMessenger invalid bool singleMes int diff --git a/p2p/messenger/messenger_test.go b/p2p/messenger/messenger_test.go new file mode 100644 index 000000000..d9aafabb1 --- /dev/null +++ b/p2p/messenger/messenger_test.go @@ -0,0 +1,339 @@ +// +build unit + +package messenger + +import ( + "context" + "crypto/rand" + "fmt" + "io" + "os" + "testing" + "time" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/common" + pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + "github.com/ipfs/go-ipfs-addr" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-crypto" + "github.com/libp2p/go-libp2p-host" + "github.com/libp2p/go-libp2p-kad-dht" + libp2pPeer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + "github.com/libp2p/go-libp2p-protocol" + ma "github.com/multiformats/go-multiaddr" + mh "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/assert" +) + +const MessengerDummyProtocol protocol.ID = "/messeger/dummy/0.0.1" +const MessengerDummyProtocol2 protocol.ID = "/messeger/dummy/0.0.2" + +var mockedHandler = func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { + dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) + if err != nil { + return nil, err + } + if p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDocRep.String() + } else if p2pcommon.MessageTypeRequestSignature.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeRequestSignatureRep.String() + } else if p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type) { + dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDoc.String() + } else if p2pcommon.MessageTypeError.Equals(dataEnv.Header.Type) { + return nil, errors.New("dummy error") + } else if p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type) { + return nil, nil + } else if p2pcommon.MessageTypeInvalid.Equals(dataEnv.Header.Type) { + return nil, errors.New("invalid data") + } + + return p2pcommon.PrepareP2PEnvelope(ctx, uint32(0), p2pcommon.MessageTypeFromString(dataEnv.Header.Type), dataEnv) +} + +var cfg config.Service + +func TestMain(m *testing.M) { + ctx := make(map[string]interface{}) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + &configstore.Bootstrapper{}, + &queue.Bootstrapper{}, + transactions.Bootstrapper{}, + &anchors.Bootstrapper{}, + documents.Bootstrapper{}, + } + idService := &testingcommons.MockIDService{} + ctx[identity.BootstrappedIDService] = idService + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + cfg = ctx[config.BootstrappedConfigStorage].(config.Service) + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + +// Using a single test for all cases to use the same hosts in a synchronous way +func TestHandleNewMessage(t *testing.T) { + cfg, err := cfg.GetConfig() + assert.NoError(t, err) + cfg = updateKeys(cfg) + ctx, canc := context.WithCancel(context.Background()) + c := testingconfig.CreateTenantContextWithContext(t, ctx, cfg) + r := rand.Reader + p1 := 35000 + p2 := 35001 + p3 := 35002 + h1 := createRandomHost(t, p1, r) + h2 := createRandomHost(t, p2, r) + h3 := createRandomHost(t, p3, r) + // set h2 as the bootnode for h1 + _ = runDHT(c, h1, []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", p2, h2.ID().Pretty())}) + + m1 := NewP2PMessenger(c, h1, 5*time.Second, mockedHandler) + m2 := NewP2PMessenger(c, h2, 5*time.Second, mockedHandler) + + m1.Init(MessengerDummyProtocol) + m2.Init(MessengerDummyProtocol) + m2.Init(MessengerDummyProtocol2) + + // 1. happy path + // from h1 to h2 (with a message size ~ MessageSizeMax, has to be less because of the length bytes) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax - 400)}) + assert.NoError(t, err) + msg, err := m1.SendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) + assert.NoError(t, err) + dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) + assert.NoError(t, err) + assert.True(t, p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type)) + + // from h1 to h2 different protocol - intentionally setting reply-response in opposite for differentiation + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDocRep, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol2) + assert.NoError(t, err) + dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) + assert.NoError(t, err) + assert.True(t, p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type)) + + // from h2 to h1 + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDoc, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m2.SendMessage(c, h1.ID(), p2pEnv, MessengerDummyProtocol) + assert.NoError(t, err) + dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) + assert.NoError(t, err) + assert.True(t, p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type)) + + // 2. unrecognized protocol + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h2.ID(), p2pEnv, "wrong") + if assert.Error(t, err) { + assert.Equal(t, "protocol not supported", err.Error()) + } + + // 3. unrecognized message type - stream would be reset by the peer + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeInvalid, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } + + // 4. handler error + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeError, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } + + // 5. can't find host - h3 + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h3.ID(), p2pEnv, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "dial attempt failed: failed to dial MessageSizeMax) + p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax)}) + assert.NoError(t, err) + msg, err = m1.SendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) + if assert.Error(t, err) { + assert.Equal(t, "stream reset", err.Error()) + } + canc() +} + +func createRandomHost(t *testing.T, port int, r io.Reader) host.Host { + priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) + assert.NoError(t, err) + h1, err := makeBasicHost(priv, pub, "", port) + assert.NoError(t, err) + return h1 +} + +// makeBasicHost creates a LibP2P host with a peer ID listening on the given port +func makeBasicHost(priv crypto.PrivKey, pub crypto.PubKey, externalIP string, listenPort int) (host.Host, error) { + // Obtain Peer ID from public key + // We should be using the following method to get the ID, but looks like is not compatible with + // secio when adding the pub and pvt keys, fail as id+pub/pvt key is checked to match and method defaults to + // IDFromPublicKey(pk) + //pid, err := peer.IDFromEd25519PublicKey(pub) + pid, err := libp2pPeer.IDFromPublicKey(pub) + if err != nil { + return nil, err + } + + // Create a peerstore + ps := pstore.NewPeerstore() + + // Add the keys to the peerstore + // for this peer ID. + err = ps.AddPubKey(pid, pub) + if err != nil { + log.Infof("Could not enable encryption: %v\n", err) + return nil, err + } + + err = ps.AddPrivKey(pid, priv) + if err != nil { + log.Infof("Could not enable encryption: %v\n", err) + return nil, err + } + + var extMultiAddr ma.Multiaddr + if externalIP == "" { + log.Warning("External IP not defined, Peers might not be able to resolve this node if behind NAT\n") + } else { + extMultiAddr, err = ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", externalIP, listenPort)) + if err != nil { + return nil, errors.New("failed to create multiaddr: %v", err) + } + } + + addressFactory := func(addrs []ma.Multiaddr) []ma.Multiaddr { + if extMultiAddr != nil { + // We currently support a single protocol and transport, if we add more to support then we will need to adapt this code + addrs = []ma.Multiaddr{extMultiAddr} + } + return addrs + } + + opts := []libp2p.Option{ + libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", listenPort)), + libp2p.Identity(priv), + libp2p.DefaultMuxers, + libp2p.AddrsFactory(addressFactory), + } + + bhost, err := libp2p.New(context.Background(), opts...) + if err != nil { + return nil, err + } + + hostAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", bhost.ID().Pretty())) + if err != nil { + return nil, errors.New("failed to get addr: %v", err) + } + + log.Infof("P2P Server at: %s %s\n", hostAddr.String(), bhost.Addrs()) + return bhost, nil +} + +func runDHT(ctx context.Context, h host.Host, bootstrapPeers []string) error { + // Run it as a Bootstrap Node + dhtClient := dht.NewDHT(ctx, h, ds.NewMapDatastore()) + log.Infof("Bootstrapping %s\n", bootstrapPeers) + + for _, addr := range bootstrapPeers { + iaddr, _ := ipfsaddr.ParseString(addr) + pinfo, _ := pstore.InfoFromP2pAddr(iaddr.Multiaddr()) + if err := h.Connect(ctx, *pinfo); err != nil { + log.Info("Bootstrapping to peer failed: ", err) + } + } + + // Using the sha256 of our "topic" as our rendezvous value + cidPref, _ := cid.NewPrefixV1(cid.Raw, mh.SHA2_256).Sum([]byte("centrifuge-dht")) + + // First, announce ourselves as participating in this topic + log.Info("Announcing ourselves...") + tctx, cancel := context.WithTimeout(ctx, time.Second*10) + if err := dhtClient.Provide(tctx, cidPref, true); err != nil { + // Important to keep this as Non-Fatal error, otherwise it will fail for a node that behaves as well as bootstrap one + log.Infof("Error: %s\n", err.Error()) + } + cancel() + + // Now, look for others who have announced + log.Info("Searching for other peers ...") + tctx, cancel = context.WithTimeout(ctx, time.Second*10) + peers, err := dhtClient.FindProviders(tctx, cidPref) + if err != nil { + log.Error(err) + } + cancel() + log.Infof("Found %d peers!\n", len(peers)) + + // Now connect to them, so they are added to the PeerStore + for _, pe := range peers { + log.Infof("Peer %s %s\n", pe.ID.Pretty(), pe.Addrs) + + if pe.ID == h.ID() { + // No sense connecting to ourselves + continue + } + + tctx, cancel := context.WithTimeout(ctx, time.Second*5) + if err := h.Connect(tctx, pe); err != nil { + log.Info("Failed to connect to peer: ", err) + } + cancel() + } + + log.Info("Bootstrapping and discovery complete!") + return nil +} + +func updateKeys(c config.Configuration) config.Configuration { + n := c.(*configstore.NodeConfig) + n.MainIdentity.SigningKeyPair.Pub = "../../build/resources/signingKey.pub.pem" + n.MainIdentity.SigningKeyPair.Priv = "../../build/resources/signingKey.key.pem" + n.MainIdentity.EthAuthKeyPair.Pub = "../../build/resources/ethauth.pub.pem" + n.MainIdentity.EthAuthKeyPair.Priv = "../../build/resources/ethauth.key.pem" + return c +} diff --git a/p2p/messenger_test.go b/p2p/messenger_test.go deleted file mode 100644 index f02d9812c..000000000 --- a/p2p/messenger_test.go +++ /dev/null @@ -1,162 +0,0 @@ -// +build unit - -package p2p - -import ( - "context" - "crypto/rand" - "fmt" - "io" - "testing" - "time" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/errors" - - pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/libp2p/go-libp2p-crypto" - "github.com/libp2p/go-libp2p-host" - libp2pPeer "github.com/libp2p/go-libp2p-peer" - "github.com/libp2p/go-libp2p-protocol" - "github.com/stretchr/testify/assert" -) - -const MessengerDummyProtocol protocol.ID = "/messeger/dummy/0.0.1" -const MessengerDummyProtocol2 protocol.ID = "/messeger/dummy/0.0.2" - -var mockedHandler = func(ctx context.Context, peer libp2pPeer.ID, protoc protocol.ID, msg *pb.P2PEnvelope) (envelope *pb.P2PEnvelope, e error) { - dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) - if err != nil { - return nil, err - } - if p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type) { - dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDocRep.String() - } else if p2pcommon.MessageTypeRequestSignature.Equals(dataEnv.Header.Type) { - dataEnv.Header.Type = p2pcommon.MessageTypeRequestSignatureRep.String() - } else if p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type) { - dataEnv.Header.Type = p2pcommon.MessageTypeSendAnchoredDoc.String() - } else if p2pcommon.MessageTypeError.Equals(dataEnv.Header.Type) { - return nil, errors.New("dummy error") - } else if p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type) { - return nil, nil - } else if p2pcommon.MessageTypeInvalid.Equals(dataEnv.Header.Type) { - return nil, errors.New("invalid data") - } - - return p2pcommon.PrepareP2PEnvelope(ctx, uint32(0), p2pcommon.MessageTypeFromString(dataEnv.Header.Type), dataEnv) -} - -// Using a single test for all cases to use the same hosts in a synchronous way -func TestHandleNewMessage(t *testing.T) { - cfg, err := cfg.GetConfig() - assert.NoError(t, err) - cfg = updateKeys(cfg) - ctx, canc := context.WithCancel(context.Background()) - c := testingconfig.CreateTenantContextWithContext(t, ctx, cfg) - r := rand.Reader - p1 := 35000 - p2 := 35001 - p3 := 35002 - h1 := createRandomHost(t, p1, r) - h2 := createRandomHost(t, p2, r) - h3 := createRandomHost(t, p3, r) - // set h2 as the bootnode for h1 - _ = runDHT(c, h1, []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/ipfs/%s", p2, h2.ID().Pretty())}) - - m1 := newP2PMessenger(c, h1, 5*time.Second, mockedHandler) - m2 := newP2PMessenger(c, h2, 5*time.Second, mockedHandler) - - m1.init(MessengerDummyProtocol) - m2.init(MessengerDummyProtocol) - m2.init(MessengerDummyProtocol2) - - // 1. happy path - // from h1 to h2 (with a message size ~ MessageSizeMax, has to be less because of the length bytes) - p2pEnv, err := p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax - 400)}) - assert.NoError(t, err) - msg, err := m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) - assert.NoError(t, err) - dataEnv, err := p2pcommon.ResolveDataEnvelope(msg) - assert.NoError(t, err) - assert.True(t, p2pcommon.MessageTypeRequestSignatureRep.Equals(dataEnv.Header.Type)) - - // from h1 to h2 different protocol - intentionally setting reply-response in opposite for differentiation - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDocRep, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol2) - assert.NoError(t, err) - dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) - assert.NoError(t, err) - assert.True(t, p2pcommon.MessageTypeSendAnchoredDoc.Equals(dataEnv.Header.Type)) - - // from h2 to h1 - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeSendAnchoredDoc, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m2.sendMessage(c, h1.ID(), p2pEnv, MessengerDummyProtocol) - assert.NoError(t, err) - dataEnv, err = p2pcommon.ResolveDataEnvelope(msg) - assert.NoError(t, err) - assert.True(t, p2pcommon.MessageTypeSendAnchoredDocRep.Equals(dataEnv.Header.Type)) - - // 2. unrecognized protocol - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, "wrong") - if assert.Error(t, err) { - assert.Equal(t, "protocol not supported", err.Error()) - } - - // 3. unrecognized message type - stream would be reset by the peer - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeInvalid, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) - if assert.Error(t, err) { - assert.Equal(t, "stream reset", err.Error()) - } - - // 4. handler error - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeError, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) - if assert.Error(t, err) { - assert.Equal(t, "stream reset", err.Error()) - } - - // 5. can't find host - h3 - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(3)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h3.ID(), p2pEnv, MessengerDummyProtocol) - if assert.Error(t, err) { - assert.Contains(t, err.Error(), "dial attempt failed: failed to dial MessageSizeMax) - p2pEnv, err = p2pcommon.PrepareP2PEnvelope(c, uint32(0), p2pcommon.MessageTypeRequestSignature, &p2ppb.Envelope{Body: utils.RandomSlice(MessageSizeMax)}) - assert.NoError(t, err) - msg, err = m1.sendMessage(c, h2.ID(), p2pEnv, MessengerDummyProtocol) - if assert.Error(t, err) { - assert.Equal(t, "stream reset", err.Error()) - } - canc() -} - -func createRandomHost(t *testing.T, port int, r io.Reader) host.Host { - priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) - assert.NoError(t, err) - h1, err := makeBasicHost(priv, pub, "", port) - assert.NoError(t, err) - return h1 -} diff --git a/p2p/server.go b/p2p/server.go index 387c57a11..8f93983e1 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -7,18 +7,13 @@ import ( "time" "github.com/centrifuge/go-centrifuge/config" - + cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/p2p/common" + ms "github.com/centrifuge/go-centrifuge/p2p/messenger" "github.com/centrifuge/go-centrifuge/p2p/receiver" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - - "github.com/libp2p/go-libp2p-protocol" - - "github.com/centrifuge/go-centrifuge/errors" - - cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-ipfs-addr" @@ -29,6 +24,7 @@ import ( "github.com/libp2p/go-libp2p-kad-dht" libp2pPeer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" + "github.com/libp2p/go-libp2p-protocol" ma "github.com/multiformats/go-multiaddr" mh "github.com/multiformats/go-multihash" ) @@ -37,9 +33,12 @@ var log = logging.Logger("p2p-server") // messenger is an interface to wrap p2p messaging implementation type messenger interface { - init(protocols ...protocol.ID) - sendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) + // Init inits the messenger + Init(protocols ...protocol.ID) + + // SendMessage sends a message through messenger + SendMessage(ctx context.Context, p libp2pPeer.ID, pmes *pb.P2PEnvelope, protoc protocol.ID) (*pb.P2PEnvelope, error) } // peer implements node.Server @@ -85,7 +84,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- return } - s.mes = newP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout(), s.handlerCreator().HandleInterceptor) + s.mes = ms.NewP2PMessenger(ctx, s.host, nc.GetP2PConnectionTimeout(), s.handlerCreator().HandleInterceptor) err = s.initProtocols() if err != nil { startupErr <- err @@ -115,13 +114,13 @@ func (s *peer) initProtocols() error { } protocols = append(protocols, p2pcommon.ProtocolForCID(CID)) } - s.mes.init(protocols...) + s.mes.Init(protocols...) return nil } func (s *peer) InitProtocolForCID(CID identity.CentID) { p := p2pcommon.ProtocolForCID(CID) - s.mes.init(p) + s.mes.Init(p) } func (s *peer) createSigningKey(pubKey, privKey string) (priv crypto.PrivKey, pub crypto.PubKey, err error) { From afb2074968f36fb3de45eb057c02e196cdac303c Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 28 Jan 2019 14:23:01 +0100 Subject: [PATCH 165/220] Currently godoc.org doesn't index the root directory, this fixes it (#696) --- doc.go | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 doc.go diff --git a/doc.go b/doc.go new file mode 100644 index 000000000..1a4ce710b --- /dev/null +++ b/doc.go @@ -0,0 +1,4 @@ +/* +Package centrifuge is the root package for go-centrifuge. Currently its empty, but this file enables indexing the package in godoc.org. +*/ +package centrifuge From 1740a40df00e850dbc0957f17b0a333bff78bd13 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Mon, 28 Jan 2019 17:11:21 +0100 Subject: [PATCH 166/220] identity: added execute method (#698) * added initial code for new identity * initial identity interfaces * added GetKey and AddKey to identity * formmatting logs * added new anchor contract * execute method added * added first test for execute method * more tests added for execute method * formatting * formatting --- anchors/anchor_contract.go | 616 +++++++++++++++++++++++ identity/did/bootstrapper.go | 4 + identity/did/execute_integration_test.go | 134 +++++ identity/did/identity.go | 50 ++ 4 files changed, 804 insertions(+) create mode 100644 anchors/anchor_contract.go create mode 100644 identity/did/execute_integration_test.go diff --git a/anchors/anchor_contract.go b/anchors/anchor_contract.go new file mode 100644 index 000000000..5757e12f5 --- /dev/null +++ b/anchors/anchor_contract.go @@ -0,0 +1,616 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package anchors + +import ( + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// AnchorContractABI is the input ABI used to generate the binding from. +const AnchorContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"commits\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xc7c4a615\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preCommits\",\"outputs\":[{\"name\":\"signingRoot\",\"type\":\"bytes32\"},{\"name\":\"identity\",\"type\":\"address\"},{\"name\":\"expirationBlock\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xd04cc3da\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\",\"signature\":\"0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\",\"signature\":\"0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_signingRoot\",\"type\":\"bytes32\"},{\"name\":\"_expirationBlock\",\"type\":\"uint256\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\",\"signature\":\"0xdb004f37\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_documentRoot\",\"type\":\"bytes32\"},{\"name\":\"_documentProofs\",\"type\":\"bytes32[]\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\",\"signature\":\"0x58522947\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x32bf361b\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xb5c7d034\"}]" + +// AnchorContract is an auto generated Go binding around an Ethereum contract. +type AnchorContract struct { + AnchorContractCaller // Read-only binding to the contract + AnchorContractTransactor // Write-only binding to the contract + AnchorContractFilterer // Log filterer for contract events +} + +// AnchorContractCaller is an auto generated read-only Go binding around an Ethereum contract. +type AnchorContractCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AnchorContractTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AnchorContractTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AnchorContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AnchorContractFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AnchorContractSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AnchorContractSession struct { + Contract *AnchorContract // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AnchorContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AnchorContractCallerSession struct { + Contract *AnchorContractCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AnchorContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AnchorContractTransactorSession struct { + Contract *AnchorContractTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AnchorContractRaw is an auto generated low-level Go binding around an Ethereum contract. +type AnchorContractRaw struct { + Contract *AnchorContract // Generic contract binding to access the raw methods on +} + +// AnchorContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AnchorContractCallerRaw struct { + Contract *AnchorContractCaller // Generic read-only contract binding to access the raw methods on +} + +// AnchorContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AnchorContractTransactorRaw struct { + Contract *AnchorContractTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAnchorContract creates a new instance of AnchorContract, bound to a specific deployed contract. +func NewAnchorContract(address common.Address, backend bind.ContractBackend) (*AnchorContract, error) { + contract, err := bindAnchorContract(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AnchorContract{AnchorContractCaller: AnchorContractCaller{contract: contract}, AnchorContractTransactor: AnchorContractTransactor{contract: contract}, AnchorContractFilterer: AnchorContractFilterer{contract: contract}}, nil +} + +// NewAnchorContractCaller creates a new read-only instance of AnchorContract, bound to a specific deployed contract. +func NewAnchorContractCaller(address common.Address, caller bind.ContractCaller) (*AnchorContractCaller, error) { + contract, err := bindAnchorContract(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AnchorContractCaller{contract: contract}, nil +} + +// NewAnchorContractTransactor creates a new write-only instance of AnchorContract, bound to a specific deployed contract. +func NewAnchorContractTransactor(address common.Address, transactor bind.ContractTransactor) (*AnchorContractTransactor, error) { + contract, err := bindAnchorContract(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AnchorContractTransactor{contract: contract}, nil +} + +// NewAnchorContractFilterer creates a new log filterer instance of AnchorContract, bound to a specific deployed contract. +func NewAnchorContractFilterer(address common.Address, filterer bind.ContractFilterer) (*AnchorContractFilterer, error) { + contract, err := bindAnchorContract(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AnchorContractFilterer{contract: contract}, nil +} + +// bindAnchorContract binds a generic wrapper to an already deployed contract. +func bindAnchorContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(AnchorContractABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AnchorContract *AnchorContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _AnchorContract.Contract.AnchorContractCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AnchorContract *AnchorContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AnchorContract.Contract.AnchorContractTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AnchorContract *AnchorContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AnchorContract.Contract.AnchorContractTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AnchorContract *AnchorContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { + return _AnchorContract.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AnchorContract *AnchorContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AnchorContract.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AnchorContract *AnchorContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AnchorContract.Contract.contract.Transact(opts, method, params...) +} + +// Commits is a free data retrieval call binding the contract method 0xc7c4a615. +// +// Solidity: function commits( uint256) constant returns(bytes32) +func (_AnchorContract *AnchorContractCaller) Commits(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { + var ( + ret0 = new([32]byte) + ) + out := ret0 + err := _AnchorContract.contract.Call(opts, out, "commits", arg0) + return *ret0, err +} + +// Commits is a free data retrieval call binding the contract method 0xc7c4a615. +// +// Solidity: function commits( uint256) constant returns(bytes32) +func (_AnchorContract *AnchorContractSession) Commits(arg0 *big.Int) ([32]byte, error) { + return _AnchorContract.Contract.Commits(&_AnchorContract.CallOpts, arg0) +} + +// Commits is a free data retrieval call binding the contract method 0xc7c4a615. +// +// Solidity: function commits( uint256) constant returns(bytes32) +func (_AnchorContract *AnchorContractCallerSession) Commits(arg0 *big.Int) ([32]byte, error) { + return _AnchorContract.Contract.Commits(&_AnchorContract.CallOpts, arg0) +} + +// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. +// +// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) +func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, _anchorId *big.Int) (struct { + AnchorId *big.Int + DocumentRoot [32]byte +}, error) { + ret := new(struct { + AnchorId *big.Int + DocumentRoot [32]byte + }) + out := ret + err := _AnchorContract.contract.Call(opts, out, "getAnchorById", _anchorId) + return *ret, err +} + +// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. +// +// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) +func (_AnchorContract *AnchorContractSession) GetAnchorById(_anchorId *big.Int) (struct { + AnchorId *big.Int + DocumentRoot [32]byte +}, error) { + return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, _anchorId) +} + +// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. +// +// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) +func (_AnchorContract *AnchorContractCallerSession) GetAnchorById(_anchorId *big.Int) (struct { + AnchorId *big.Int + DocumentRoot [32]byte +}, error) { + return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, _anchorId) +} + +// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. +// +// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) +func (_AnchorContract *AnchorContractCaller) HasValidPreCommit(opts *bind.CallOpts, _anchorId *big.Int) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _AnchorContract.contract.Call(opts, out, "hasValidPreCommit", _anchorId) + return *ret0, err +} + +// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. +// +// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) +func (_AnchorContract *AnchorContractSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { + return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, _anchorId) +} + +// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. +// +// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) +func (_AnchorContract *AnchorContractCallerSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { + return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, _anchorId) +} + +// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. +// +// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) +func (_AnchorContract *AnchorContractCaller) PreCommits(opts *bind.CallOpts, arg0 *big.Int) (struct { + SigningRoot [32]byte + Identity common.Address + ExpirationBlock uint32 +}, error) { + ret := new(struct { + SigningRoot [32]byte + Identity common.Address + ExpirationBlock uint32 + }) + out := ret + err := _AnchorContract.contract.Call(opts, out, "preCommits", arg0) + return *ret, err +} + +// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. +// +// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) +func (_AnchorContract *AnchorContractSession) PreCommits(arg0 *big.Int) (struct { + SigningRoot [32]byte + Identity common.Address + ExpirationBlock uint32 +}, error) { + return _AnchorContract.Contract.PreCommits(&_AnchorContract.CallOpts, arg0) +} + +// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. +// +// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) +func (_AnchorContract *AnchorContractCallerSession) PreCommits(arg0 *big.Int) (struct { + SigningRoot [32]byte + Identity common.Address + ExpirationBlock uint32 +}, error) { + return _AnchorContract.Contract.PreCommits(&_AnchorContract.CallOpts, arg0) +} + +// Commit is a paid mutator transaction binding the contract method 0x58522947. +// +// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() +func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, _anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.contract.Transact(opts, "commit", _anchorId, _documentRoot, _documentProofs) +} + +// Commit is a paid mutator transaction binding the contract method 0x58522947. +// +// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() +func (_AnchorContract *AnchorContractSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, _anchorId, _documentRoot, _documentProofs) +} + +// Commit is a paid mutator transaction binding the contract method 0x58522947. +// +// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() +func (_AnchorContract *AnchorContractTransactorSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, _anchorId, _documentRoot, _documentProofs) +} + +// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// +// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() +func (_AnchorContract *AnchorContractTransactor) PreCommit(opts *bind.TransactOpts, _anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { + return _AnchorContract.contract.Transact(opts, "preCommit", _anchorId, _signingRoot, _expirationBlock) +} + +// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// +// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() +func (_AnchorContract *AnchorContractSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { + return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, _anchorId, _signingRoot, _expirationBlock) +} + +// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// +// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() +func (_AnchorContract *AnchorContractTransactorSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { + return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, _anchorId, _signingRoot, _expirationBlock) +} + +// AnchorContractAnchorCommittedIterator is returned from FilterAnchorCommitted and is used to iterate over the raw logs and unpacked data for AnchorCommitted events raised by the AnchorContract contract. +type AnchorContractAnchorCommittedIterator struct { + Event *AnchorContractAnchorCommitted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AnchorContractAnchorCommittedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AnchorContractAnchorCommitted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AnchorContractAnchorCommitted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AnchorContractAnchorCommittedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AnchorContractAnchorCommittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AnchorContractAnchorCommitted represents a AnchorCommitted event raised by the AnchorContract contract. +type AnchorContractAnchorCommitted struct { + From common.Address + AnchorId *big.Int + DocumentRoot [32]byte + BlockHeight uint32 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterAnchorCommitted is a free log retrieval operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. +// +// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) +func (_AnchorContract *AnchorContractFilterer) FilterAnchorCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorCommittedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var anchorIdRule []interface{} + for _, anchorIdItem := range anchorId { + anchorIdRule = append(anchorIdRule, anchorIdItem) + } + + logs, sub, err := _AnchorContract.contract.FilterLogs(opts, "AnchorCommitted", fromRule, anchorIdRule) + if err != nil { + return nil, err + } + return &AnchorContractAnchorCommittedIterator{contract: _AnchorContract.contract, event: "AnchorCommitted", logs: logs, sub: sub}, nil +} + +// WatchAnchorCommitted is a free log subscription operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. +// +// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) +func (_AnchorContract *AnchorContractFilterer) WatchAnchorCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var anchorIdRule []interface{} + for _, anchorIdItem := range anchorId { + anchorIdRule = append(anchorIdRule, anchorIdItem) + } + + logs, sub, err := _AnchorContract.contract.WatchLogs(opts, "AnchorCommitted", fromRule, anchorIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AnchorContractAnchorCommitted) + if err := _AnchorContract.contract.UnpackLog(event, "AnchorCommitted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// AnchorContractAnchorPreCommittedIterator is returned from FilterAnchorPreCommitted and is used to iterate over the raw logs and unpacked data for AnchorPreCommitted events raised by the AnchorContract contract. +type AnchorContractAnchorPreCommittedIterator struct { + Event *AnchorContractAnchorPreCommitted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AnchorContractAnchorPreCommittedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AnchorContractAnchorPreCommitted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AnchorContractAnchorPreCommitted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AnchorContractAnchorPreCommittedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AnchorContractAnchorPreCommittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AnchorContractAnchorPreCommitted represents a AnchorPreCommitted event raised by the AnchorContract contract. +type AnchorContractAnchorPreCommitted struct { + From common.Address + AnchorId *big.Int + BlockHeight uint32 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterAnchorPreCommitted is a free log retrieval operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. +// +// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) +func (_AnchorContract *AnchorContractFilterer) FilterAnchorPreCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorPreCommittedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var anchorIdRule []interface{} + for _, anchorIdItem := range anchorId { + anchorIdRule = append(anchorIdRule, anchorIdItem) + } + + logs, sub, err := _AnchorContract.contract.FilterLogs(opts, "AnchorPreCommitted", fromRule, anchorIdRule) + if err != nil { + return nil, err + } + return &AnchorContractAnchorPreCommittedIterator{contract: _AnchorContract.contract, event: "AnchorPreCommitted", logs: logs, sub: sub}, nil +} + +// WatchAnchorPreCommitted is a free log subscription operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. +// +// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) +func (_AnchorContract *AnchorContractFilterer) WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorPreCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var anchorIdRule []interface{} + for _, anchorIdItem := range anchorId { + anchorIdRule = append(anchorIdRule, anchorIdItem) + } + + logs, sub, err := _AnchorContract.contract.WatchLogs(opts, "AnchorPreCommitted", fromRule, anchorIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AnchorContractAnchorPreCommitted) + if err := _AnchorContract.contract.UnpackLog(event, "AnchorPreCommitted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index 24437e8e1..5af96eef1 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -63,6 +63,10 @@ func getFactoryAddress() common.Address { } +func getAnchorAddress() common.Address { + return common.HexToAddress(smartContractAddresses.AnchorRepositoryAddr) +} + // Note: this block will be removed after the identity migration is done // currently we are using two versions of centrifuge contracts to not break the compatiblitiy // --------------------------------------------------------------------------------------------------------------------- diff --git a/identity/did/execute_integration_test.go b/identity/did/execute_integration_test.go new file mode 100644 index 000000000..222c469d7 --- /dev/null +++ b/identity/did/execute_integration_test.go @@ -0,0 +1,134 @@ +// +build integration + +/* + +The identity contract has a method called execute which forwards +a call to another contract. In Ethereum it is a useful pattern especially +related to identity smart contracts. + + +The correct behaviour currently is tested by calling the anchorRepository +commit method. It could be any other contract or method as well to simple test the +correct implementation. + +*/ + +package did + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" +) + +func TestExecute_successful(t *testing.T) { + idSrv := ctx[BootstrappedDID].(Identity) + did := deployIdentityContract(t) + anchorAddress := getAnchorAddress() + + // init params + testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + rootHash := utils.RandomSlice(32) + testRootHash, _ := anchors.ToDocumentRoot(rootHash) + proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} + + watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + assert.Nil(t, err, "Execute method calls should be successful") + + txStatus := <-watchTrans + assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transaction should be successful") + + checkAnchor(t, testAnchorId, rootHash) + +} + +func TestExecute_fail_falseMethodName(t *testing.T) { + idSrv := ctx[BootstrappedDID].(Identity) + did := deployIdentityContract(t) + anchorAddress := getAnchorAddress() + + testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + rootHash := utils.RandomSlice(32) + testRootHash, _ := anchors.ToDocumentRoot(rootHash) + + proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} + + watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) + assert.Error(t, err, "should throw an error because method is not existing in abi") + assert.Nil(t, watchTrans, "no channel should be returned") +} + +func TestExecute_fail_MissingParam(t *testing.T) { + idSrv := ctx[BootstrappedDID].(Identity) + did := deployIdentityContract(t) + anchorAddress := getAnchorAddress() + + testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + rootHash := utils.RandomSlice(32) + testRootHash, _ := anchors.ToDocumentRoot(rootHash) + + watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) + assert.Error(t, err, "should throw an error because method is not existing in abi") + assert.Nil(t, watchTrans, "no channel should be returned") +} + +func checkAnchor(t *testing.T, anchorId anchors.AnchorID, expectedRootHash []byte) { + anchorAddress := getAnchorAddress() + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + // check if anchor has been added + opts, _ := client.GetGethCallOpts(false) + anchorContract := bindAnchorContract(t, anchorAddress) + result, err := anchorContract.GetAnchorById(opts, anchorId.BigInt()) + assert.Nil(t, err, "get anchor should be successful") + assert.Equal(t, expectedRootHash[:], result.DocumentRoot[:], "committed anchor should be the same") +} + +// Checks the standard behaviour of the anchor contract +func TestAnchorWithoutExecute_successful(t *testing.T) { + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + anchorAddress := getAnchorAddress() + anchorContract := bindAnchorContract(t, anchorAddress) + + testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + rootHash := utils.RandomSlice(32) + testRootHash, _ := anchors.ToDocumentRoot(rootHash) + + //commit without execute method + txStatus := commitAnchorWithoutExecute(t, anchorContract, testAnchorId, testRootHash) + assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transaction should be successful") + + opts, _ := client.GetGethCallOpts(false) + result, err := anchorContract.GetAnchorById(opts, testAnchorId.BigInt()) + assert.Nil(t, err, "get anchor should be successful") + assert.Equal(t, rootHash[:], result.DocumentRoot[:], "committed anchor should be the same") + +} + +// Checks the standard behaviour of the anchor contract +func commitAnchorWithoutExecute(t *testing.T, anchorContract *anchors.AnchorContract, anchorId anchors.AnchorID, rootHash anchors.DocumentRoot) *ethereum.WatchTransaction { + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} + + opts, err := client.GetTxOpts(cfg.GetEthereumDefaultAccountName()) + tx, err := client.SubmitTransactionWithRetries(anchorContract.Commit, opts, anchorId.BigInt(), rootHash, proofs) + + assert.Nil(t, err, "submit transaction should be successful") + + watchTrans := make(chan *ethereum.WatchTransaction) + go waitForTransaction(client, tx.Hash(), watchTrans) + return <-watchTrans +} + +func bindAnchorContract(t *testing.T, address common.Address) *anchors.AnchorContract { + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + anchorContract, err := anchors.NewAnchorContract(address, client.GetEthClient()) + assert.Nil(t, err, "bind anchor contract should not throw an error") + + return anchorContract +} diff --git a/identity/did/identity.go b/identity/did/identity.go index 05b7d7cde..ae2b03fb8 100644 --- a/identity/did/identity.go +++ b/identity/did/identity.go @@ -3,8 +3,11 @@ package did import ( "context" "math/big" + "strings" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" @@ -34,8 +37,15 @@ func NewDIDFromString(address string) DID { type Identity interface { // AddKey adds a key to identity contract AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, error) + // GetKey return a key from the identity contract GetKey(did *DID, key [32]byte) (*KeyResponse, error) + + // RawExecute calls the execute method on the identity contract + RawExecute(did *DID, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) + + // Execute creates the abi encoding an calls the execute method on the identity contract + Execute(did *DID, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) } type contract interface { @@ -49,6 +59,8 @@ type contract interface { // transactions AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) + + Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) } type identity struct { @@ -152,3 +164,41 @@ func (i identity) GetKey(did *DID, key [32]byte) (*KeyResponse, error) { return &KeyResponse{result.Key, result.Purposes, result.RevokedAt}, nil } + +func (i identity) RawExecute(did *DID, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { + contract, opts, err := i.prepareTransaction(*did) + if err != nil { + return nil, err + } + + // default: no ether should be send + value := big.NewInt(0) + + tx, err := i.client.SubmitTransactionWithRetries(contract.Execute, opts, to, value, data) + if err != nil { + log.Infof("could not call execute method on identity contract: %v[txHash: %s] toAddress: %s : %v", tx.Hash(), to.String(), err) + return nil, errors.New("could not execute to identity contract: %v", err) + } + logTxHash(tx) + + txStatus := make(chan *ethereum.WatchTransaction) + // TODO will be replaced with transaction Status task + go waitForTransaction(i.client, tx.Hash(), txStatus) + + return txStatus, nil + +} + +func (i identity) Execute(did *DID, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { + abi, err := abi.JSON(strings.NewReader(contractAbi)) + if err != nil { + return nil, err + } + + // Pack encodes the parameters and additionally checks if the method and arguments are defined correctly + data, err := abi.Pack(methodName, args...) + if err != nil { + return nil, err + } + return i.RawExecute(did, to, data) +} From f02b8dffc4cc09dbc1188e4dff8fb724dbb68e84 Mon Sep 17 00:00:00 2001 From: Charly Date: Tue, 29 Jan 2019 14:35:10 +0100 Subject: [PATCH 167/220] Extend client api to support AccessTokens (#697) * accesstoken protobufs on client api * protos/gobindings, renamed document dir --- api/service.go | 2 +- documents/error.go | 2 +- documents/handler.go | 2 +- documents/handler_test.go | 2 +- documents/invoice/bootstrapper_test.go | 2 +- .../{documents => document}/service.proto | 14 ++ .../go/{documents => document}/service.pb.go | 205 +++++++++++++----- .../{documents => document}/service.pb.gw.go | 2 +- protobufs/gen/go/invoice/service.pb.go | 166 +++++++------- protobufs/gen/go/purchaseorder/service.pb.go | 169 ++++++++------- protobufs/gen/swagger.json | 1 - .../service.swagger.json | 2 +- .../gen/swagger/invoice/service.swagger.json | 31 ++- .../purchaseorder/service.swagger.json | 29 +++ protobufs/invoice/service.proto | 6 +- protobufs/purchaseorder/service.proto | 2 + 16 files changed, 420 insertions(+), 217 deletions(-) rename protobufs/{documents => document}/service.proto (81%) rename protobufs/gen/go/{documents => document}/service.pb.go (62%) rename protobufs/gen/go/{documents => document}/service.pb.gw.go (99%) delete mode 100644 protobufs/gen/swagger.json rename protobufs/gen/swagger/{documents => document}/service.swagger.json (99%) diff --git a/api/service.go b/api/service.go index 1ebda4efb..dd92fde56 100644 --- a/api/service.go +++ b/api/service.go @@ -12,7 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/health" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" diff --git a/documents/error.go b/documents/error.go index 6b5f8f244..48524876d 100644 --- a/documents/error.go +++ b/documents/error.go @@ -12,7 +12,7 @@ const ( ErrDocumentConfigAccountID = errors.Error("error with accountID operations") // ErrDocumentBootstrap must be used for errors related to documents package bootstrapping - ErrDocumentBootstrap = errors.Error("error when bootstrapping document package") + ErrDocumentBootstrap = errors.Error("error when bootstrapping documents package") // ErrDocumentIdentifier must be used for errors caused by document identifier problems ErrDocumentIdentifier = errors.Error("document identifier error") diff --git a/documents/handler.go b/documents/handler.go index 2565458a2..5811cc383 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -5,7 +5,7 @@ import ( "github.com/centrifuge/go-centrifuge/code" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/documents/handler_test.go b/documents/handler_test.go index 2a2f6a4c6..79e6612d0 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/documents" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" diff --git a/documents/invoice/bootstrapper_test.go b/documents/invoice/bootstrapper_test.go index 0719bb9c5..dd251e6a5 100644 --- a/documents/invoice/bootstrapper_test.go +++ b/documents/invoice/bootstrapper_test.go @@ -19,7 +19,7 @@ func TestBootstrapper_registerInvoiceService(t *testing.T) { // ////coreDocument embeds a invoice //coreDocument := testingutils.GenerateCoreDocument() - //registry := documents.GetRegistryInstance() + //registry := document.GetRegistryInstance() // //documentType, err := cd.GetTypeUrl(coreDocument) //assert.Nil(t, err, "should not throw an error because document contains a type") diff --git a/protobufs/documents/service.proto b/protobufs/document/service.proto similarity index 81% rename from protobufs/documents/service.proto rename to protobufs/document/service.proto index 809ba5905..aecf93828 100644 --- a/protobufs/documents/service.proto +++ b/protobufs/document/service.proto @@ -33,6 +33,20 @@ service DocumentService { } } +message UpdateAccessTokenPayload { + // The document which should contain the access token referenced below + string delegating_document_identifier = 1; + // The access token to be appended to the indicated document above + AccessTokenParams access_token_params = 2; +} + +message AccessTokenParams { + // The identity being granted access to the document + string grantee = 4; + // Original identifier of the document + string document_identifier = 2; +} + message CreateDocumentProofRequest { string identifier = 1; string type = 2; diff --git a/protobufs/gen/go/documents/service.pb.go b/protobufs/gen/go/document/service.pb.go similarity index 62% rename from protobufs/gen/go/documents/service.pb.go rename to protobufs/gen/go/document/service.pb.go index b57887f5f..2795eea94 100644 --- a/protobufs/gen/go/documents/service.pb.go +++ b/protobufs/gen/go/document/service.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: documents/service.proto +// source: document/service.proto package documentpb @@ -26,6 +26,102 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type UpdateAccessTokenPayload struct { + // The document which should contain the access token referenced below + DelegatingDocumentIdentifier string `protobuf:"bytes,1,opt,name=delegating_document_identifier,json=delegatingDocumentIdentifier,proto3" json:"delegating_document_identifier,omitempty"` + // The access token to be appended to the indicated document above + AccessTokenParams *AccessTokenParams `protobuf:"bytes,2,opt,name=access_token_params,json=accessTokenParams,proto3" json:"access_token_params,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateAccessTokenPayload) Reset() { *m = UpdateAccessTokenPayload{} } +func (m *UpdateAccessTokenPayload) String() string { return proto.CompactTextString(m) } +func (*UpdateAccessTokenPayload) ProtoMessage() {} +func (*UpdateAccessTokenPayload) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6db8efe3c4a04f30, []int{0} +} +func (m *UpdateAccessTokenPayload) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateAccessTokenPayload.Unmarshal(m, b) +} +func (m *UpdateAccessTokenPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateAccessTokenPayload.Marshal(b, m, deterministic) +} +func (dst *UpdateAccessTokenPayload) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateAccessTokenPayload.Merge(dst, src) +} +func (m *UpdateAccessTokenPayload) XXX_Size() int { + return xxx_messageInfo_UpdateAccessTokenPayload.Size(m) +} +func (m *UpdateAccessTokenPayload) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateAccessTokenPayload.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateAccessTokenPayload proto.InternalMessageInfo + +func (m *UpdateAccessTokenPayload) GetDelegatingDocumentIdentifier() string { + if m != nil { + return m.DelegatingDocumentIdentifier + } + return "" +} + +func (m *UpdateAccessTokenPayload) GetAccessTokenParams() *AccessTokenParams { + if m != nil { + return m.AccessTokenParams + } + return nil +} + +type AccessTokenParams struct { + // The identity being granted access to the document + Grantee string `protobuf:"bytes,4,opt,name=grantee,proto3" json:"grantee,omitempty"` + // Original identifier of the document + DocumentIdentifier string `protobuf:"bytes,2,opt,name=document_identifier,json=documentIdentifier,proto3" json:"document_identifier,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AccessTokenParams) Reset() { *m = AccessTokenParams{} } +func (m *AccessTokenParams) String() string { return proto.CompactTextString(m) } +func (*AccessTokenParams) ProtoMessage() {} +func (*AccessTokenParams) Descriptor() ([]byte, []int) { + return fileDescriptor_service_6db8efe3c4a04f30, []int{1} +} +func (m *AccessTokenParams) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AccessTokenParams.Unmarshal(m, b) +} +func (m *AccessTokenParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AccessTokenParams.Marshal(b, m, deterministic) +} +func (dst *AccessTokenParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessTokenParams.Merge(dst, src) +} +func (m *AccessTokenParams) XXX_Size() int { + return xxx_messageInfo_AccessTokenParams.Size(m) +} +func (m *AccessTokenParams) XXX_DiscardUnknown() { + xxx_messageInfo_AccessTokenParams.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessTokenParams proto.InternalMessageInfo + +func (m *AccessTokenParams) GetGrantee() string { + if m != nil { + return m.Grantee + } + return "" +} + +func (m *AccessTokenParams) GetDocumentIdentifier() string { + if m != nil { + return m.DocumentIdentifier + } + return "" +} + type CreateDocumentProofRequest struct { Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` @@ -39,7 +135,7 @@ func (m *CreateDocumentProofRequest) Reset() { *m = CreateDocumentProofR func (m *CreateDocumentProofRequest) String() string { return proto.CompactTextString(m) } func (*CreateDocumentProofRequest) ProtoMessage() {} func (*CreateDocumentProofRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_69e16bff75411dd5, []int{0} + return fileDescriptor_service_6db8efe3c4a04f30, []int{2} } func (m *CreateDocumentProofRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateDocumentProofRequest.Unmarshal(m, b) @@ -94,7 +190,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_69e16bff75411dd5, []int{1} + return fileDescriptor_service_6db8efe3c4a04f30, []int{3} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -147,7 +243,7 @@ func (m *DocumentProof) Reset() { *m = DocumentProof{} } func (m *DocumentProof) String() string { return proto.CompactTextString(m) } func (*DocumentProof) ProtoMessage() {} func (*DocumentProof) Descriptor() ([]byte, []int) { - return fileDescriptor_service_69e16bff75411dd5, []int{2} + return fileDescriptor_service_6db8efe3c4a04f30, []int{4} } func (m *DocumentProof) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DocumentProof.Unmarshal(m, b) @@ -197,7 +293,7 @@ func (m *Proof) Reset() { *m = Proof{} } func (m *Proof) String() string { return proto.CompactTextString(m) } func (*Proof) ProtoMessage() {} func (*Proof) Descriptor() ([]byte, []int) { - return fileDescriptor_service_69e16bff75411dd5, []int{3} + return fileDescriptor_service_6db8efe3c4a04f30, []int{5} } func (m *Proof) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Proof.Unmarshal(m, b) @@ -266,7 +362,7 @@ func (m *CreateDocumentProofForVersionRequest) Reset() { *m = CreateDocu func (m *CreateDocumentProofForVersionRequest) String() string { return proto.CompactTextString(m) } func (*CreateDocumentProofForVersionRequest) ProtoMessage() {} func (*CreateDocumentProofForVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_69e16bff75411dd5, []int{4} + return fileDescriptor_service_6db8efe3c4a04f30, []int{6} } func (m *CreateDocumentProofForVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateDocumentProofForVersionRequest.Unmarshal(m, b) @@ -315,6 +411,8 @@ func (m *CreateDocumentProofForVersionRequest) GetFields() []string { } func init() { + proto.RegisterType((*UpdateAccessTokenPayload)(nil), "document.UpdateAccessTokenPayload") + proto.RegisterType((*AccessTokenParams)(nil), "document.AccessTokenParams") proto.RegisterType((*CreateDocumentProofRequest)(nil), "document.CreateDocumentProofRequest") proto.RegisterType((*ResponseHeader)(nil), "document.ResponseHeader") proto.RegisterType((*DocumentProof)(nil), "document.DocumentProof") @@ -424,48 +522,55 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "documents/service.proto", -} - -func init() { proto.RegisterFile("documents/service.proto", fileDescriptor_service_69e16bff75411dd5) } - -var fileDescriptor_service_69e16bff75411dd5 = []byte{ - // 591 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4f, 0x6f, 0xd3, 0x30, - 0x14, 0x57, 0xda, 0xb5, 0xac, 0x6e, 0xc7, 0x24, 0x83, 0x58, 0x14, 0x6d, 0x60, 0xc2, 0x04, 0xd5, - 0xa0, 0x0d, 0x2a, 0x37, 0x6e, 0x1b, 0x13, 0x5a, 0x6f, 0x55, 0x11, 0x20, 0x71, 0xa9, 0xd2, 0xe4, - 0x25, 0x35, 0xca, 0xe2, 0x60, 0xbb, 0x45, 0xd5, 0xc4, 0x01, 0x0e, 0x5c, 0xe0, 0x34, 0xbe, 0x00, - 0xdf, 0x89, 0x0b, 0x1f, 0x80, 0x4f, 0xc1, 0x09, 0xc5, 0x76, 0x9a, 0x56, 0x5b, 0xc7, 0x61, 0xa7, - 0xbc, 0x7f, 0x79, 0xef, 0xf7, 0xfb, 0x3d, 0xdb, 0x68, 0x27, 0x64, 0xc1, 0xf4, 0x14, 0x52, 0x29, - 0x3c, 0x01, 0x7c, 0x46, 0x03, 0xe8, 0x66, 0x9c, 0x49, 0x86, 0x37, 0x8b, 0x84, 0xb3, 0x1b, 0x33, - 0x16, 0x27, 0xe0, 0xf9, 0x19, 0xf5, 0xfc, 0x34, 0x65, 0xd2, 0x97, 0x94, 0xa5, 0x42, 0xd7, 0x39, - 0x8f, 0x32, 0x0e, 0x01, 0x15, 0xd0, 0xc9, 0x38, 0x63, 0x91, 0xf0, 0xca, 0x8f, 0x64, 0xda, 0x31, - 0x85, 0x4f, 0xd4, 0x27, 0xe8, 0xc4, 0x90, 0x76, 0xc4, 0x47, 0x3f, 0x8e, 0x81, 0x7b, 0x2c, 0x53, - 0xad, 0x2e, 0xb6, 0x75, 0x27, 0xc8, 0x79, 0xc1, 0xc1, 0x97, 0x70, 0x6c, 0x60, 0x0c, 0xf2, 0x56, - 0x43, 0xf8, 0x30, 0x05, 0x21, 0xf1, 0x5d, 0x84, 0x68, 0x08, 0xa9, 0xa4, 0x11, 0x05, 0x6e, 0x5b, - 0xc4, 0x6a, 0x37, 0x86, 0x4b, 0x11, 0x8c, 0xd1, 0x86, 0x9c, 0x67, 0x60, 0x57, 0x54, 0x46, 0xd9, - 0xf8, 0x0e, 0xaa, 0x47, 0x14, 0x92, 0x50, 0xd8, 0x55, 0x52, 0x6d, 0x37, 0x86, 0xc6, 0x73, 0x23, - 0x74, 0x73, 0x08, 0x22, 0x63, 0xa9, 0x80, 0x13, 0xf0, 0x43, 0xe0, 0xf8, 0x1e, 0x6a, 0x16, 0xe4, - 0x47, 0x34, 0x2c, 0xda, 0x17, 0xa1, 0x7e, 0x88, 0xf7, 0x10, 0x9a, 0x01, 0x17, 0x94, 0xa5, 0x79, - 0x5e, 0x0f, 0x69, 0x98, 0x48, 0x3f, 0xc4, 0xb7, 0x51, 0x4d, 0x48, 0x5f, 0x82, 0x5d, 0x55, 0x19, - 0xed, 0xb8, 0x53, 0xb4, 0xb5, 0xc2, 0x05, 0x3f, 0x45, 0xf5, 0x89, 0x1a, 0xa8, 0x26, 0x34, 0x7b, - 0x76, 0xb7, 0x18, 0xd1, 0x5d, 0x05, 0x34, 0x34, 0x75, 0xb8, 0x87, 0x5a, 0x0a, 0xf4, 0x48, 0x8b, - 0x6c, 0x57, 0x48, 0xb5, 0xdd, 0xec, 0x6d, 0x97, 0xff, 0x69, 0x91, 0x9a, 0xaa, 0x48, 0xd9, 0xc2, - 0xfd, 0x6a, 0xa1, 0x9a, 0x9e, 0xe7, 0xa0, 0xcd, 0x8c, 0xb3, 0x0c, 0xb8, 0x9c, 0x1b, 0x4e, 0x0b, - 0x3f, 0x87, 0x3c, 0xf3, 0x93, 0x69, 0xa1, 0x98, 0x76, 0x72, 0x19, 0x85, 0x9f, 0x48, 0xc3, 0x43, - 0xd9, 0x79, 0x6c, 0xe2, 0x8b, 0x89, 0xbd, 0xa1, 0x63, 0xb9, 0x8d, 0x1f, 0xa0, 0x2d, 0xc1, 0xb8, - 0x84, 0x70, 0x94, 0xbb, 0x20, 0xec, 0x9a, 0x52, 0xb8, 0xa5, 0x83, 0x27, 0x2a, 0xe6, 0x7e, 0xb7, - 0xd0, 0xfe, 0x25, 0x2b, 0x7d, 0xc9, 0xf8, 0x1b, 0xad, 0xdc, 0x75, 0x96, 0x6b, 0xa3, 0x1b, 0x46, - 0x7f, 0x03, 0xb6, 0x70, 0x97, 0xd6, 0xbe, 0xb1, 0xbc, 0xf6, 0xde, 0xdf, 0x2a, 0xda, 0x2e, 0x80, - 0xbc, 0xd2, 0x27, 0x1f, 0xff, 0xb6, 0xd0, 0xad, 0x4b, 0x20, 0xe2, 0xfd, 0x52, 0xe1, 0xf5, 0x87, - 0xd2, 0xd9, 0x29, 0xab, 0x56, 0xf2, 0xee, 0x67, 0xeb, 0xfc, 0xf0, 0xad, 0xf3, 0x5a, 0xff, 0x2a, - 0x88, 0x4f, 0x12, 0x2a, 0x24, 0x61, 0x11, 0x31, 0x57, 0x87, 0xe8, 0x75, 0x92, 0x88, 0x71, 0x22, - 0x27, 0x40, 0x44, 0x06, 0x41, 0x4e, 0x35, 0x24, 0x1a, 0x6b, 0x5e, 0x9a, 0xc7, 0x8b, 0xf6, 0x24, - 0xa6, 0x33, 0x48, 0xc9, 0x78, 0x4e, 0xfa, 0xc7, 0x5f, 0x7e, 0xfd, 0xf9, 0x51, 0xb9, 0xef, 0xee, - 0x7a, 0x45, 0xd2, 0x3b, 0x2b, 0xa5, 0xfa, 0xa4, 0x2f, 0xe0, 0x73, 0xeb, 0x00, 0x7f, 0xab, 0xa0, - 0xbd, 0x2b, 0xd5, 0xc7, 0xdd, 0x2b, 0x49, 0x5e, 0x58, 0xd3, 0x7a, 0xba, 0x3f, 0xad, 0xf3, 0xc3, - 0xc4, 0x79, 0x7f, 0x6d, 0xba, 0x9a, 0xa5, 0xd9, 0xe3, 0x7f, 0x35, 0x78, 0xec, 0x3e, 0x5c, 0xa3, - 0xc1, 0x99, 0x69, 0x51, 0xaa, 0x71, 0x74, 0x80, 0x5a, 0x01, 0x3b, 0x5d, 0x10, 0x38, 0x6a, 0x99, - 0x13, 0x30, 0xc8, 0xdf, 0x9e, 0x81, 0xf5, 0x6e, 0x71, 0xd9, 0xb3, 0xf1, 0xb8, 0xae, 0x1e, 0xa4, - 0x67, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xf0, 0x43, 0xa0, 0x2a, 0x05, 0x00, 0x00, + Metadata: "document/service.proto", +} + +func init() { proto.RegisterFile("document/service.proto", fileDescriptor_service_6db8efe3c4a04f30) } + +var fileDescriptor_service_6db8efe3c4a04f30 = []byte{ + // 699 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x6e, 0x13, 0x49, + 0x10, 0xd6, 0xd8, 0xf9, 0x2d, 0x3b, 0x1b, 0xa5, 0xb3, 0xca, 0x8e, 0xbc, 0x49, 0xb6, 0x77, 0x36, + 0xda, 0xb5, 0xb2, 0xc4, 0x46, 0xe6, 0xc6, 0x2d, 0x21, 0x42, 0x89, 0xb8, 0x58, 0x86, 0x80, 0xc4, + 0x01, 0xab, 0x33, 0x53, 0x1e, 0x0f, 0x4c, 0xa6, 0x87, 0xee, 0xb6, 0x91, 0x15, 0x71, 0x80, 0x03, + 0x17, 0x38, 0x85, 0x17, 0xe0, 0x05, 0x78, 0x1a, 0x2e, 0x3c, 0x00, 0x4f, 0xc1, 0x09, 0x4d, 0x77, + 0x8f, 0xc7, 0xc6, 0x49, 0x38, 0xe4, 0x34, 0x5d, 0xd5, 0x5f, 0x57, 0x7f, 0xdf, 0x57, 0x3d, 0x05, + 0x1b, 0x01, 0xf7, 0x07, 0x67, 0x98, 0xa8, 0xa6, 0x44, 0x31, 0x8c, 0x7c, 0x6c, 0xa4, 0x82, 0x2b, + 0x4e, 0x96, 0xf2, 0x7c, 0x6d, 0x33, 0xe4, 0x3c, 0x8c, 0xb1, 0xc9, 0xd2, 0xa8, 0xc9, 0x92, 0x84, + 0x2b, 0xa6, 0x22, 0x9e, 0x48, 0x83, 0xab, 0xfd, 0x97, 0x0a, 0xf4, 0x23, 0x89, 0x7b, 0xa9, 0xe0, + 0xbc, 0x27, 0x9b, 0xc5, 0x47, 0x71, 0x13, 0x58, 0xe0, 0x2d, 0xfd, 0xf1, 0xf7, 0x42, 0x4c, 0xf6, + 0xe4, 0x2b, 0x16, 0x86, 0x28, 0x9a, 0x3c, 0xd5, 0xa5, 0x66, 0xcb, 0x7a, 0x9f, 0x1d, 0x70, 0x4f, + 0xd2, 0x80, 0x29, 0xdc, 0xf7, 0x7d, 0x94, 0xf2, 0x11, 0x7f, 0x81, 0x49, 0x9b, 0x8d, 0x62, 0xce, + 0x02, 0x72, 0x08, 0xdb, 0x01, 0xc6, 0x18, 0x32, 0x15, 0x25, 0x61, 0x37, 0x27, 0xda, 0x8d, 0x02, + 0x4c, 0x54, 0xd4, 0x8b, 0x50, 0xb8, 0x0e, 0x75, 0xea, 0xcb, 0x9d, 0xcd, 0x02, 0x75, 0x68, 0x41, + 0xc7, 0x63, 0x0c, 0x79, 0x00, 0xeb, 0x4c, 0xd7, 0xee, 0xaa, 0xac, 0x78, 0x37, 0x65, 0x82, 0x9d, + 0x49, 0xb7, 0x44, 0x9d, 0x7a, 0xa5, 0xf5, 0x67, 0x23, 0x2f, 0xdb, 0x98, 0x22, 0x90, 0x41, 0x3a, + 0x6b, 0xec, 0xe7, 0x94, 0xf7, 0x0c, 0xd6, 0x66, 0x70, 0xc4, 0x85, 0xc5, 0x50, 0xb0, 0x44, 0x21, + 0xba, 0x73, 0x9a, 0x50, 0x1e, 0x92, 0x26, 0xac, 0x5f, 0x46, 0xbb, 0xa4, 0x51, 0x24, 0x98, 0x21, + 0xeb, 0xf5, 0xa1, 0x76, 0x4f, 0x20, 0x53, 0x98, 0x0b, 0x69, 0x67, 0xd6, 0x76, 0xf0, 0xe5, 0x00, + 0xa5, 0x22, 0xdb, 0x00, 0x33, 0xe2, 0x27, 0x32, 0x84, 0xc0, 0x9c, 0x1a, 0xa5, 0x68, 0xeb, 0xeb, + 0x35, 0xd9, 0x80, 0x85, 0x5e, 0x84, 0x71, 0x20, 0xdd, 0x32, 0x2d, 0xd7, 0x97, 0x3b, 0x36, 0xf2, + 0x7a, 0xf0, 0x5b, 0x07, 0x65, 0xca, 0x13, 0x89, 0x47, 0xc8, 0x02, 0x14, 0xe4, 0x2f, 0xa8, 0x4c, + 0x90, 0xcd, 0xcb, 0x17, 0x24, 0xc9, 0x16, 0xc0, 0x10, 0x85, 0x8c, 0x78, 0x92, 0xed, 0x9b, 0x4b, + 0x96, 0x6d, 0xe6, 0x38, 0x20, 0xbf, 0xc3, 0xbc, 0x54, 0x4c, 0xa1, 0x5b, 0xd6, 0x3b, 0x26, 0xf0, + 0x06, 0xb0, 0x32, 0xa5, 0x85, 0xdc, 0x86, 0x85, 0xbe, 0xbe, 0x50, 0xdf, 0x50, 0x69, 0xb9, 0x45, + 0x0b, 0xa6, 0x09, 0x75, 0x2c, 0x8e, 0xb4, 0xa0, 0xaa, 0x49, 0x77, 0xcd, 0xa3, 0x73, 0x4b, 0xb4, + 0x5c, 0xaf, 0xb4, 0x56, 0x8b, 0x73, 0xc6, 0xa4, 0x8a, 0x06, 0xe9, 0xb5, 0xf4, 0xde, 0x39, 0x30, + 0x6f, 0xee, 0xab, 0xc1, 0x52, 0x2a, 0x78, 0x8a, 0x42, 0x8d, 0xac, 0xa6, 0x71, 0x9c, 0x51, 0x1e, + 0xb2, 0x78, 0x90, 0x3b, 0x66, 0x82, 0xcc, 0x46, 0xc9, 0x62, 0x65, 0x75, 0xe8, 0x75, 0x96, 0xeb, + 0x33, 0xd9, 0xb7, 0x0d, 0xd6, 0x6b, 0xf2, 0x0f, 0xac, 0x48, 0x2e, 0x14, 0x06, 0xdd, 0x2c, 0x44, + 0xe9, 0xce, 0x6b, 0x87, 0xab, 0x26, 0x79, 0xa4, 0x73, 0xde, 0x07, 0x07, 0x76, 0x2e, 0x69, 0xe9, + 0x7d, 0x2e, 0x1e, 0x1b, 0xe7, 0x6e, 0xd2, 0x5c, 0x17, 0x16, 0xad, 0xff, 0x96, 0x6c, 0x1e, 0x4e, + 0xb4, 0x7d, 0x6e, 0xb2, 0xed, 0xad, 0xef, 0x65, 0x58, 0xcd, 0x89, 0x3c, 0x34, 0x93, 0x80, 0x7c, + 0x75, 0x60, 0xfd, 0x12, 0x8a, 0x64, 0xa7, 0x70, 0xf8, 0xea, 0x47, 0x59, 0xfb, 0xa3, 0x40, 0x4d, + 0xed, 0x7b, 0x6f, 0x9c, 0x8b, 0xfd, 0x27, 0xb5, 0x13, 0x73, 0x54, 0x52, 0x46, 0xe3, 0x48, 0x2a, + 0xca, 0x7b, 0xd4, 0x8e, 0x12, 0x6a, 0xda, 0x49, 0x7b, 0x5c, 0x50, 0xd5, 0x47, 0x2a, 0x53, 0xf4, + 0x33, 0xa9, 0x01, 0x35, 0x5c, 0x33, 0x68, 0x96, 0xcf, 0xcb, 0xd3, 0x30, 0x1a, 0x62, 0x42, 0x4f, + 0x47, 0xf4, 0xf8, 0xf0, 0xed, 0x97, 0x6f, 0x1f, 0x4b, 0x7f, 0x7b, 0x9b, 0xcd, 0xf1, 0x58, 0x3b, + 0x2f, 0xac, 0x7a, 0x6d, 0x06, 0xd2, 0x5d, 0x67, 0x97, 0xbc, 0x2f, 0xc1, 0xd6, 0xb5, 0xee, 0x93, + 0xc6, 0xb5, 0x22, 0x67, 0xda, 0x74, 0xb5, 0xdc, 0x4f, 0xce, 0xc5, 0x7e, 0x5c, 0x7b, 0x7e, 0x63, + 0xb9, 0x46, 0xa5, 0xed, 0xe3, 0x2f, 0x3d, 0xf8, 0xdf, 0xfb, 0xf7, 0x0a, 0x0f, 0xce, 0x6d, 0x89, + 0xc2, 0x8d, 0x83, 0x5d, 0xa8, 0xfa, 0xfc, 0x6c, 0x2c, 0xe0, 0xa0, 0x6a, 0x5f, 0x40, 0x3b, 0x9b, + 0xc5, 0x6d, 0xe7, 0xe9, 0xf8, 0x67, 0x4f, 0x4f, 0x4f, 0x17, 0xf4, 0x80, 0xbe, 0xf3, 0x23, 0x00, + 0x00, 0xff, 0xff, 0x17, 0xaa, 0x39, 0x7f, 0x39, 0x06, 0x00, 0x00, } diff --git a/protobufs/gen/go/documents/service.pb.gw.go b/protobufs/gen/go/document/service.pb.gw.go similarity index 99% rename from protobufs/gen/go/documents/service.pb.gw.go rename to protobufs/gen/go/document/service.pb.gw.go index 837db838a..67016c66a 100644 --- a/protobufs/gen/go/documents/service.pb.gw.go +++ b/protobufs/gen/go/document/service.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: documents/service.proto +// source: document/service.proto /* Package documentpb is a reverse proxy. diff --git a/protobufs/gen/go/invoice/service.pb.go b/protobufs/gen/go/invoice/service.pb.go index faca5b352..1e5372d8b 100644 --- a/protobufs/gen/go/invoice/service.pb.go +++ b/protobufs/gen/go/invoice/service.pb.go @@ -6,6 +6,7 @@ package invoicepb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" +import document "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" import timestamp "github.com/golang/protobuf/ptypes/timestamp" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" @@ -37,7 +38,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{0} + return fileDescriptor_service_493cda4133eb71cc, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -76,7 +77,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{1} + return fileDescriptor_service_493cda4133eb71cc, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -122,7 +123,7 @@ func (m *InvoiceCreatePayload) Reset() { *m = InvoiceCreatePayload{} } func (m *InvoiceCreatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceCreatePayload) ProtoMessage() {} func (*InvoiceCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{2} + return fileDescriptor_service_493cda4133eb71cc, []int{2} } func (m *InvoiceCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceCreatePayload.Unmarshal(m, b) @@ -157,19 +158,20 @@ func (m *InvoiceCreatePayload) GetData() *InvoiceData { } type InvoiceUpdatePayload struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` - Data *InvoiceData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + Data *InvoiceData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + AccessTokenPayload *document.UpdateAccessTokenPayload `protobuf:"bytes,4,opt,name=access_token_payload,json=accessTokenPayload,proto3" json:"access_token_payload,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *InvoiceUpdatePayload) Reset() { *m = InvoiceUpdatePayload{} } func (m *InvoiceUpdatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceUpdatePayload) ProtoMessage() {} func (*InvoiceUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{3} + return fileDescriptor_service_493cda4133eb71cc, []int{3} } func (m *InvoiceUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceUpdatePayload.Unmarshal(m, b) @@ -210,6 +212,13 @@ func (m *InvoiceUpdatePayload) GetData() *InvoiceData { return nil } +func (m *InvoiceUpdatePayload) GetAccessTokenPayload() *document.UpdateAccessTokenPayload { + if m != nil { + return m.AccessTokenPayload + } + return nil +} + type InvoiceResponse struct { Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Data *InvoiceData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -222,7 +231,7 @@ func (m *InvoiceResponse) Reset() { *m = InvoiceResponse{} } func (m *InvoiceResponse) String() string { return proto.CompactTextString(m) } func (*InvoiceResponse) ProtoMessage() {} func (*InvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{4} + return fileDescriptor_service_493cda4133eb71cc, []int{4} } func (m *InvoiceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceResponse.Unmarshal(m, b) @@ -256,7 +265,7 @@ func (m *InvoiceResponse) GetData() *InvoiceData { return nil } -// ResponseHeader contains a set of common fields for most documents +// ResponseHeader contains a set of common fields for most document type ResponseHeader struct { DocumentId string `protobuf:"bytes,1,opt,name=document_id,json=documentId,proto3" json:"document_id,omitempty"` VersionId string `protobuf:"bytes,2,opt,name=version_id,json=versionId,proto3" json:"version_id,omitempty"` @@ -272,7 +281,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{5} + return fileDescriptor_service_493cda4133eb71cc, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -370,7 +379,7 @@ func (m *InvoiceData) Reset() { *m = InvoiceData{} } func (m *InvoiceData) String() string { return proto.CompactTextString(m) } func (*InvoiceData) ProtoMessage() {} func (*InvoiceData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_3d2a42d875b08717, []int{6} + return fileDescriptor_service_493cda4133eb71cc, []int{6} } func (m *InvoiceData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceData.Unmarshal(m, b) @@ -739,67 +748,70 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ Metadata: "invoice/service.proto", } -func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_3d2a42d875b08717) } - -var fileDescriptor_service_3d2a42d875b08717 = []byte{ - // 939 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0x1b, 0x45, - 0x1b, 0x96, 0x93, 0xd4, 0x3f, 0xaf, 0xed, 0xa4, 0x99, 0x3a, 0xcd, 0x66, 0xd5, 0x7e, 0xd9, 0xfa, - 0x2b, 0xc8, 0x94, 0xd6, 0x96, 0x82, 0x10, 0x02, 0x89, 0x83, 0x34, 0x95, 0x42, 0x0e, 0xa8, 0xa2, - 0x0d, 0x70, 0xd0, 0x13, 0x6b, 0xbc, 0xfb, 0xda, 0x1d, 0xc9, 0x3b, 0xb3, 0xcc, 0x8c, 0x43, 0xdc, - 0xaa, 0x27, 0x08, 0x71, 0x01, 0x81, 0x3b, 0xe1, 0x52, 0xb8, 0x05, 0xae, 0x81, 0x63, 0x34, 0x3f, - 0xeb, 0xdf, 0x28, 0x81, 0xa3, 0xd5, 0x3c, 0xef, 0xf3, 0xfe, 0x3c, 0xf3, 0xf3, 0x2c, 0xec, 0x31, - 0x7e, 0x29, 0x58, 0x82, 0x3d, 0x85, 0xf2, 0x92, 0x25, 0xd8, 0xcd, 0xa5, 0xd0, 0x82, 0x54, 0x3c, - 0x1c, 0x3e, 0x1a, 0x09, 0x31, 0x1a, 0x63, 0x8f, 0xe6, 0xac, 0x47, 0x39, 0x17, 0x9a, 0x6a, 0x26, - 0xb8, 0x72, 0xb4, 0xf0, 0xd0, 0x47, 0xed, 0x6a, 0x30, 0x19, 0xf6, 0x34, 0xcb, 0x50, 0x69, 0x9a, - 0xe5, 0x9e, 0xf0, 0xdc, 0x7e, 0x92, 0x17, 0x23, 0xe4, 0x2f, 0xd4, 0x4f, 0x74, 0x34, 0x42, 0xd9, - 0x13, 0xb9, 0x2d, 0xb1, 0x5e, 0xae, 0xfd, 0x1c, 0xe0, 0x14, 0x75, 0x8c, 0x3f, 0x4e, 0x50, 0x69, - 0xf2, 0x3f, 0x00, 0x96, 0x22, 0xd7, 0x6c, 0xc8, 0x50, 0x06, 0xa5, 0xa8, 0xd4, 0xa9, 0xc5, 0x0b, - 0x48, 0xfb, 0x5b, 0xd8, 0x3d, 0x45, 0xfd, 0x03, 0x4a, 0xc5, 0x04, 0xff, 0x97, 0x49, 0x24, 0x80, - 0xca, 0xa5, 0xcb, 0x08, 0x36, 0x6c, 0xb0, 0x58, 0xb6, 0x87, 0xd0, 0x3a, 0x73, 0xa2, 0x4f, 0x24, - 0x52, 0x8d, 0xe7, 0x74, 0x3a, 0x16, 0x34, 0x25, 0x4f, 0xa1, 0x99, 0x88, 0xf1, 0x98, 0x0e, 0x84, - 0xa4, 0x5a, 0x48, 0x15, 0x94, 0xa2, 0xcd, 0x4e, 0x2d, 0x5e, 0x06, 0x49, 0x07, 0xb6, 0x52, 0xaa, - 0xa9, 0x2d, 0x5a, 0x3f, 0x6a, 0x75, 0xfd, 0xfe, 0x75, 0x7d, 0xc9, 0x57, 0x54, 0xd3, 0xd8, 0x32, - 0xda, 0xbf, 0x96, 0x66, 0x8d, 0xbe, 0xcf, 0xd3, 0x85, 0x46, 0x77, 0x8d, 0xbe, 0x36, 0xc8, 0xc6, - 0x6d, 0x83, 0x6c, 0xde, 0x39, 0xc8, 0x18, 0x76, 0x3c, 0x18, 0xa3, 0xca, 0x05, 0x57, 0x48, 0x7a, - 0x50, 0x7e, 0x8b, 0x34, 0xf5, 0xed, 0xeb, 0x47, 0xfb, 0xb3, 0xf4, 0x82, 0xf2, 0x8d, 0x0d, 0xc7, - 0x9e, 0xf6, 0x1f, 0x64, 0xff, 0x51, 0x82, 0xed, 0xe5, 0x22, 0xe4, 0x10, 0xea, 0xa9, 0x48, 0x26, - 0x19, 0x72, 0xdd, 0x67, 0x69, 0xa1, 0xb8, 0x80, 0xce, 0x52, 0xf2, 0x18, 0xc0, 0x9f, 0x8e, 0x89, - 0xbb, 0xf3, 0xaa, 0x79, 0xe4, 0x2c, 0x25, 0x2d, 0xb8, 0xa7, 0x34, 0xd5, 0x68, 0xb5, 0xd6, 0x62, - 0xb7, 0x58, 0xdf, 0xa6, 0xad, 0x9b, 0xb6, 0xe9, 0x23, 0xd8, 0xd6, 0x92, 0x72, 0x45, 0x13, 0xed, - 0xcb, 0xdf, 0xb3, 0x45, 0x9a, 0x0b, 0xe8, 0x59, 0xda, 0xfe, 0xbb, 0x0c, 0xf5, 0x05, 0x2d, 0x26, - 0xcd, 0x4b, 0xec, 0x9b, 0x6e, 0x13, 0x15, 0x1c, 0xb8, 0x34, 0x8f, 0x5e, 0x58, 0x70, 0x91, 0xc6, - 0x27, 0xd9, 0x60, 0x76, 0x9c, 0x05, 0xed, 0xb5, 0x05, 0xcd, 0x06, 0x28, 0xe4, 0x29, 0xca, 0x3e, - 0xa7, 0x59, 0x21, 0x03, 0x1c, 0xf4, 0x9a, 0x66, 0x48, 0xfe, 0x0f, 0x4d, 0x4f, 0x50, 0x5a, 0x22, - 0xea, 0x60, 0xcb, 0x52, 0x1a, 0x0e, 0xbc, 0xb0, 0xd8, 0x42, 0x95, 0x84, 0xe9, 0xa9, 0xd7, 0xe1, - 0xab, 0x9c, 0x30, 0x3d, 0x35, 0xd3, 0x78, 0xc2, 0x3b, 0x96, 0x27, 0x22, 0xc5, 0xa0, 0xec, 0xa6, - 0x71, 0xe8, 0x1b, 0x07, 0x2e, 0xd0, 0x12, 0x31, 0xe1, 0x5a, 0x4e, 0x83, 0xca, 0x22, 0xed, 0xc4, - 0x81, 0x86, 0x26, 0x31, 0x61, 0x39, 0x33, 0xc7, 0x66, 0xe7, 0xae, 0x3a, 0xda, 0x0c, 0xb5, 0xa3, - 0x7f, 0x02, 0xf7, 0xe7, 0x34, 0x3f, 0x7d, 0xcd, 0x12, 0x77, 0x66, 0xb8, 0x17, 0xb0, 0x54, 0xd1, - 0x6a, 0x80, 0x95, 0x8a, 0x56, 0xc6, 0xa7, 0xb0, 0x3b, 0xa7, 0x15, 0x4a, 0xea, 0x96, 0x39, 0x6f, - 0x55, 0x88, 0x59, 0x22, 0x17, 0x7a, 0x1a, 0x2b, 0xe4, 0x42, 0x52, 0x08, 0xd5, 0x64, 0x22, 0x25, - 0xf2, 0x64, 0x1a, 0x34, 0x2d, 0x67, 0xb6, 0x26, 0x4f, 0xa0, 0x31, 0x92, 0x42, 0xa9, 0x3e, 0xcd, - 0x0c, 0x3b, 0xd8, 0x8e, 0x4a, 0x9d, 0xcd, 0xb8, 0x6e, 0xb1, 0x63, 0x0b, 0x99, 0x6b, 0xca, 0x51, - 0x17, 0x84, 0x1d, 0x4b, 0xa8, 0x71, 0xd4, 0xf3, 0xb0, 0xa6, 0x57, 0x45, 0xf8, 0xbe, 0x0b, 0x6b, - 0x7a, 0xe5, 0xc3, 0x07, 0x50, 0x35, 0x61, 0x69, 0x2e, 0xf2, 0xae, 0x0d, 0x56, 0x34, 0xbd, 0x8a, - 0xcd, 0x55, 0x7e, 0x04, 0xb5, 0xd9, 0xac, 0x01, 0x71, 0xd7, 0x7f, 0x06, 0x90, 0x87, 0x50, 0x76, - 0x27, 0x13, 0x3c, 0xb0, 0x21, 0xbf, 0x32, 0xcf, 0x22, 0xa7, 0x53, 0xc4, 0xa0, 0xe5, 0x9e, 0x85, - 0x5d, 0x18, 0xe3, 0x4b, 0x44, 0x66, 0x1e, 0x56, 0xb0, 0xe7, 0x8c, 0xcf, 0x2f, 0xc9, 0xe7, 0x50, - 0x4d, 0x27, 0xd8, 0x37, 0x56, 0x14, 0x3c, 0xb4, 0xef, 0x38, 0xec, 0x3a, 0x5f, 0xef, 0x16, 0xbe, - 0xde, 0xfd, 0xae, 0xf0, 0xf5, 0xb8, 0x92, 0x4e, 0xcc, 0x53, 0x40, 0xf2, 0x35, 0x34, 0x4c, 0x4a, - 0x3f, 0xb1, 0x6e, 0x99, 0x06, 0xfb, 0x77, 0xa6, 0xd6, 0x0d, 0xdf, 0x99, 0xab, 0x7d, 0xdb, 0x78, - 0xa5, 0x25, 0xed, 0x5b, 0xff, 0x08, 0x9c, 0x38, 0x8b, 0x98, 0x87, 0x76, 0xf4, 0xcb, 0x16, 0xec, - 0xbc, 0xf2, 0x4e, 0x70, 0xe1, 0x7e, 0x4d, 0x24, 0x83, 0xb2, 0xcb, 0x26, 0x8f, 0x57, 0x8d, 0x66, - 0xc9, 0xb2, 0xc3, 0x60, 0x35, 0x5c, 0x18, 0x4f, 0xfb, 0xd9, 0xf5, 0x71, 0x2b, 0x24, 0x8e, 0xad, - 0x22, 0xca, 0x23, 0x4f, 0xfc, 0xf9, 0xcf, 0xbf, 0x7e, 0xdb, 0x68, 0xb6, 0xab, 0x3d, 0xbf, 0xfe, - 0xaa, 0xf4, 0x8c, 0xbc, 0x83, 0xb2, 0x33, 0xe8, 0xf5, 0x76, 0x4b, 0xc6, 0x7d, 0x4b, 0xbb, 0x2f, - 0x6c, 0x3b, 0xc7, 0x5e, 0x6b, 0x17, 0x86, 0x7b, 0x45, 0xbb, 0xde, 0xfb, 0xb9, 0xcf, 0x7f, 0x30, - 0xbd, 0x7f, 0x2f, 0xd9, 0x5f, 0xa1, 0xff, 0xb9, 0x91, 0x70, 0xd6, 0x61, 0xed, 0x8f, 0x77, 0x4b, - 0xf7, 0xf3, 0xeb, 0xe3, 0x8f, 0xc3, 0xa7, 0xa7, 0xa8, 0x23, 0x1a, 0xa9, 0x1c, 0x13, 0x36, 0x64, - 0x49, 0xe4, 0xed, 0x33, 0x12, 0xc3, 0xd5, 0x79, 0x9e, 0x90, 0xc3, 0x1b, 0xe7, 0xe9, 0xbd, 0xf7, - 0x39, 0x1f, 0x88, 0x80, 0xcd, 0x53, 0xd4, 0xe4, 0xc1, 0xe2, 0x38, 0x77, 0xcf, 0xf1, 0xe5, 0xf5, - 0xf1, 0x41, 0xb8, 0x6f, 0xe6, 0xd0, 0x6f, 0x31, 0x72, 0x2f, 0x4b, 0x2f, 0xb5, 0xde, 0x27, 0x37, - 0x6f, 0xc5, 0xcb, 0x0e, 0xd4, 0x13, 0x91, 0x15, 0x95, 0x5f, 0x36, 0xfc, 0x55, 0x38, 0x37, 0x97, - 0xeb, 0xbc, 0xf4, 0xa6, 0xe6, 0x03, 0xf9, 0x60, 0x50, 0xb6, 0x17, 0xee, 0xb3, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x0c, 0x8d, 0xd7, 0x8a, 0xd1, 0x08, 0x00, 0x00, +func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_493cda4133eb71cc) } + +var fileDescriptor_service_493cda4133eb71cc = []byte{ + // 983 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x5f, 0x6f, 0x1b, 0x45, + 0x10, 0x97, 0x93, 0xd4, 0x89, 0xc7, 0x71, 0xd2, 0x6c, 0x9d, 0xe4, 0x72, 0x6a, 0xc9, 0xd5, 0x14, + 0x64, 0x4a, 0x6b, 0x4b, 0x41, 0x08, 0x81, 0xc4, 0x83, 0x9b, 0x4a, 0x21, 0x0f, 0x54, 0xd1, 0x25, + 0xf0, 0xd0, 0x17, 0x6b, 0xbd, 0x37, 0x76, 0x4f, 0xf8, 0x76, 0x8f, 0xdb, 0x75, 0x88, 0x5b, 0xf5, + 0x05, 0xf1, 0x09, 0x02, 0xdf, 0x84, 0x8f, 0xc2, 0x2b, 0x8f, 0x7c, 0x06, 0x9e, 0xd1, 0xfe, 0xf3, + 0xdf, 0x28, 0xa1, 0x4f, 0xa7, 0xfd, 0xcd, 0x6f, 0x67, 0x7e, 0x33, 0x37, 0x3b, 0x03, 0xbb, 0x29, + 0xbf, 0x14, 0x29, 0xc3, 0xb6, 0xc4, 0xe2, 0x32, 0x65, 0xd8, 0xca, 0x0b, 0xa1, 0x04, 0x59, 0x77, + 0x70, 0xb8, 0x97, 0x08, 0x36, 0xca, 0x90, 0xab, 0x79, 0x42, 0xf8, 0x70, 0x20, 0xc4, 0x60, 0x88, + 0x6d, 0x9a, 0xa7, 0x6d, 0xca, 0xb9, 0x50, 0x54, 0xa5, 0x82, 0x4b, 0x67, 0x3d, 0x74, 0x56, 0x73, + 0xea, 0x8d, 0xfa, 0x6d, 0x95, 0x66, 0x28, 0x15, 0xcd, 0x72, 0x47, 0x78, 0x66, 0x3e, 0xec, 0xf9, + 0x00, 0xf9, 0x73, 0xf9, 0x0b, 0x1d, 0x0c, 0xb0, 0x68, 0x8b, 0xdc, 0xb8, 0x58, 0x76, 0xd7, 0x78, + 0x06, 0x70, 0x82, 0x2a, 0xc6, 0x9f, 0x47, 0x28, 0x15, 0xf9, 0x08, 0x20, 0x4d, 0x90, 0xab, 0xb4, + 0x9f, 0x62, 0x11, 0x94, 0xa2, 0x52, 0xb3, 0x12, 0xcf, 0x20, 0x8d, 0xef, 0x61, 0xe7, 0x04, 0xd5, + 0x8f, 0x58, 0xc8, 0x54, 0xf0, 0xff, 0x79, 0x89, 0x04, 0xb0, 0x7e, 0x69, 0x6f, 0x04, 0x2b, 0xc6, + 0xe8, 0x8f, 0x8d, 0x3e, 0xd4, 0x4f, 0x6d, 0x31, 0x8e, 0x0b, 0xa4, 0x0a, 0xcf, 0xe8, 0x78, 0x28, + 0x68, 0x42, 0x9e, 0x40, 0x8d, 0x89, 0xe1, 0x90, 0xf6, 0x44, 0x41, 0x95, 0x28, 0x64, 0x50, 0x8a, + 0x56, 0x9b, 0x95, 0x78, 0x1e, 0x24, 0x4d, 0x58, 0x4b, 0xa8, 0xa2, 0xc6, 0x69, 0xf5, 0xa8, 0xde, + 0x72, 0x75, 0x6d, 0x39, 0x97, 0x2f, 0xa9, 0xa2, 0xb1, 0x61, 0x34, 0xfe, 0x2e, 0x4d, 0x02, 0xfd, + 0x90, 0x27, 0x33, 0x81, 0xee, 0x92, 0xbe, 0x24, 0x64, 0xe5, 0x36, 0x21, 0xab, 0x77, 0x09, 0x21, + 0x17, 0x50, 0xa7, 0x8c, 0xa1, 0x94, 0x5d, 0x25, 0x7e, 0x42, 0xde, 0xcd, 0xad, 0x8e, 0x60, 0xcd, + 0xdc, 0x6c, 0xb4, 0x7c, 0x47, 0xb4, 0xac, 0xcc, 0x8e, 0xe1, 0x5e, 0x68, 0xaa, 0x53, 0x1c, 0x13, + 0xba, 0x84, 0x35, 0x86, 0xb0, 0xed, 0x42, 0xc5, 0x28, 0x73, 0xc1, 0x25, 0x92, 0x36, 0x94, 0xdf, + 0x20, 0x4d, 0x5c, 0x52, 0xd5, 0xa3, 0xfd, 0x89, 0x28, 0x4f, 0xf9, 0xce, 0x98, 0x63, 0x47, 0xfb, + 0x80, 0x62, 0xfe, 0x59, 0x82, 0xad, 0x79, 0x27, 0xe4, 0x10, 0xaa, 0x5e, 0x79, 0x37, 0x4d, 0x7c, + 0x1d, 0x3d, 0x74, 0x9a, 0x90, 0x47, 0x00, 0xee, 0x9f, 0x6b, 0xbb, 0xed, 0x82, 0x8a, 0x43, 0x4e, + 0x13, 0x52, 0x87, 0x7b, 0x52, 0x51, 0x85, 0xa6, 0x82, 0x95, 0xd8, 0x1e, 0x96, 0x8b, 0xbf, 0x76, + 0x53, 0xf1, 0x3f, 0x81, 0x2d, 0x55, 0x50, 0x2e, 0x29, 0x53, 0xce, 0xfd, 0x3d, 0xe3, 0xa4, 0x36, + 0x83, 0x9e, 0x26, 0x8d, 0x7f, 0xcb, 0x50, 0x9d, 0xc9, 0x45, 0x5f, 0x73, 0x29, 0x76, 0x75, 0xb4, + 0x91, 0x0c, 0x0e, 0xec, 0x35, 0x87, 0x9e, 0x1b, 0x70, 0x96, 0xc6, 0x47, 0x59, 0x6f, 0xd2, 0x24, + 0x9e, 0xf6, 0xca, 0x80, 0xba, 0x00, 0x12, 0x79, 0x82, 0x45, 0x97, 0xd3, 0xcc, 0xa7, 0x01, 0x16, + 0x7a, 0x45, 0x33, 0x24, 0x1f, 0x43, 0xcd, 0x11, 0xa4, 0x2a, 0x10, 0x95, 0xf9, 0xe3, 0x95, 0x78, + 0xd3, 0x82, 0xe7, 0x06, 0x9b, 0xf1, 0xc2, 0x52, 0x35, 0x76, 0x79, 0x38, 0x2f, 0xc7, 0xa9, 0x1a, + 0x6b, 0x35, 0x8e, 0xf0, 0x36, 0xcd, 0x99, 0x48, 0x30, 0x28, 0x5b, 0x35, 0x16, 0x7d, 0x6d, 0xc1, + 0x19, 0x1a, 0x13, 0x23, 0xae, 0x8a, 0x71, 0xb0, 0x3e, 0x4b, 0x3b, 0xb6, 0xa0, 0xa6, 0x15, 0xc8, + 0xd2, 0x3c, 0xd5, 0xbf, 0xcd, 0xe8, 0xde, 0xb0, 0xb4, 0x09, 0x6a, 0xa4, 0x7f, 0x06, 0xf7, 0xa7, + 0x34, 0xa7, 0xbe, 0x62, 0x88, 0xdb, 0x13, 0xdc, 0x25, 0x30, 0xe7, 0xd1, 0xe4, 0x00, 0x0b, 0x1e, + 0x4d, 0x1a, 0x9f, 0xc3, 0xce, 0x94, 0xe6, 0x33, 0xa9, 0x1a, 0xe6, 0x34, 0x94, 0x4f, 0x66, 0x8e, + 0xec, 0xf3, 0xd9, 0x5c, 0x20, 0xfb, 0x94, 0x42, 0xd8, 0x60, 0xa3, 0xa2, 0x40, 0xce, 0xc6, 0x41, + 0xcd, 0x70, 0x26, 0x67, 0xf2, 0x18, 0x36, 0x07, 0x85, 0x90, 0xb2, 0x4b, 0x33, 0xcd, 0x0e, 0xb6, + 0xa2, 0x52, 0x73, 0x35, 0xae, 0x1a, 0xac, 0x63, 0x20, 0xdd, 0xa6, 0x1c, 0x95, 0x27, 0x6c, 0x1b, + 0x42, 0x85, 0xa3, 0x9a, 0x9a, 0x15, 0xbd, 0xf2, 0xe6, 0xfb, 0xd6, 0xac, 0xe8, 0x95, 0x33, 0x1f, + 0xc0, 0x86, 0x36, 0x17, 0xba, 0x91, 0x77, 0x8c, 0x71, 0x5d, 0xd1, 0xab, 0x58, 0xb7, 0xf2, 0x43, + 0xa8, 0x4c, 0xb4, 0x06, 0xc4, 0xb6, 0xff, 0x04, 0x20, 0x7b, 0x50, 0xb6, 0x7f, 0x26, 0x78, 0x60, + 0x4c, 0xee, 0xa4, 0x9f, 0x45, 0x4e, 0xc7, 0x88, 0x41, 0xdd, 0x3e, 0x0b, 0x73, 0xd0, 0xe3, 0x94, + 0x89, 0x4c, 0x3f, 0xac, 0x60, 0xd7, 0x8e, 0x53, 0x77, 0x24, 0x5f, 0xc2, 0x46, 0x32, 0xc2, 0xae, + 0x9e, 0x1c, 0xc1, 0x9e, 0x79, 0xc7, 0x61, 0xcb, 0x6e, 0x8b, 0x96, 0xdf, 0x16, 0xad, 0x0b, 0xbf, + 0x2d, 0xe2, 0xf5, 0x64, 0xa4, 0x9f, 0x02, 0x92, 0x6f, 0x61, 0x53, 0x5f, 0xe9, 0x32, 0x33, 0x83, + 0x93, 0x60, 0xff, 0xce, 0xab, 0x55, 0xcd, 0xb7, 0x23, 0xdb, 0xbc, 0x6d, 0xbc, 0x52, 0x05, 0xed, + 0x9a, 0xf9, 0x11, 0xd8, 0xe4, 0x0c, 0xa2, 0x1f, 0xda, 0xd1, 0x6f, 0x6b, 0xb0, 0xfd, 0xd2, 0x4d, + 0x82, 0x73, 0xbb, 0xe7, 0x48, 0x06, 0x65, 0x7b, 0x9b, 0x3c, 0x5a, 0x1c, 0x34, 0x73, 0x8b, 0x20, + 0x0c, 0x16, 0xcd, 0x7e, 0xf0, 0x34, 0x9e, 0x5e, 0x77, 0xea, 0x21, 0xb1, 0x6c, 0x19, 0x51, 0x1e, + 0x39, 0xe2, 0xaf, 0x7f, 0xfd, 0xf3, 0xfb, 0x4a, 0xad, 0xb1, 0xd1, 0x76, 0xe7, 0x6f, 0x4a, 0x4f, + 0xc9, 0x5b, 0x28, 0xdb, 0x79, 0xba, 0x1c, 0x6e, 0x6e, 0x1d, 0xdc, 0x12, 0xee, 0x2b, 0x13, 0xce, + 0xb2, 0x97, 0xc2, 0x85, 0xe1, 0xae, 0x0f, 0xd7, 0x7e, 0x37, 0xdd, 0x1e, 0xef, 0x75, 0xec, 0x3f, + 0x4a, 0x66, 0xc1, 0xba, 0x95, 0x49, 0xc2, 0x49, 0x84, 0xa5, 0x3d, 0x7a, 0x4b, 0xf4, 0xb3, 0xeb, + 0xce, 0xa7, 0xe1, 0x93, 0x13, 0x54, 0x11, 0x8d, 0x64, 0x8e, 0x2c, 0xed, 0xa7, 0x2c, 0x72, 0xe3, + 0x33, 0x12, 0xfd, 0x45, 0x3d, 0x8f, 0xc9, 0xe1, 0x8d, 0x7a, 0xda, 0xef, 0xdc, 0x9d, 0xf7, 0x44, + 0xc0, 0xea, 0x09, 0x2a, 0xf2, 0x60, 0x56, 0xce, 0xdd, 0x3a, 0xbe, 0xbe, 0xee, 0x1c, 0x84, 0xfb, + 0x5a, 0x87, 0x7a, 0x83, 0x91, 0x7d, 0x59, 0x6a, 0x2e, 0xf4, 0x3e, 0xb9, 0xb9, 0x14, 0x2f, 0x9a, + 0x50, 0x65, 0x22, 0xf3, 0x9e, 0x5f, 0x6c, 0xba, 0x56, 0x38, 0xd3, 0xcd, 0x75, 0x56, 0x7a, 0x5d, + 0x71, 0x86, 0xbc, 0xd7, 0x2b, 0x9b, 0x86, 0xfb, 0xe2, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdd, + 0x1f, 0x15, 0x2c, 0x3f, 0x09, 0x00, 0x00, } diff --git a/protobufs/gen/go/purchaseorder/service.pb.go b/protobufs/gen/go/purchaseorder/service.pb.go index d1b20e857..184716ea1 100644 --- a/protobufs/gen/go/purchaseorder/service.pb.go +++ b/protobufs/gen/go/purchaseorder/service.pb.go @@ -6,6 +6,7 @@ package purchaseorderpb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" +import document "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" import timestamp "github.com/golang/protobuf/ptypes/timestamp" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" @@ -37,7 +38,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{0} + return fileDescriptor_service_a9b80dc96b015f6f, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -76,7 +77,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{1} + return fileDescriptor_service_a9b80dc96b015f6f, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -122,7 +123,7 @@ func (m *PurchaseOrderCreatePayload) Reset() { *m = PurchaseOrderCreateP func (m *PurchaseOrderCreatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderCreatePayload) ProtoMessage() {} func (*PurchaseOrderCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{2} + return fileDescriptor_service_a9b80dc96b015f6f, []int{2} } func (m *PurchaseOrderCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderCreatePayload.Unmarshal(m, b) @@ -157,19 +158,20 @@ func (m *PurchaseOrderCreatePayload) GetData() *PurchaseOrderData { } type PurchaseOrderUpdatePayload struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` - Data *PurchaseOrderData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + Data *PurchaseOrderData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + AccessTokenPayload *document.UpdateAccessTokenPayload `protobuf:"bytes,4,opt,name=access_token_payload,json=accessTokenPayload,proto3" json:"access_token_payload,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *PurchaseOrderUpdatePayload) Reset() { *m = PurchaseOrderUpdatePayload{} } func (m *PurchaseOrderUpdatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderUpdatePayload) ProtoMessage() {} func (*PurchaseOrderUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{3} + return fileDescriptor_service_a9b80dc96b015f6f, []int{3} } func (m *PurchaseOrderUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderUpdatePayload.Unmarshal(m, b) @@ -210,6 +212,13 @@ func (m *PurchaseOrderUpdatePayload) GetData() *PurchaseOrderData { return nil } +func (m *PurchaseOrderUpdatePayload) GetAccessTokenPayload() *document.UpdateAccessTokenPayload { + if m != nil { + return m.AccessTokenPayload + } + return nil +} + type PurchaseOrderResponse struct { Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Data *PurchaseOrderData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -222,7 +231,7 @@ func (m *PurchaseOrderResponse) Reset() { *m = PurchaseOrderResponse{} } func (m *PurchaseOrderResponse) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderResponse) ProtoMessage() {} func (*PurchaseOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{4} + return fileDescriptor_service_a9b80dc96b015f6f, []int{4} } func (m *PurchaseOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderResponse.Unmarshal(m, b) @@ -272,7 +281,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{5} + return fileDescriptor_service_a9b80dc96b015f6f, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -373,7 +382,7 @@ func (m *PurchaseOrderData) Reset() { *m = PurchaseOrderData{} } func (m *PurchaseOrderData) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderData) ProtoMessage() {} func (*PurchaseOrderData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_393a7cd179a9d71e, []int{6} + return fileDescriptor_service_a9b80dc96b015f6f, []int{6} } func (m *PurchaseOrderData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderData.Unmarshal(m, b) @@ -743,70 +752,72 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_393a7cd179a9d71e) -} - -var fileDescriptor_service_393a7cd179a9d71e = []byte{ - // 963 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x5f, 0x6f, 0x1b, 0x45, - 0x10, 0xd7, 0xe5, 0x8f, 0x63, 0xaf, 0xed, 0xa4, 0xde, 0xb6, 0x70, 0xbd, 0x34, 0xf4, 0x30, 0xad, - 0x48, 0xdb, 0xc4, 0x96, 0x42, 0xe1, 0x01, 0x09, 0xa1, 0x34, 0x91, 0x42, 0x1e, 0x28, 0xd1, 0x05, - 0x78, 0xa8, 0x90, 0xac, 0xf5, 0xde, 0xc4, 0x39, 0xc9, 0x77, 0x7b, 0xec, 0xad, 0x83, 0x4d, 0xd5, - 0x17, 0xc4, 0x17, 0x20, 0xbc, 0x80, 0x90, 0xf8, 0x10, 0xf0, 0x51, 0xf8, 0x0a, 0x7c, 0x05, 0xde, - 0xd1, 0xce, 0xee, 0xd9, 0x3e, 0xbb, 0x38, 0x09, 0x4f, 0xa7, 0xfd, 0xcd, 0x6f, 0xe6, 0x7e, 0x33, - 0xb3, 0x3b, 0x43, 0x36, 0xd3, 0x81, 0xe4, 0xe7, 0x2c, 0x03, 0x21, 0x43, 0x90, 0xed, 0x0c, 0xe4, - 0x45, 0xc4, 0xa1, 0x95, 0x4a, 0xa1, 0x04, 0xad, 0x17, 0x8c, 0xde, 0xfd, 0x9e, 0x10, 0xbd, 0x3e, - 0xb4, 0x59, 0x1a, 0xb5, 0x59, 0x92, 0x08, 0xc5, 0x54, 0x24, 0x92, 0xcc, 0x90, 0xbd, 0x07, 0xd6, - 0x8a, 0xa7, 0xee, 0xe0, 0xac, 0xad, 0xa2, 0x18, 0x32, 0xc5, 0xe2, 0xd4, 0x12, 0x76, 0xf0, 0xc3, - 0x77, 0x7b, 0x90, 0xec, 0x66, 0xdf, 0xb1, 0x5e, 0x0f, 0x64, 0x5b, 0xa4, 0x18, 0x62, 0x3e, 0x5c, - 0x73, 0x87, 0x90, 0x23, 0x50, 0x01, 0x7c, 0x3b, 0x80, 0x4c, 0xd1, 0x77, 0x08, 0x89, 0x42, 0x48, - 0x54, 0x74, 0x16, 0x81, 0x74, 0x1d, 0xdf, 0xd9, 0xae, 0x04, 0x53, 0x48, 0xf3, 0x73, 0xd2, 0x38, - 0x02, 0xf5, 0x35, 0xc8, 0x2c, 0x12, 0xc9, 0x35, 0x9d, 0xa8, 0x4b, 0xd6, 0x2e, 0x8c, 0x87, 0xbb, - 0x84, 0xc6, 0xfc, 0xd8, 0x1c, 0x12, 0xef, 0xc4, 0xa6, 0xfe, 0x85, 0x4e, 0xfd, 0x40, 0x02, 0x53, - 0x70, 0xc2, 0x46, 0x7d, 0xc1, 0x42, 0xfa, 0x90, 0xd4, 0xb9, 0xe8, 0xf7, 0x59, 0x57, 0x48, 0xa6, - 0x84, 0xcc, 0x5c, 0xc7, 0x5f, 0xde, 0xae, 0x04, 0x45, 0x90, 0x3e, 0x23, 0x2b, 0x21, 0x53, 0x0c, - 0x43, 0x57, 0xf7, 0xfc, 0x56, 0xa1, 0x96, 0xad, 0x42, 0xf8, 0x43, 0xa6, 0x58, 0x80, 0xec, 0xe6, - 0x2f, 0xce, 0xcc, 0xaf, 0xbf, 0x4a, 0xc3, 0xa9, 0x5f, 0x5f, 0x95, 0xd2, 0x9c, 0xb4, 0xa5, 0x45, - 0xd2, 0x96, 0x6f, 0x24, 0xed, 0x47, 0x87, 0xdc, 0x2d, 0xd8, 0x02, 0xc8, 0x52, 0x91, 0x64, 0x40, - 0x3f, 0x24, 0xa5, 0x73, 0x60, 0xa1, 0x55, 0x54, 0xdd, 0xdb, 0x9a, 0x89, 0x98, 0x13, 0x3f, 0x43, - 0x52, 0x60, 0xc9, 0xff, 0xb3, 0x42, 0x7f, 0x3a, 0x64, 0xbd, 0x18, 0x90, 0x3e, 0x20, 0xd5, 0x50, - 0xf0, 0x41, 0x0c, 0x89, 0xea, 0x44, 0x61, 0x5e, 0x96, 0x1c, 0x3a, 0x0e, 0xe9, 0x16, 0x21, 0xb6, - 0xb5, 0xda, 0x6e, 0x9a, 0x5d, 0xb1, 0xc8, 0x71, 0x48, 0xef, 0x90, 0xd5, 0x4c, 0x31, 0x05, 0x58, - 0x90, 0x4a, 0x60, 0x0e, 0xf3, 0xb5, 0x5c, 0x79, 0x53, 0x2d, 0x1f, 0x91, 0x75, 0x25, 0x59, 0x92, - 0x31, 0xae, 0x6c, 0xf8, 0x55, 0x0c, 0x52, 0x9f, 0x42, 0x8f, 0xc3, 0xe6, 0x3f, 0x25, 0xd2, 0x98, - 0xcb, 0x88, 0x6e, 0x92, 0x4a, 0x2a, 0x3a, 0xfa, 0x77, 0x83, 0xcc, 0x75, 0xd1, 0xaf, 0x9c, 0x8a, - 0x53, 0x3c, 0x5b, 0x63, 0x32, 0x88, 0xbb, 0xe3, 0x56, 0x97, 0x53, 0xf1, 0x02, 0xcf, 0x3a, 0x23, - 0x2c, 0x53, 0x27, 0x61, 0x31, 0xe4, 0x19, 0x21, 0xf2, 0x82, 0xc5, 0x40, 0xdf, 0x25, 0x35, 0x63, - 0xce, 0x94, 0x04, 0x50, 0x36, 0xb1, 0x2a, 0x62, 0xa7, 0x08, 0x4d, 0x22, 0xf0, 0x48, 0x8d, 0xdc, - 0x95, 0xa9, 0x08, 0x07, 0x91, 0x1a, 0xd1, 0xf7, 0x48, 0xdd, 0x98, 0xbf, 0x8f, 0x52, 0x2e, 0x42, - 0xb0, 0x69, 0x99, 0xb0, 0x2f, 0x0d, 0x36, 0x21, 0x71, 0x31, 0x48, 0x94, 0x1c, 0xb9, 0xa5, 0x29, - 0xd2, 0x81, 0xc1, 0x74, 0x85, 0x24, 0xf0, 0x28, 0x8d, 0x74, 0x7b, 0x50, 0xee, 0x9a, 0xa9, 0xd0, - 0x18, 0x45, 0xc9, 0x8f, 0xc9, 0xad, 0x09, 0xcd, 0xca, 0x2e, 0x23, 0x71, 0x63, 0x8c, 0x5b, 0xe9, - 0x85, 0x88, 0x28, 0xbf, 0x32, 0x13, 0x11, 0x53, 0x78, 0x4a, 0x1a, 0x13, 0x5a, 0x9e, 0x06, 0x41, - 0xe6, 0xe4, 0x57, 0x79, 0x2a, 0x05, 0x72, 0x9e, 0x4e, 0x75, 0x86, 0x9c, 0xa7, 0xe4, 0x91, 0x32, - 0x1f, 0x48, 0x09, 0x09, 0x1f, 0xb9, 0x35, 0xd3, 0x99, 0xfc, 0x3c, 0x29, 0x3d, 0x8b, 0x35, 0xdb, - 0xad, 0xfb, 0xce, 0xf6, 0xb2, 0x2d, 0xfd, 0x3e, 0x42, 0xba, 0xf4, 0x09, 0xa8, 0x9c, 0xb0, 0x8e, - 0x84, 0x4a, 0x02, 0x6a, 0x62, 0x56, 0x6c, 0x98, 0x9b, 0x37, 0x8c, 0x59, 0xb1, 0xa1, 0x35, 0xdf, - 0x23, 0x65, 0x6d, 0x96, 0xfa, 0xc2, 0xde, 0x42, 0xe3, 0x9a, 0x62, 0xc3, 0x40, 0x5f, 0xd9, 0xfb, - 0xa4, 0x32, 0xd6, 0xea, 0x36, 0x4c, 0x4b, 0xc7, 0x80, 0xbe, 0xe6, 0xa8, 0xc2, 0xa5, 0xe6, 0x9a, - 0xe3, 0x61, 0xba, 0x87, 0x89, 0x62, 0x5c, 0xb9, 0xb7, 0x0b, 0x3d, 0x44, 0x4c, 0x8f, 0x4a, 0x2e, - 0x62, 0xfd, 0x9a, 0xdc, 0x3b, 0x66, 0x54, 0xda, 0x23, 0xfd, 0x94, 0xd4, 0x43, 0xe8, 0x47, 0x17, - 0x20, 0x47, 0x1d, 0x3d, 0xa9, 0xdc, 0xbb, 0xf8, 0x9a, 0xbd, 0x96, 0x59, 0x07, 0xad, 0x7c, 0x1d, - 0xb4, 0xbe, 0xcc, 0xd7, 0x41, 0x50, 0xcb, 0x1d, 0x0e, 0xb5, 0xe6, 0x4f, 0x48, 0x4d, 0xfb, 0x75, - 0x38, 0xce, 0xd8, 0xd0, 0x7d, 0xeb, 0x4a, 0xff, 0xaa, 0xe6, 0x9b, 0x91, 0x8c, 0x4f, 0x1b, 0x86, - 0x4a, 0xb2, 0x0e, 0x8e, 0x92, 0xb7, 0x4d, 0xce, 0x88, 0xe8, 0x17, 0xb6, 0xf7, 0xeb, 0x2a, 0xd9, - 0x38, 0xb4, 0x83, 0xe0, 0xd4, 0x2c, 0x37, 0xfa, 0x93, 0x43, 0x4a, 0xc6, 0x9d, 0x3e, 0x5e, 0x34, - 0x74, 0x0a, 0x53, 0xdf, 0x7b, 0xb8, 0x88, 0x9a, 0x0f, 0xa4, 0xe6, 0x47, 0x97, 0xfb, 0x9e, 0xe7, - 0x1a, 0xcf, 0xcc, 0x67, 0x7e, 0xee, 0xe3, 0xa3, 0xd3, 0x0f, 0x7f, 0xfd, 0xfd, 0xf3, 0xd2, 0xed, - 0xe6, 0x7a, 0xbb, 0x10, 0xea, 0x63, 0xe7, 0x09, 0xfd, 0xdd, 0x21, 0x25, 0x33, 0xea, 0x17, 0x6b, - 0x2a, 0xac, 0x83, 0x6b, 0x6a, 0x3a, 0x40, 0x4d, 0xc6, 0xf3, 0x3f, 0x34, 0xf9, 0xde, 0x66, 0x51, - 0x53, 0xfb, 0xd5, 0x64, 0xab, 0xbc, 0xd6, 0x02, 0xff, 0x70, 0x70, 0x21, 0xdb, 0x15, 0x4b, 0x67, - 0xa7, 0xf5, 0xdc, 0xf6, 0xbd, 0xa6, 0xb6, 0x6f, 0x2e, 0xf7, 0x77, 0xbc, 0x27, 0x47, 0xa0, 0x7c, - 0xe6, 0x67, 0x29, 0xf0, 0xe8, 0x2c, 0xe2, 0xbe, 0x9d, 0xcc, 0xbe, 0x38, 0x7b, 0xb3, 0xda, 0xf7, - 0xe9, 0xa3, 0x05, 0x6a, 0xdb, 0xaf, 0xac, 0xff, 0x6b, 0xfa, 0x9b, 0x43, 0x96, 0x8f, 0x40, 0xd1, - 0x7b, 0xf3, 0x6a, 0x6f, 0x26, 0xf3, 0xf4, 0x72, 0x7f, 0xd7, 0x7b, 0xaa, 0x65, 0xaa, 0x73, 0xf0, - 0xcd, 0x5b, 0x57, 0x57, 0xea, 0xdc, 0xa2, 0x8b, 0xaa, 0xfa, 0xfc, 0x19, 0x69, 0x70, 0x11, 0x17, - 0xff, 0xff, 0xbc, 0x66, 0x6f, 0xe9, 0x89, 0xbe, 0xf7, 0x27, 0xce, 0xcb, 0x8d, 0x82, 0x39, 0xed, - 0x76, 0x4b, 0xf8, 0x22, 0x3e, 0xf8, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xa0, 0xe0, 0x99, 0xba, - 0x09, 0x00, 0x00, + proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_a9b80dc96b015f6f) +} + +var fileDescriptor_service_a9b80dc96b015f6f = []byte{ + // 1008 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdf, 0x6e, 0x1b, 0xc5, + 0x17, 0xd6, 0xe6, 0x8f, 0x13, 0x8f, 0xe3, 0xa4, 0x99, 0xa6, 0xfd, 0x6d, 0x37, 0xcd, 0xaf, 0x8b, + 0x69, 0x45, 0xda, 0x26, 0xb6, 0x14, 0x0a, 0x17, 0x48, 0x08, 0xa5, 0x89, 0x14, 0x72, 0x41, 0x89, + 0x36, 0x81, 0x8b, 0x0a, 0xc9, 0x1a, 0xcf, 0x9e, 0x38, 0x2b, 0xec, 0x9d, 0x65, 0x76, 0x1c, 0x6c, + 0xaa, 0xde, 0x20, 0x5e, 0x80, 0x70, 0x85, 0x90, 0x78, 0x08, 0x78, 0x14, 0x5e, 0x81, 0x6b, 0xee, + 0xb8, 0x47, 0x73, 0x66, 0xc6, 0xf6, 0xda, 0xc5, 0x49, 0xb9, 0x5a, 0xcd, 0x77, 0xbe, 0x73, 0xf6, + 0x3b, 0x67, 0xce, 0x9c, 0x43, 0x36, 0xb3, 0x9e, 0xe4, 0x17, 0x2c, 0x07, 0x21, 0x63, 0x90, 0x8d, + 0x1c, 0xe4, 0x65, 0xc2, 0xa1, 0x9e, 0x49, 0xa1, 0x04, 0xad, 0x16, 0x8c, 0xc1, 0xdd, 0x58, 0xf0, + 0x5e, 0x17, 0x52, 0x55, 0xa4, 0x05, 0xf7, 0xdb, 0x42, 0xb4, 0x3b, 0xd0, 0x60, 0x59, 0xd2, 0x60, + 0x69, 0x2a, 0x14, 0x53, 0x89, 0x48, 0x73, 0x6b, 0x7d, 0x60, 0xad, 0x78, 0x6a, 0xf5, 0xce, 0x1b, + 0x2a, 0xe9, 0x42, 0xae, 0x58, 0x37, 0xb3, 0x84, 0x1d, 0xfc, 0xf0, 0xdd, 0x36, 0xa4, 0xbb, 0xf9, + 0xb7, 0xac, 0xdd, 0x06, 0xd9, 0x10, 0x19, 0x86, 0x98, 0x0e, 0x57, 0xdb, 0x21, 0xe4, 0x08, 0x54, + 0x04, 0xdf, 0xf4, 0x20, 0x57, 0xf4, 0xff, 0x84, 0x24, 0x31, 0xa4, 0x2a, 0x39, 0x4f, 0x40, 0xfa, + 0x5e, 0xe8, 0x6d, 0x97, 0xa3, 0x31, 0xa4, 0xf6, 0x19, 0x59, 0x3f, 0x02, 0xf5, 0x25, 0xc8, 0x3c, + 0x11, 0xe9, 0x0d, 0x9d, 0xa8, 0x4f, 0x96, 0x2e, 0x8d, 0x87, 0x3f, 0x87, 0x46, 0x77, 0xac, 0xf5, + 0x49, 0x70, 0x62, 0x4b, 0xf2, 0xb9, 0x2e, 0xc9, 0x81, 0x04, 0xa6, 0xe0, 0x84, 0x0d, 0x3a, 0x82, + 0xc5, 0xf4, 0x21, 0xa9, 0x72, 0xd1, 0xe9, 0xb0, 0x96, 0x90, 0x4c, 0x09, 0x99, 0xfb, 0x5e, 0x38, + 0xbf, 0x5d, 0x8e, 0x8a, 0x20, 0x7d, 0x46, 0x16, 0x62, 0xa6, 0x18, 0x86, 0xae, 0xec, 0x85, 0xf5, + 0x42, 0x8d, 0xeb, 0x85, 0xf0, 0x87, 0x4c, 0xb1, 0x08, 0xd9, 0xb5, 0xbf, 0xbc, 0x89, 0x5f, 0x7f, + 0x91, 0xc5, 0x63, 0xbf, 0xbe, 0x2e, 0xa5, 0x29, 0x69, 0x73, 0xb3, 0xa4, 0xcd, 0xbf, 0x8d, 0x34, + 0x7a, 0x46, 0x36, 0x18, 0xe7, 0x90, 0xe7, 0x4d, 0x25, 0xbe, 0x86, 0xb4, 0x99, 0x19, 0x4d, 0xfe, + 0x02, 0x46, 0xa9, 0xd5, 0x5d, 0xd7, 0xd4, 0x8d, 0xe4, 0x7d, 0xe4, 0x9e, 0x69, 0xaa, 0x55, 0x1f, + 0x51, 0x36, 0x85, 0xd5, 0x7e, 0xf0, 0xc8, 0x9d, 0xc2, 0x1f, 0x23, 0xc8, 0x33, 0x91, 0xe6, 0x40, + 0x3f, 0x20, 0xa5, 0x0b, 0x60, 0xb1, 0xcd, 0xb3, 0xb2, 0xb7, 0x35, 0xa1, 0xd3, 0x11, 0x3f, 0x45, + 0x52, 0x64, 0xc9, 0xff, 0xb1, 0xee, 0xbf, 0x7b, 0x64, 0xb5, 0x18, 0x90, 0x3e, 0x20, 0x15, 0x97, + 0x52, 0x33, 0x89, 0x5d, 0xb1, 0x1d, 0x74, 0x1c, 0xd3, 0x2d, 0x42, 0x6c, 0xc3, 0x68, 0xbb, 0x69, + 0xa1, 0xb2, 0x45, 0x8e, 0x63, 0xba, 0x41, 0x16, 0x73, 0xc5, 0x14, 0x60, 0x99, 0xcb, 0x91, 0x39, + 0x4c, 0xdf, 0xd0, 0xc2, 0x9b, 0x6e, 0xe8, 0x11, 0x59, 0x55, 0x92, 0xa5, 0x39, 0xe3, 0xca, 0x86, + 0x5f, 0xc4, 0x20, 0xd5, 0x31, 0xf4, 0x38, 0xae, 0xfd, 0x5d, 0x22, 0xeb, 0x53, 0x19, 0xd1, 0x4d, + 0x52, 0xce, 0x44, 0x53, 0xff, 0xae, 0x97, 0xfb, 0x3e, 0xfa, 0x2d, 0x67, 0xe2, 0x14, 0xcf, 0xd6, + 0x98, 0xf6, 0xba, 0xad, 0x61, 0x03, 0x2d, 0x67, 0xe2, 0x05, 0x9e, 0x75, 0x46, 0x58, 0xa6, 0x66, + 0xca, 0xba, 0xe0, 0x32, 0x42, 0xe4, 0x05, 0xeb, 0x02, 0x7d, 0x87, 0xac, 0x18, 0x73, 0xae, 0x24, + 0x80, 0xb2, 0x89, 0x55, 0x10, 0x3b, 0x45, 0x68, 0x14, 0x81, 0x27, 0x6a, 0x80, 0xad, 0xe1, 0x22, + 0x1c, 0x24, 0x6a, 0x40, 0xdf, 0x25, 0x55, 0x63, 0xfe, 0x2e, 0xc9, 0xb8, 0x88, 0xc1, 0xa6, 0x65, + 0xc2, 0xbe, 0x34, 0xd8, 0x88, 0xc4, 0x45, 0x2f, 0x55, 0x72, 0xe0, 0x97, 0xc6, 0x48, 0x07, 0x06, + 0xd3, 0x15, 0x92, 0xc0, 0x93, 0x2c, 0xd1, 0xd7, 0x83, 0x72, 0x97, 0x4c, 0x85, 0x86, 0x28, 0x4a, + 0x7e, 0x4c, 0x6e, 0x8d, 0x68, 0x56, 0xf6, 0x32, 0x12, 0xd7, 0x86, 0xb8, 0x95, 0x5e, 0x88, 0x88, + 0xf2, 0xcb, 0x13, 0x11, 0x31, 0x85, 0xa7, 0x64, 0x7d, 0x44, 0x73, 0x69, 0x10, 0x64, 0x8e, 0x7e, + 0xe5, 0x52, 0x29, 0x90, 0x5d, 0x3a, 0x95, 0x09, 0xb2, 0x4b, 0x29, 0x20, 0xcb, 0xbc, 0x27, 0x25, + 0xa4, 0x7c, 0xe0, 0xaf, 0x98, 0x9b, 0x71, 0xe7, 0x51, 0xe9, 0x59, 0x57, 0xb3, 0xfd, 0x6a, 0xe8, + 0x6d, 0xcf, 0xdb, 0xd2, 0xef, 0x23, 0xa4, 0x4b, 0x9f, 0x82, 0x72, 0x84, 0x55, 0x24, 0x94, 0x53, + 0x50, 0x23, 0xb3, 0x62, 0x7d, 0x67, 0x5e, 0x33, 0x66, 0xc5, 0xfa, 0xd6, 0x7c, 0x8f, 0x2c, 0x6b, + 0xb3, 0xd4, 0x0d, 0x7b, 0x0b, 0x8d, 0x4b, 0x8a, 0xf5, 0x23, 0xdd, 0xb2, 0xf7, 0x49, 0x79, 0xa8, + 0xd5, 0x5f, 0x37, 0x57, 0x3a, 0x04, 0x74, 0x9b, 0xa3, 0x0a, 0x9f, 0x9a, 0x36, 0xc7, 0xc3, 0xf8, + 0x1d, 0xa6, 0x8a, 0x71, 0xe5, 0xdf, 0x2e, 0xdc, 0x21, 0x62, 0x7a, 0x00, 0x73, 0xd1, 0xd5, 0xaf, + 0xc9, 0xdf, 0x30, 0x03, 0xd8, 0x1e, 0xe9, 0x27, 0xa4, 0x1a, 0x43, 0x27, 0xb9, 0x04, 0x39, 0x68, + 0xea, 0x61, 0xe2, 0xdf, 0xc1, 0xd7, 0x1c, 0xd4, 0xcd, 0x92, 0xa9, 0xbb, 0x25, 0x53, 0x3f, 0x73, + 0x4b, 0x26, 0x5a, 0x71, 0x0e, 0x87, 0x5a, 0xf3, 0xc7, 0x64, 0x45, 0xfb, 0x35, 0x39, 0x4e, 0xee, + 0xd8, 0xbf, 0x7b, 0xad, 0x7f, 0x45, 0xf3, 0xcd, 0xa0, 0xc7, 0xa7, 0x0d, 0x7d, 0x25, 0x59, 0x13, + 0x47, 0xc9, 0xff, 0x4c, 0xce, 0x88, 0xe8, 0x17, 0xb6, 0xf7, 0xf3, 0x22, 0x59, 0x3b, 0xb4, 0x83, + 0xe0, 0xd4, 0xec, 0x48, 0xfa, 0xa3, 0x47, 0x4a, 0xc6, 0x9d, 0x3e, 0x9e, 0x35, 0x74, 0x0a, 0xbb, + 0x24, 0x78, 0x38, 0x8b, 0xea, 0x06, 0x52, 0xed, 0xc3, 0xab, 0xfd, 0x20, 0xf0, 0x8d, 0x67, 0x1e, + 0xb2, 0xd0, 0xf9, 0x84, 0xe8, 0xf4, 0xfd, 0x1f, 0x7f, 0xfe, 0x34, 0x77, 0xbb, 0xb6, 0xda, 0x28, + 0x84, 0xfa, 0xc8, 0x7b, 0x42, 0x7f, 0xf5, 0x48, 0xc9, 0x4c, 0xe3, 0xd9, 0x9a, 0x0a, 0x4b, 0xe6, + 0x86, 0x9a, 0x0e, 0x50, 0x93, 0xf1, 0xfc, 0x17, 0x4d, 0x61, 0xb0, 0x59, 0xd4, 0xd4, 0x78, 0x35, + 0xda, 0x55, 0xaf, 0xb5, 0xc0, 0xdf, 0x3c, 0x5c, 0xf3, 0x76, 0x71, 0xd3, 0xc9, 0x69, 0x3d, 0xb5, + 0xd3, 0x6f, 0xa8, 0xed, 0xab, 0xab, 0xfd, 0x9d, 0xe0, 0xc9, 0x11, 0xa8, 0x90, 0x85, 0x79, 0x06, + 0x3c, 0x39, 0x4f, 0x78, 0x68, 0x27, 0x73, 0x28, 0xce, 0xdf, 0xac, 0xf6, 0x3d, 0xfa, 0x68, 0x86, + 0xda, 0xc6, 0x2b, 0xeb, 0xff, 0x9a, 0xfe, 0xe2, 0x91, 0xf9, 0x23, 0x50, 0xf4, 0xde, 0xb4, 0xda, + 0xb7, 0x93, 0x79, 0x7a, 0xb5, 0xbf, 0x1b, 0x3c, 0xd5, 0x32, 0xd5, 0x05, 0x84, 0xe6, 0xad, 0xab, + 0x6b, 0x75, 0x6e, 0xd1, 0x59, 0x55, 0x7d, 0xfe, 0x8c, 0xac, 0x73, 0xd1, 0x2d, 0xfe, 0xff, 0xf9, + 0x8a, 0xed, 0xd2, 0x13, 0xdd, 0xf7, 0x27, 0xde, 0xcb, 0xb5, 0x82, 0x39, 0x6b, 0xb5, 0x4a, 0xf8, + 0x22, 0xde, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0x50, 0xe0, 0xb3, 0xc0, 0x28, 0x0a, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json deleted file mode 100644 index 55aac60c7..000000000 --- a/protobufs/gen/swagger.json +++ /dev/null @@ -1 +0,0 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/documents/service.swagger.json b/protobufs/gen/swagger/document/service.swagger.json similarity index 99% rename from protobufs/gen/swagger/documents/service.swagger.json rename to protobufs/gen/swagger/document/service.swagger.json index b2bd4fde1..81a23ee2f 100644 --- a/protobufs/gen/swagger/documents/service.swagger.json +++ b/protobufs/gen/swagger/document/service.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "documents/service.proto", + "title": "document/service.proto", "version": "version not set" }, "schemes": [ diff --git a/protobufs/gen/swagger/invoice/service.swagger.json b/protobufs/gen/swagger/invoice/service.swagger.json index 96a0daaf5..c5f299e1b 100644 --- a/protobufs/gen/swagger/invoice/service.swagger.json +++ b/protobufs/gen/swagger/invoice/service.swagger.json @@ -131,6 +131,32 @@ } }, "definitions": { + "documentAccessTokenParams": { + "type": "object", + "properties": { + "grantee": { + "type": "string", + "title": "The identity being granted access to the document" + }, + "document_identifier": { + "type": "string", + "title": "Original identifier of the document" + } + } + }, + "documentUpdateAccessTokenPayload": { + "type": "object", + "properties": { + "delegating_document_identifier": { + "type": "string", + "title": "The document which should contain the access token referenced below" + }, + "access_token_params": { + "$ref": "#/definitions/documentAccessTokenParams", + "title": "The access token to be appended to the indicated document above" + } + } + }, "invoiceInvoiceCreatePayload": { "type": "object", "properties": { @@ -262,6 +288,9 @@ }, "data": { "$ref": "#/definitions/invoiceInvoiceData" + }, + "access_token_payload": { + "$ref": "#/definitions/documentUpdateAccessTokenPayload" } } }, @@ -287,7 +316,7 @@ "type": "string" } }, - "title": "ResponseHeader contains a set of common fields for most documents" + "title": "ResponseHeader contains a set of common fields for most document" } } } diff --git a/protobufs/gen/swagger/purchaseorder/service.swagger.json b/protobufs/gen/swagger/purchaseorder/service.swagger.json index 143880d90..9d922d72d 100644 --- a/protobufs/gen/swagger/purchaseorder/service.swagger.json +++ b/protobufs/gen/swagger/purchaseorder/service.swagger.json @@ -131,6 +131,32 @@ } }, "definitions": { + "documentAccessTokenParams": { + "type": "object", + "properties": { + "grantee": { + "type": "string", + "title": "The identity being granted access to the document" + }, + "document_identifier": { + "type": "string", + "title": "Original identifier of the document" + } + } + }, + "documentUpdateAccessTokenPayload": { + "type": "object", + "properties": { + "delegating_document_identifier": { + "type": "string", + "title": "The document which should contain the access token referenced below" + }, + "access_token_params": { + "$ref": "#/definitions/documentAccessTokenParams", + "title": "The access token to be appended to the indicated document above" + } + } + }, "purchaseorderPurchaseOrderCreatePayload": { "type": "object", "properties": { @@ -265,6 +291,9 @@ }, "data": { "$ref": "#/definitions/purchaseorderPurchaseOrderData" + }, + "access_token_payload": { + "$ref": "#/definitions/documentUpdateAccessTokenPayload" } } }, diff --git a/protobufs/invoice/service.proto b/protobufs/invoice/service.proto index 6796074c2..a0e11808e 100644 --- a/protobufs/invoice/service.proto +++ b/protobufs/invoice/service.proto @@ -7,11 +7,12 @@ option java_multiple_files = true; option java_outer_classname = "ServiceProto"; option java_package = "com.invoice"; +import "document/service.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-swagger/options/annotations.proto"; -// DocumentService contains all common interactions for invoice documents +// DocumentService contains all common interactions for invoice document service DocumentService { rpc Create(InvoiceCreatePayload) returns (InvoiceResponse) { option (google.api.http) = { @@ -67,6 +68,7 @@ message InvoiceUpdatePayload { string identifier = 1; repeated string collaborators = 2; InvoiceData data = 3; + document.UpdateAccessTokenPayload access_token_payload = 4; } message InvoiceResponse { @@ -74,7 +76,7 @@ message InvoiceResponse { InvoiceData data = 2; } -// ResponseHeader contains a set of common fields for most documents +// ResponseHeader contains a set of common fields for most document message ResponseHeader { string document_id = 1; string version_id = 2; diff --git a/protobufs/purchaseorder/service.proto b/protobufs/purchaseorder/service.proto index 952fb6093..c2acf79db 100644 --- a/protobufs/purchaseorder/service.proto +++ b/protobufs/purchaseorder/service.proto @@ -7,6 +7,7 @@ option java_multiple_files = true; option java_outer_classname = "ServiceProto"; option java_package = "com.purchaseorder"; +import "document/service.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-swagger/options/annotations.proto"; @@ -67,6 +68,7 @@ message PurchaseOrderUpdatePayload { string identifier = 1; repeated string collaborators = 2; PurchaseOrderData data = 3; + document.UpdateAccessTokenPayload access_token_payload = 4; } message PurchaseOrderResponse { From b2caf95d51ed6530d97de65b109794d2eff615bc Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Tue, 29 Jan 2019 22:36:33 +0530 Subject: [PATCH 168/220] Feat/nft document update (#663) * add nft owner of * add nft checks * fix unit tests * fix integration tests * minor refactor * more tests * unneded logging * add chian task to eth task * Update coredocument/read_acls.go Co-Authored-By: vedhavyas * add nft update task * minor refactroing * add chian task to eth task * add nft update task * update service * add nft created task * fix data race * fix tetss * fix unit tests and integrartion tests * add nft created test * Transaction manager update * compile fix * Fix tests * Tests and fixes * review comment * Minor update * Fix bug * Fix race * Fix role key bug * Fix unit test * Review comments * Fix testworld cleanup * Fix testworld cleanup --- anchors/anchor_repository_integration_test.go | 6 +- api/service.go | 2 +- build/scripts/tests/run_testworld.sh | 2 +- contextutil/context.go | 18 ++ coredocument/coredocument_test.go | 4 +- coredocument/read_acls.go | 19 +- coredocument/read_acls_test.go | 6 +- documents/anchor.go | 1 + documents/anchor_task.go | 30 ++- documents/anchor_task_test.go | 10 +- documents/bootstrapper.go | 16 +- documents/bootstrapper_test.go | 2 +- documents/documents_test/anchor_test.go | 2 +- documents/documents_test/service_test.go | 26 +-- documents/invoice/bootstrapper.go | 4 +- documents/invoice/handler_test.go | 18 +- documents/invoice/model.go | 21 ++- documents/invoice/model_test.go | 4 +- documents/invoice/service.go | 20 +- documents/invoice/service_test.go | 26 ++- documents/invoice/validator_test.go | 2 +- documents/nft_created_task.go | 173 ++++++++++++++++++ documents/nft_created_task_test.go | 52 ++++++ documents/processor_test.go | 10 +- documents/purchaseorder/bootstrapper.go | 4 +- documents/purchaseorder/handler_test.go | 21 +-- documents/purchaseorder/model.go | 21 ++- documents/purchaseorder/model_test.go | 4 +- documents/purchaseorder/service.go | 12 +- documents/purchaseorder/service_test.go | 28 +-- documents/purchaseorder/validator_test.go | 2 +- documents/service.go | 1 - documents/validator_test.go | 4 +- ethereum/bootstrapper.go | 18 +- ethereum/geth_client.go | 56 ++---- ethereum/geth_client_integration_test.go | 8 +- ethereum/transaction_status_task.go | 55 +++--- ...ransaction_status_task_integration_test.go | 24 +-- .../ethereum_identity_integration_test.go | 8 +- nft/bootstrapper.go | 12 +- nft/ethereum_payment_obligation.go | 111 ++++++++--- nft/ethereum_payment_obligation_test.go | 67 +++++-- nft/handler.go | 6 +- nft/payment_obligation_integration_test.go | 26 ++- notification/notification_test.go | 2 +- p2p/client_integration_test.go | 6 +- p2p/client_test.go | 6 +- p2p/receiver/handler_integration_test.go | 22 +-- p2p/receiver/handler_test.go | 12 +- testingutils/commons/mock_ethclient.go | 9 - testingutils/config/config.go | 2 +- testingutils/identity/identity.go | 2 +- testworld/README.md | 2 +- transactions/base_task.go | 48 +++-- transactions/base_task_test.go | 28 ++- transactions/bootstrapper.go | 4 +- transactions/handler.go | 4 +- transactions/handler_test.go | 4 +- transactions/manager.go | 143 +++++++++++++++ .../{service_test.go => manager_test.go} | 58 +++++- transactions/repository_test.go | 2 +- transactions/service.go | 91 --------- transactions/transaction.go | 20 +- 63 files changed, 953 insertions(+), 474 deletions(-) create mode 100644 documents/nft_created_task.go create mode 100644 documents/nft_created_task_test.go create mode 100644 transactions/manager.go rename transactions/{service_test.go => manager_test.go} (55%) delete mode 100644 transactions/service.go diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index 3262184fa..a6a8970e3 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -39,7 +39,7 @@ func TestMain(m *testing.M) { func createIdentityWithKeys(t *testing.T, centrifugeId []byte) []byte { centIdTyped, _ := identity.ToCentID(centrifugeId) cfg.Set("identityId", centIdTyped.String()) - id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centIdTyped) + id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centIdTyped) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") @@ -81,7 +81,7 @@ func commitAnchor(t *testing.T, anchorID, centrifugeId, documentRoot, signature centIdFixed, _ := identity.ToCentID(centrifugeId) cfg.Set("identityId", centIdFixed.String()) - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) confirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) @@ -111,7 +111,7 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { assert.Nil(t, err, " error must be nil") commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) cfg.Set("identityId", centIdFixed.String()) - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) confirmationList[ix], err = anchorRepo.CommitAnchor(ctx, currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) if err != nil { t.Fatalf("Error commit Anchor %v", err) diff --git a/api/service.go b/api/service.go index dd92fde56..88f3a7449 100644 --- a/api/service.go +++ b/api/service.go @@ -108,7 +108,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, } // transactions - txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Service) + txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Manager) h := transactions.GRPCHandler(txSrv, configService) transactionspb.RegisterTransactionServiceServer(grpcServer, h) if err := transactionspb.RegisterTransactionServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts); err != nil { diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index 7c6fce4e6..b6fb8d9c9 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -2,7 +2,7 @@ echo "Running Testworld" -cleanup="ls testworld/peerconfigs/* | grep testworld | grep -v README.md | tr -d : | xargs rm -rf" +cleanup="ls testworld/hostconfigs/* | grep testworld | grep -v README.md | tr -d : | xargs rm -rf" eval "$cleanup" diff --git a/contextutil/context.go b/contextutil/context.go index 75c64b962..5968df10e 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/satori/go.uuid" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/centrifuge/go-centrifuge/config" @@ -23,6 +25,8 @@ const ( ErrSelfNotFound = errors.Error("self value not found in the context") self = contextKey("self") + + tx = contextKey("tx") ) // New creates new instance of the request headers. @@ -30,6 +34,11 @@ func New(ctx context.Context, cfg config.Account) (context.Context, error) { return context.WithValue(ctx, self, cfg), nil } +// WithTX returns a context with TX ID +func WithTX(ctx context.Context, txID uuid.UUID) context.Context { + return context.WithValue(ctx, tx, txID) +} + // Self returns Self CentID. func Self(ctx context.Context) (*identity.IDConfig, error) { tc, ok := ctx.Value(self).(config.Account) @@ -39,6 +48,15 @@ func Self(ctx context.Context) (*identity.IDConfig, error) { return identity.GetIdentityConfig(tc) } +// TX returns current txID +func TX(ctx context.Context) uuid.UUID { + tid, ok := ctx.Value(tx).(uuid.UUID) + if !ok { + return uuid.Nil + } + return tid +} + // Account extracts the TenanConfig from the given context value func Account(ctx context.Context) (config.Account, error) { tc, ok := ctx.Value(self).(config.Account) diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 77be13963..41e90a81c 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -237,7 +237,7 @@ func TestGetExternalCollaborators(t *testing.T) { c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - self, err := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + self, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) assert.NoError(t, err) collaborators, err := GetExternalCollaborators(self.ID, cd) assert.Nil(t, err) @@ -252,7 +252,7 @@ func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { cd, err := NewWithCollaborators(c) assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) cd.Collaborators[1] = utils.RandomSlice(5) - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) _, err = GetExternalCollaborators(self.ID, cd) assert.NotNil(t, err) } diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go index 41c031587..ad5e2c32d 100644 --- a/coredocument/read_acls.go +++ b/coredocument/read_acls.go @@ -72,21 +72,26 @@ func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, acti cd.ReadRules = append(cd.ReadRules, rule) } -// addNFTToReadRules adds NFT token to the read rules of core document. -func addNFTToReadRules(cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte) error { - nft, err := constructNFT(registry, tokenID) +// AddNFTToReadRules adds NFT token to the read rules of core document. +func AddNFTToReadRules(cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte) error { + nft, err := ConstructNFT(registry, tokenID) if err != nil { return errors.New("failed to construct NFT: %v", err) } role := new(coredocumentpb.Role) + rk, err := utils.ConvertIntToByte32(len(cd.Roles)) + if err != nil { + return err + } + role.RoleKey = rk[:] role.Nfts = append(role.Nfts, nft) addNewRule(cd, role, coredocumentpb.Action_ACTION_READ) - return nil + return FillSalts(cd) } -// constructNFT appends registry and tokenID to byte slice -func constructNFT(registry common.Address, tokenID []byte) ([]byte, error) { +// ConstructNFT appends registry and tokenID to byte slice +func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { var nft []byte // first 20 bytes of registry nft = append(nft, registry.Bytes()...) @@ -225,7 +230,7 @@ func findRole( // isNFTInRole checks if the given nft(registry + token) is part of the core document role. func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) bool { - enft, err := constructNFT(registry, tokenID) + enft, err := ConstructNFT(registry, tokenID) if err != nil { return false } diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go index 369023f1b..44e10373b 100644 --- a/coredocument/read_acls_test.go +++ b/coredocument/read_acls_test.go @@ -55,7 +55,7 @@ func Test_addNFTToReadRules(t *testing.T) { registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") tokenID := utils.RandomSlice(34) - err := addNFTToReadRules(nil, registry, tokenID) + err := AddNFTToReadRules(nil, registry, tokenID) assert.Error(t, err) cd, err := NewWithCollaborators([]string{"0x010203040506"}) @@ -65,7 +65,7 @@ func Test_addNFTToReadRules(t *testing.T) { assert.Len(t, cd.Roles, 1) tokenID = utils.RandomSlice(32) - err = addNFTToReadRules(cd, registry, tokenID) + err = AddNFTToReadRules(cd, registry, tokenID) assert.NoError(t, err) assert.Len(t, cd.ReadRules, 2) assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) @@ -105,7 +105,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { tr := mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() - addNFTToReadRules(cd, registry, tokenID) + AddNFTToReadRules(cd, registry, tokenID) validator = NftValidator(tr) err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) assert.Error(t, err) diff --git a/documents/anchor.go b/documents/anchor.go index 9369af82d..1143d0838 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -61,6 +61,7 @@ func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, upda return nil, err } + // TODO [TXManager] this function creates a child task in the queue which should be removed and called from the TxManger function err = proc.AnchorDocument(ctx, model) if err != nil { return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to anchor document: %v", err)) diff --git a/documents/anchor_task.go b/documents/anchor_task.go index f4c959f8a..8cae7fd68 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -19,8 +19,12 @@ import ( ) const ( - modelIDParam = "modelID" - accountIDParam = "accountID" + // DocumentIDParam maps to model ID in the kwargs + DocumentIDParam = "documentID" + + // AccountIDParam maps to account ID in the kwargs + AccountIDParam = "accountID" + documentAnchorTaskName = "Document Anchoring" ) @@ -51,7 +55,7 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { return err } - modelID, ok := kwargs[modelIDParam].(string) + modelID, ok := kwargs[DocumentIDParam].(string) if !ok { return errors.New("missing model ID") } @@ -61,7 +65,7 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { return errors.New("invalid model ID") } - accountID, ok := kwargs[accountIDParam].(string) + accountID, ok := kwargs[AccountIDParam].(string) if !ok { return errors.New("missing account ID") } @@ -76,7 +80,7 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { // Copy returns a new task with state. func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { return &documentAnchorTask{ - BaseTask: transactions.BaseTask{TxService: d.TxService}, + BaseTask: transactions.BaseTask{TxManager: d.TxManager}, config: d.config, processor: d.processor, modelGetFunc: d.modelGetFunc, @@ -116,16 +120,24 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { } // InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. -func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Service, accountID identity.CentID, modelID []byte) (uuid.UUID, error) { - tx, err := txService.CreateTransaction(accountID, documentAnchorTaskName) +// TODO [TXManager] migrate this to use TxManager +func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Manager, accountID identity.CentID, modelID []byte, txID uuid.UUID) (uuid.UUID, error) { + var tx *transactions.Transaction + var err error + if txID != uuid.Nil { + tx, err = txService.GetTransaction(accountID, txID) + } else { + tx, err = txService.CreateTransaction(accountID, documentAnchorTaskName) + } + if err != nil { return uuid.Nil, err } params := map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), - modelIDParam: hexutil.Encode(modelID), - accountIDParam: accountID.String(), + DocumentIDParam: hexutil.Encode(modelID), + AccountIDParam: accountID.String(), } _, err = tq.EnqueueJob(documentAnchorTaskName, params) diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index 77a9104d5..509a976bc 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -43,7 +43,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { { kwargs: map[string]interface{}{ transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), - modelIDParam: hexutil.Encode(utils.RandomSlice(32)), + DocumentIDParam: hexutil.Encode(utils.RandomSlice(32)), }, err: "missing account ID", @@ -54,8 +54,8 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { name: "success", kwargs: map[string]interface{}{ transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), - modelIDParam: hexutil.Encode(utils.RandomSlice(32)), - accountIDParam: identity.RandomCentID().String(), + DocumentIDParam: hexutil.Encode(utils.RandomSlice(32)), + AccountIDParam: identity.RandomCentID().String(), }, }, } @@ -76,8 +76,8 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { err = task.ParseKwargs(d) if c.err == "" { assert.Equal(t, task.TxID.String(), c.kwargs[transactions.TxIDParam]) - assert.Equal(t, hexutil.Encode(task.id), c.kwargs[modelIDParam]) - assert.Equal(t, task.accountID.String(), c.kwargs[accountIDParam]) + assert.Equal(t, hexutil.Encode(task.id), c.kwargs[DocumentIDParam]) + assert.Equal(t, task.accountID.String(), c.kwargs[AccountIDParam]) return } diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index ed0b443af..8f098da69 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -91,15 +91,25 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("p2p client not initialised") } - task := &documentAnchorTask{ + txMan := ctx[transactions.BootstrappedService].(transactions.Manager) + anchorTask := &documentAnchorTask{ BaseTask: transactions.BaseTask{ - TxService: ctx[transactions.BootstrappedService].(transactions.Service), + TxManager: txMan, }, config: cfgService, processor: DefaultProcessor(idService, p2pClient, anchorRepo, cfg), modelGetFunc: repo.Get, modelSaveFunc: repo.Update, } - queueSrv.RegisterTaskType(documentAnchorTaskName, task) + + nftTask := &nftCreatedTask{ + BaseTask: transactions.BaseTask{ + TxManager: txMan, + }, + docSrv: ctx[BootstrappedDocumentService].(Service), + cfgSrv: cfgService, + } + queueSrv.RegisterTaskType(documentAnchorTaskName, anchorTask) + queueSrv.RegisterTaskType(nftCreatedTaskName, nftTask) return nil } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index affbedee8..4a43a6bd6 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -25,7 +25,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { repo := leveldb.NewLevelDBRepository(db) ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo - ctx[transactions.BootstrappedService] = transactions.NewService(transactions.NewRepository(repo)) + ctx[transactions.BootstrappedService] = transactions.NewManager(transactions.NewRepository(repo)) ctx[identity.BootstrappedIDService] = new(testingcommons.MockIDService) ctx[anchors.BootstrappedAnchorRepo] = new(testinganchors.MockAnchorRepo) err = Bootstrapper{}.Bootstrap(ctx) diff --git a/documents/documents_test/anchor_test.go b/documents/documents_test/anchor_test.go index a8265240b..41c2a285d 100644 --- a/documents/documents_test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -71,7 +71,7 @@ func (m *mockAnchorProcessor) GetDataProofHashes(coreDocument *coredocumentpb.Co } func TestAnchorDocument(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) updater := func(id []byte, model documents.Model) error { return nil } diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index 52fcbd633..314f9295e 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -57,7 +57,7 @@ func TestMain(m *testing.M) { func TestService_ReceiveAnchoredDocument(t *testing.T) { poSrv := documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } @@ -197,7 +197,7 @@ func TestService_CreateProofs(t *testing.T) { service, idService := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) idService = mockSignatureCheck(i, idService, service) proof, err := service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) @@ -214,7 +214,7 @@ func TestService_CreateProofsValidationFails(t *testing.T) { err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") @@ -225,7 +225,7 @@ func TestService_CreateProofsInvalidField(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) @@ -233,7 +233,7 @@ func TestService_CreateProofsInvalidField(t *testing.T) { func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { service, _ := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err := service.CreateProofs(ctxh, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) @@ -247,7 +247,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { olderVersion := i.CoreDocument.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) proof, err := service.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) @@ -262,7 +262,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) i.CoreDocument.SigningRoot = nil - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) @@ -273,7 +273,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { i, err := createAnchoredMockDocument(t, false) s, _ := getServiceWithMockedLayers() assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err = s.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) @@ -314,7 +314,7 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { } - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) model, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.Nil(t, err) @@ -338,7 +338,7 @@ func TestService_GetVersion_successful(t *testing.T) { }, } - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) err := testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) @@ -357,7 +357,7 @@ func TestService_GetCurrentVersion_error(t *testing.T) { documentIdentifier := utils.RandomSlice(32) //document is not existing - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) @@ -384,7 +384,7 @@ func TestService_GetVersion_error(t *testing.T) { currentVersion := utils.RandomSlice(32) //document is not existing - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) @@ -422,7 +422,7 @@ func testRepo() documents.Repository { func TestService_Exists(t *testing.T) { service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) //document is not existing _, err := service.GetCurrentVersion(ctxh, documentIdentifier) diff --git a/documents/invoice/bootstrapper.go b/documents/invoice/bootstrapper.go index 6c846a04a..fb35b7ca8 100644 --- a/documents/invoice/bootstrapper.go +++ b/documents/invoice/bootstrapper.go @@ -41,7 +41,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("queue server not initialised") } - txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + txManager, ok := ctx[transactions.BootstrappedService].(transactions.Manager) if !ok { return errors.New("transaction service not initialised") } @@ -55,7 +55,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { srv := DefaultService( docSrv, repo, - queueSrv, txService) + queueSrv, txManager) err := registry.Register(documenttypes.InvoiceDataTypeUrl, srv) if err != nil { diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index abb35e2f8..2ae1b5f8c 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -29,11 +31,10 @@ func (m *mockService) DeriveFromCreatePayload(ctx context.Context, payload *clie return model, args.Error(1) } -func (m *mockService) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { - args := m.Called(ctx, inv) - model, _ := args.Get(0).(documents.Model) - txID, _ := uuid.FromString(args.Get(1).(string)) - return model, txID, args.Error(2) +func (m *mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, model) + model, _ = args.Get(0).(documents.Model) + return model, contextutil.TX(ctx), args.Error(2) } func (m *mockService) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { @@ -60,11 +61,10 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { - args := m.Called(ctx, doc) +func (m *mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, model) doc1, _ := args.Get(0).(documents.Model) - txID, _ := uuid.FromString(args.Get(1).(string)) - return doc1, txID, args.Error(2) + return doc1, contextutil.TX(ctx), args.Error(2) } func (m *mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index b9b4f0773..5e99f08d8 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -306,9 +306,7 @@ func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error } if coreDoc.EmbeddedData == nil || - coreDoc.EmbeddedData.TypeUrl != documenttypes.InvoiceDataTypeUrl || - coreDoc.EmbeddedDataSalts == nil || - coreDoc.EmbeddedDataSalts.TypeUrl != documenttypes.InvoiceSaltsTypeUrl { + coreDoc.EmbeddedData.TypeUrl != documenttypes.InvoiceDataTypeUrl { return errors.New("trying to convert document with incorrect schema") } @@ -319,13 +317,18 @@ func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error } i.loadFromP2PProtobuf(invoiceData) - invoiceSalts := &invoicepb.InvoiceDataSalts{} - err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, invoiceSalts) - if err != nil { - return err - } - i.InvoiceSalts = invoiceSalts + if coreDoc.EmbeddedDataSalts == nil { + i.InvoiceSalts = i.getInvoiceSalts(invoiceData) + } else { + invoiceSalts := new(invoicepb.InvoiceDataSalts) + err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, invoiceSalts) + if err != nil { + return err + } + + i.InvoiceSalts = invoiceSalts + } i.CoreDocument = new(coredocumentpb.CoreDocument) proto.Merge(i.CoreDocument, coreDoc) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index e7b156892..8d1170c23 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -197,7 +197,7 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) // fail recipient data := &clientinvoicepb.InvoiceData{ Sender: "some number", @@ -255,7 +255,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) m := new(Invoice) err := m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 9821af454..6a8629903 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -39,7 +39,7 @@ type service struct { documents.Service repo documents.Repository queueSrv queue.TaskQueuer - txService transactions.Service + txManager transactions.Manager } // DefaultService returns the default implementation of the service. @@ -47,12 +47,12 @@ func DefaultService( srv documents.Service, repo documents.Repository, queueSrv queue.TaskQueuer, - txService transactions.Service, + txManager transactions.Manager, ) Service { return service{ repo: repo, queueSrv: queueSrv, - txService: txService, + txManager: txManager, Service: srv, } } @@ -138,11 +138,12 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask( + txID := contextutil.TX(ctx) + txID, err = documents.InitDocumentAnchorTask( s.queueSrv, - s.txService, + s.txManager, self.ID, - cd.CurrentVersion) + cd.CurrentVersion, txID) if err != nil { return nil, uuid.Nil, err } @@ -172,11 +173,12 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask( + txID := contextutil.TX(ctx) + txID, err = documents.InitDocumentAnchorTask( s.queueSrv, - s.txService, + s.txManager, self.ID, - cd.CurrentVersion) + cd.CurrentVersion, txID) if err != nil { return nil, uuid.Nil, err } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 73d7f5e82..d94d86108 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -31,8 +31,6 @@ var ( cid = identity.RandomCentID() centIDBytes = cid[:] accountID = cid[:] - key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} ) type mockAnchorRepo struct { @@ -68,7 +66,7 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { docSrv, repo, queueSrv, - ctx[transactions.BootstrappedService].(transactions.Service)) + ctx[transactions.BootstrappedService].(transactions.Manager)) } func createMockDocument() (*Invoice, error) { @@ -121,7 +119,7 @@ func TestService_DeriveFromPayload(t *testing.T) { _, err = invSrv.DeriveFromCreatePayload(nil, &clientinvoicepb.InvoiceCreatePayload{}) assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - model, err = invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) + model, err = invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") receivedCoreDocument, err := model.PackCoreDocument() @@ -135,7 +133,7 @@ func TestService_GetLastVersion(t *testing.T) { doc, err := createMockDocument() assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) mod1, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) @@ -178,7 +176,7 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err = invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Error(t, err) @@ -198,7 +196,7 @@ func TestService_GetVersion(t *testing.T) { err := testRepo().Create(accountID, currentVersion, inv) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) mod, err := invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadInv, _ := mod.(*Invoice) @@ -222,7 +220,7 @@ func TestService_Exists(t *testing.T) { err := testRepo().Create(accountID, documentIdentifier, inv) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) exists := invSrv.Exists(ctxh, documentIdentifier) assert.True(t, exists, "invoice should exist") @@ -232,7 +230,7 @@ func TestService_Exists(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, srv := getServiceWithMockedLayers() invSrv := srv.(service) @@ -262,7 +260,7 @@ func TestService_DeriveInvoiceData(t *testing.T) { // success payload := testingdocuments.CreateInvoicePayload() - inv, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) + inv, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err, "must be non nil") data, err := invSrv.DeriveInvoiceData(inv) assert.Nil(t, err, "Derive must succeed") @@ -273,7 +271,7 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { // success invSrv := service{repo: testRepo()} payload := testingdocuments.CreateInvoicePayload() - inv1, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) + inv1, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err, "must be non nil") inv, ok := inv1.(*Invoice) assert.True(t, ok) @@ -301,7 +299,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader := testingconfig.CreateTenantContext(t, cfg) + contextHeader := testingconfig.CreateAccountContext(t, cfg) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "some identifier", Data: &clientinvoicepb.InvoiceData{}} doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) @@ -371,7 +369,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_Update(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed model := &mockModel{} @@ -440,7 +438,7 @@ func TestService_Update(t *testing.T) { func TestService_calculateDataRoot(t *testing.T) { _, srv := getServiceWithMockedLayers() invSrv := srv.(service) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // type mismatch inv, err := invSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index 728f190ce..f2ad3bfd1 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -82,7 +82,7 @@ func TestDataRootValidation_Validate(t *testing.T) { assert.Contains(t, err.Error(), "unknown document type") // mismatch - id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) inv := new(Invoice) err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) assert.Nil(t, err) diff --git a/documents/nft_created_task.go b/documents/nft_created_task.go new file mode 100644 index 000000000..2864e8065 --- /dev/null +++ b/documents/nft_created_task.go @@ -0,0 +1,173 @@ +package documents + +import ( + "context" + "fmt" + + "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/code" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/gocelery" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/satori/go.uuid" +) + +const ( + // nftCreatedTaskName is the name of the NFT Task + nftCreatedTaskName string = "NFT created task" + + // TokenRegistryParam maps to token registry address + TokenRegistryParam string = "Token Registry" + + // TokenIDParam maps to NFT token ID + TokenIDParam string = "Token ID" +) + +type nftCreatedTask struct { + transactions.BaseTask + accountID identity.CentID + documentID []byte + tokenRegistry common.Address + tokenID []byte + + // state + docSrv Service + cfgSrv config.Service +} + +func (t *nftCreatedTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + err = t.ParseTransactionID(kwargs) + if err != nil { + return err + } + + acc, ok := kwargs[AccountIDParam].(string) + if !ok { + return errors.New("account identifier not set") + } + + t.accountID, err = identity.CentIDFromString(acc) + if err != nil { + return errors.New("invalid accountID") + } + + vr, ok := kwargs[DocumentIDParam].(string) + if !ok { + return errors.New("model identifier not set") + } + + t.documentID, err = hexutil.Decode(vr) + if err != nil { + return err + } + + tr, ok := kwargs[TokenRegistryParam].(string) + if !ok { + return errors.New("token registry not set") + } + + t.tokenRegistry = common.HexToAddress(tr) + + tidr, ok := kwargs[TokenIDParam].(string) + if !ok { + return errors.New("token ID not set") + } + + t.tokenID, err = hexutil.Decode(tidr) + if err != nil { + return err + } + + return nil +} + +func (t *nftCreatedTask) Copy() (gocelery.CeleryTask, error) { + return &nftCreatedTask{ + BaseTask: t.BaseTask, + docSrv: t.docSrv, + cfgSrv: t.cfgSrv, + }, nil +} + +func (t *nftCreatedTask) RunTask() (result interface{}, err error) { + defer func() { + err = t.UpdateTransaction(t.accountID, t.TaskTypeName(), err) + }() + + tc, err := t.cfgSrv.GetAccount(t.accountID[:]) + if err != nil { + apiLog.Error(err) + return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) + } + + ctx, err := contextutil.New(context.Background(), tc) + if err != nil { + return false, errors.New("failed to get context header: %v", err) + } + + model, err := t.docSrv.GetCurrentVersion(ctx, t.documentID) + if err != nil { + return nil, err + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + + data := cd.EmbeddedData + cd, err = coredocument.PrepareNewVersion(*cd, nil) + if err != nil { + return nil, err + } + + cd.EmbeddedData = data + err = coredocument.AddNFTToReadRules(cd, t.tokenRegistry, t.tokenID) + if err != nil { + return nil, err + } + + model, err = t.docSrv.DeriveFromCoreDocument(cd) + if err != nil { + return nil, err + } + + _, _, err = t.docSrv.Update(contextutil.WithTX(ctx, t.TxID), model) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (t *nftCreatedTask) TaskTypeName() string { + return nftCreatedTaskName +} + +// InitNFTCreatedTask initiates a new nft created task +func InitNFTCreatedTask( + queuer queue.TaskQueuer, + txID uuid.UUID, + cid identity.CentID, + documentID []byte, + registry common.Address, + tokenID []byte, +) (queue.TaskResult, error) { + log.Infof("Starting NFT created task: %v\n", txID.String()) + return queuer.EnqueueJob(nftCreatedTaskName, map[string]interface{}{ + transactions.TxIDParam: txID.String(), + transactions.TxNextTask: true, + AccountIDParam: cid.String(), + DocumentIDParam: hexutil.Encode(documentID), + TokenRegistryParam: registry.String(), + TokenIDParam: hexutil.Encode(tokenID), + }) +} diff --git a/documents/nft_created_task_test.go b/documents/nft_created_task_test.go new file mode 100644 index 000000000..d7d2bcc58 --- /dev/null +++ b/documents/nft_created_task_test.go @@ -0,0 +1,52 @@ +// +build unit + +package documents + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/assert" +) + +func TestNftCreatedTask_ParseKwargs(t *testing.T) { + task := new(nftCreatedTask) + m := make(map[string]interface{}) + + // no transactions + assert.Error(t, task.ParseKwargs(m)) + + // no account + m[transactions.TxIDParam] = uuid.Must(uuid.NewV4()).String() + assert.Error(t, task.ParseKwargs(m)) + + // wrong format + m[AccountIDParam] = "0x1002030405" + assert.Error(t, task.ParseKwargs(m)) + + // no document + m[AccountIDParam] = "0x010203040506" + assert.Error(t, task.ParseKwargs(m)) + + // hex fails + m[DocumentIDParam] = "sfkvfj" + assert.Error(t, task.ParseKwargs(m)) + + // missing registry + m[DocumentIDParam] = hexutil.Encode(utils.RandomSlice(32)) + assert.Error(t, task.ParseKwargs(m)) + + // missing token ID + m[TokenRegistryParam] = "0xf72855759a39fb75fc7341139f5d7a3974d4da08" + assert.Error(t, task.ParseKwargs(m)) + + // hex util fails + m[TokenIDParam] = "lkfv" + assert.Error(t, task.ParseKwargs(m)) + + m[TokenIDParam] = hexutil.Encode(utils.RandomSlice(32)) + assert.NoError(t, task.ParseKwargs(m)) +} diff --git a/documents/processor_test.go b/documents/processor_test.go index 431935880..e8a2be3f5 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -49,7 +49,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) err := dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -71,7 +71,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() cfg.Set("keys.signing.publicKey", pub) - ctxh = testingconfig.CreateTenantContext(t, cfg) + ctxh = testingconfig.CreateAccountContext(t, cfg) // failed unpack model = mockModel{} @@ -110,7 +110,7 @@ func (p p2pClient) GetSignaturesForDocument(ctx context.Context, doc *coredocume func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() @@ -256,7 +256,7 @@ func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.Document func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed model := mockModel{} @@ -350,7 +350,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv := &testingcommons.MockIDService{} srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() diff --git a/documents/purchaseorder/bootstrapper.go b/documents/purchaseorder/bootstrapper.go index f2c10f89a..87eae8b52 100644 --- a/documents/purchaseorder/bootstrapper.go +++ b/documents/purchaseorder/bootstrapper.go @@ -41,7 +41,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("queue server not initialised") } - txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + txManager, ok := ctx[transactions.BootstrappedService].(transactions.Manager) if !ok { return errors.New("transaction service not initialised") } @@ -52,7 +52,7 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } // register service - srv := DefaultService(docSrv, repo, queueSrv, txService) + srv := DefaultService(docSrv, repo, queueSrv, txManager) err := registry.Register(documenttypes.PurchaseOrderDataTypeUrl, srv) if err != nil { return errors.New("failed to register purchase order service") diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index b585d7554..48234c19d 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,12 +6,13 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/satori/go.uuid" @@ -24,18 +25,16 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { - args := m.Called(ctx, doc) - model, _ := args.Get(0).(documents.Model) - txID, _ := uuid.FromString(args.Get(1).(string)) - return model, txID, args.Error(2) +func (m mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, model) + model, _ = args.Get(0).(documents.Model) + return model, contextutil.TX(ctx), args.Error(2) } -func (m mockService) Update(ctx context.Context, doc documents.Model) (documents.Model, uuid.UUID, error) { - args := m.Called(ctx, doc) - model, _ := args.Get(0).(documents.Model) - txID, _ := uuid.FromString(args.Get(1).(string)) - return model, txID, args.Error(2) +func (m mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { + args := m.Called(ctx, model) + model, _ = args.Get(0).(documents.Model) + return model, contextutil.TX(ctx), args.Error(2) } func (m mockService) DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) { diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 56e2870da..7a0a1c7e8 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -293,9 +293,7 @@ func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) } if coreDoc.EmbeddedData == nil || - coreDoc.EmbeddedData.TypeUrl != documenttypes.PurchaseOrderDataTypeUrl || - coreDoc.EmbeddedDataSalts == nil || - coreDoc.EmbeddedDataSalts.TypeUrl != documenttypes.PurchaseOrderSaltsTypeUrl { + coreDoc.EmbeddedData.TypeUrl != documenttypes.PurchaseOrderDataTypeUrl { return errors.New("trying to convert document with incorrect schema") } @@ -306,13 +304,18 @@ func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) } p.loadFromP2PProtobuf(poData) - poSalt := &purchaseorderpb.PurchaseOrderDataSalts{} - err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, poSalt) - if err != nil { - return err - } - p.PurchaseOrderSalt = poSalt + if coreDoc.EmbeddedDataSalts == nil { + p.PurchaseOrderSalt = p.getPurchaseOrderSalts(poData) + } else { + poSalt := &purchaseorderpb.PurchaseOrderDataSalts{} + err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, poSalt) + if err != nil { + return err + } + + p.PurchaseOrderSalt = poSalt + } p.CoreDocument = new(coredocumentpb.CoreDocument) proto.Merge(p.CoreDocument, coreDoc) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index d606a7fba..87a8e4de9 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -193,7 +193,7 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "some recipient", @@ -230,7 +230,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { } func TestPOModel_calculateDataRoot(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) poModel := new(PurchaseOrder) err := poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 7165692ba..432016c40 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -39,7 +39,7 @@ type service struct { documents.Service repo documents.Repository queueSrv queue.TaskQueuer - txService transactions.Service + txManager transactions.Manager } // DefaultService returns the default implementation of the service @@ -47,12 +47,12 @@ func DefaultService( srv documents.Service, repo documents.Repository, queueSrv queue.TaskQueuer, - txService transactions.Service, + txManager transactions.Manager, ) Service { return service{ repo: repo, queueSrv: queueSrv, - txService: txService, + txManager: txManager, Service: srv, } } @@ -118,7 +118,8 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, self.ID, cd.CurrentVersion) + txID := contextutil.TX(ctx) + txID, err = documents.InitDocumentAnchorTask(s.queueSrv, s.txManager, self.ID, cd.CurrentVersion, txID) if err != nil { return nil, uuid.Nil, err } @@ -148,7 +149,8 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, err } - txID, err := documents.InitDocumentAnchorTask(s.queueSrv, s.txService, self.ID, cd.CurrentVersion) + txID := contextutil.TX(ctx) + txID, err = documents.InitDocumentAnchorTask(s.queueSrv, s.txManager, self.ID, cd.CurrentVersion, txID) if err != nil { return nil, uuid.Nil, err } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index f06314017..7f64ffda5 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -50,18 +50,18 @@ func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) - txService := ctx[transactions.BootstrappedService].(transactions.Service) + txManager := ctx[transactions.BootstrappedService].(transactions.Manager) repo := testRepo() mockAnchor := &mockAnchorRepo{} docSrv := documents.DefaultService(repo, idService, mockAnchor, documents.NewServiceRegistry()) - return idService, DefaultService(docSrv, repo, queueSrv, txService) + return idService, DefaultService(docSrv, repo, queueSrv, txManager) } func TestService_Update(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed model := &testingdocuments.MockModel{} @@ -132,7 +132,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // nil payload doc, err := poSrv.DeriveFromUpdatePayload(ctxh, nil) @@ -147,7 +147,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // messed up identifier - contextHeader := testingconfig.CreateTenantContext(t, cfg) + contextHeader := testingconfig.CreateAccountContext(t, cfg) payload := &clientpurchaseorderpb.PurchaseOrderUpdatePayload{Identifier: "some identifier", Data: &clientpurchaseorderpb.PurchaseOrderData{}} doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) @@ -213,7 +213,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { func TestService_DeriveFromCreatePayload(t *testing.T) { poSrv := service{} - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // nil payload m, err := poSrv.DeriveFromCreatePayload(ctxh, nil) @@ -267,7 +267,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { } func TestService_Create(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() @@ -304,7 +304,7 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - m, err = poSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) + m, err = poSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err) d, err = poSrv.DerivePurchaseOrderData(m) assert.Nil(t, err) @@ -346,7 +346,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { // success payload := testingdocuments.CreatePOPayload() - po, err := poSrv.DeriveFromCreatePayload(testingconfig.CreateTenantContext(t, cfg), payload) + po, err := poSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err) r, err = poSrv.DerivePurchaseOrderResponse(po) assert.Nil(t, err) @@ -387,7 +387,7 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) _, err = poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Error(t, err) @@ -400,7 +400,7 @@ func TestService_GetCurrentVersion(t *testing.T) { thirdIdentifier := utils.RandomSlice(32) doc, err := createMockDocument() assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) mod1, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) assert.Nil(t, err) @@ -445,7 +445,7 @@ func TestService_GetVersion(t *testing.T) { err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) mod, err := poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadpo, _ := mod.(*PurchaseOrder) @@ -469,7 +469,7 @@ func TestService_Exists(t *testing.T) { err := testRepo().Create(accountID, documentIdentifier, po) assert.Nil(t, err) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) exists := poSrv.Exists(ctxh, documentIdentifier) assert.True(t, exists, "purchase order should exist") @@ -482,7 +482,7 @@ func TestService_calculateDataRoot(t *testing.T) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{repo: testRepo()} - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) // type mismatch po, err := poSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 407ea03a9..6be70286e 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -49,7 +49,7 @@ func TestFieldValidator_Validate(t *testing.T) { func TestDataRootValidation_Validate(t *testing.T) { drv := dataRootValidator() - contextHeader := testingconfig.CreateTenantContext(t, cfg) + contextHeader := testingconfig.CreateAccountContext(t, cfg) // nil error err := drv.Validate(nil, nil) diff --git a/documents/service.go b/documents/service.go index 3a1e14a35..77ba232e3 100644 --- a/documents/service.go +++ b/documents/service.go @@ -124,7 +124,6 @@ func (s service) GetCurrentVersion(ctx context.Context, documentID []byte) (Mode return nil, errors.NewTypedError(ErrDocumentNotFound, err) } return s.searchVersion(ctx, model) - } func (s service) GetVersion(ctx context.Context, documentID []byte, version []byte) (Model, error) { diff --git a/documents/validator_test.go b/documents/validator_test.go index 5e6a853f6..69d6d0f88 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -311,7 +311,7 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) idKeys := self.Keys[identity.KeyPurposeSigning] rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) @@ -638,7 +638,7 @@ func TestPostAnchoredValidator(t *testing.T) { } func TestPreSignatureRequestValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateTenantContext(t, cfg)) + self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) idKeys := self.Keys[identity.KeyPurposeSigning] psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) assert.Len(t, psv, 3) diff --git a/ethereum/bootstrapper.go b/ethereum/bootstrapper.go index 7ce5dcbf8..603068caf 100644 --- a/ethereum/bootstrapper.go +++ b/ethereum/bootstrapper.go @@ -2,7 +2,6 @@ package ethereum import ( "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/queue" @@ -22,7 +21,7 @@ func (Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - txService, ok := context[transactions.BootstrappedService].(transactions.Service) + txManager, ok := context[transactions.BootstrappedService].(transactions.Manager) if !ok { return errors.New("transactions repository not initialised") } @@ -32,21 +31,14 @@ func (Bootstrapper) Bootstrap(context map[string]interface{}) error { } queueSrv := context[bootstrap.BootstrappedQueueServer].(*queue.Server) - client, err := NewGethClient(cfg, txService, queueSrv) + client, err := NewGethClient(cfg) if err != nil { return err } - SetClient(client) - - registerTransactionStatusTask(cfg, client, queueSrv, txService) + SetClient(client) + ethTransTask := NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txManager, client.TransactionByHash, client.TransactionReceipt, DefaultWaitForTransactionMiningContext) + queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) context[BootstrappedEthereumClient] = client return nil } - -func registerTransactionStatusTask(cfg config.Configuration, client Client, queueSrv *queue.Server, txService transactions.Service) { - // queue task - ethTransTask := NewTransactionStatusTask(cfg.GetEthereumContextWaitTimeout(), txService, client.TransactionByHash, client.TransactionReceipt, DefaultWaitForTransactionMiningContext) - - queueSrv.RegisterTaskType(ethTransTask.TaskTypeName(), ethTransTask) -} diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 7cd1304f3..d18dc2331 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -11,8 +11,9 @@ import ( "sync" "time" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/config" @@ -82,9 +83,6 @@ type Client interface { // TransactionReceipt return receipt of a transaction TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - - // SubmitTransaction creates an Ethereum transactions with retries - SubmitTransaction(tendantID identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) } // gethClient implements Client for Ethereum @@ -95,15 +93,13 @@ type gethClient struct { accounts map[string]*bind.TransactOpts accMu sync.Mutex // accMu to protect accounts config Config - txService transactions.Service - queue *queue.Server // txMu to ensure one transaction at a time per client txMu sync.Mutex } // NewGethClient returns an gethClient which implements Client -func NewGethClient(config Config, transService transactions.Service, queue *queue.Server) (Client, error) { +func NewGethClient(config Config) (Client, error) { log.Info("Opening connection to Ethereum:", config.GetEthereumNodeURL()) u, err := url.Parse(config.GetEthereumNodeURL()) if err != nil { @@ -123,8 +119,6 @@ func NewGethClient(config Config, transService transactions.Service, queue *queu txMu: sync.Mutex{}, accMu: sync.Mutex{}, config: config, - txService: transService, - queue: queue, }, nil } @@ -206,35 +200,19 @@ func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, err return opts, nil } -func (gc *gethClient) queueTaskTransactionStatus(accountID identity.CentID, txHash string) (txID uuid.UUID, err error) { - tx, err := gc.txService.CreateTransaction(accountID, "polling Ethereum transaction status") - if err != nil { - return txID, err - } - _, err = gc.queue.EnqueueJob(TransactionStatusTaskName, map[string]interface{}{ - transactions.TxIDParam: tx.ID.String(), +// QueueEthTXStatusTask starts a new queuing transaction check task. +func QueueEthTXStatusTask( + accountID identity.CentID, + txID uuid.UUID, + txHash common.Hash, + next bool, + queuer queue.TaskQueuer) (res queue.TaskResult, err error) { + return queuer.EnqueueJobWithMaxTries(EthTXStatusTaskName, map[string]interface{}{ + transactions.TxIDParam: txID.String(), TransactionAccountParam: accountID.String(), - TransactionTxHashParam: txHash, + TransactionTxHashParam: txHash.String(), + transactions.TxNextTask: next, }) - - return tx.ID, err -} - -// SubmitTransaction creates an Ethereum transactions with retries -func (gc *gethClient) SubmitTransaction(account identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) { - tx, err := gc.SubmitTransactionWithRetries(contractMethod, opts, params...) - if err != nil { - return nil, nil, errors.New("Submit Ethereum transaction failed: %v", err) - } - - txHash := tx.Hash() - txID, err := gc.queueTaskTransactionStatus(account, txHash.String()) - - if err != nil { - return nil, nil, errors.New("Failed to generated a queue task to poll the Ethereum transaction status: %v", err) - } - return &txID, tx, nil - } /** @@ -247,13 +225,13 @@ gas prices that means that a concurrent transaction race condition event has hap Note: contractMethod must always return "*types.Transaction, error" */ func (gc *gethClient) SubmitTransactionWithRetries(contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*types.Transaction, error) { + gc.txMu.Lock() + defer gc.txMu.Unlock() + var current int f := reflect.ValueOf(contractMethod) maxTries := gc.config.GetEthereumMaxRetries() - gc.txMu.Lock() - defer gc.txMu.Unlock() - var err error for { diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index faef377f2..973cfd28f 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -31,7 +31,7 @@ var ctx = map[string]interface{}{} func registerMockedTransactionTask() { queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - txService := ctx[transactions.BootstrappedService].(transactions.Service) + txManager := ctx[transactions.BootstrappedService].(transactions.Manager) mockClient := &testingcommons.MockEthClient{} @@ -46,8 +46,8 @@ func registerMockedTransactionTask() { // txHash: 0x3 -> pending mockClient.On("TransactionByHash", mock.Anything, common.HexToHash("0x3")).Return(&types.Transaction{}, true, nil).Maybe() - ethTransTask := ethereum.NewTransactionStatusTask(200*time.Millisecond, txService, mockClient.TransactionByHash, mockClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) - queueSrv.RegisterTaskType(ethereum.TransactionStatusTaskName, ethTransTask) + ethTransTask := ethereum.NewTransactionStatusTask(200*time.Millisecond, txManager, mockClient.TransactionByHash, mockClient.TransactionReceipt, ethereum.DefaultWaitForTransactionMiningContext) + queueSrv.RegisterTaskType(ethereum.EthTXStatusTaskName, ethTransTask) } @@ -93,7 +93,7 @@ func TestGetConnection_returnsSameConnection(t *testing.T) { } func TestNewGethClient(t *testing.T) { - gc, err := ethereum.NewGethClient(cfg, nil, nil) + gc, err := ethereum.NewGethClient(cfg) assert.Nil(t, err) assert.NotNil(t, gc) } diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 0bf974140..1d4a3166a 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -15,10 +15,12 @@ import ( ) const ( - // TransactionStatusTaskName contains the name of the task - TransactionStatusTaskName string = "TransactionStatusTask" + // EthTXStatusTaskName contains the name of the task + EthTXStatusTaskName string = "EthTXStatusTaskName" + // TransactionTxHashParam contains the name of the parameter TransactionTxHashParam string = "TxHashParam" + // TransactionAccountParam contains the name of the account TransactionAccountParam string = "Account ID" // TransactionStatusSuccess contains the flag for a successful receipt.status @@ -39,6 +41,7 @@ type WatchTransaction struct { type TransactionStatusTask struct { transactions.BaseTask timeout time.Duration + //state ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) @@ -52,7 +55,7 @@ type TransactionStatusTask struct { // NewTransactionStatusTask returns a the struct for the task func NewTransactionStatusTask( timeout time.Duration, - txService transactions.Service, + txService transactions.Manager, transactionByHash func(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error), transactionReceipt func(ctx context.Context, txHash common.Hash) (*types.Receipt, error), ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), @@ -60,7 +63,7 @@ func NewTransactionStatusTask( ) *TransactionStatusTask { return &TransactionStatusTask{ timeout: timeout, - BaseTask: transactions.BaseTask{TxService: txService}, + BaseTask: transactions.BaseTask{TxManager: txService}, ethContextInitializer: ethContextInitializer, transactionByHash: transactionByHash, transactionReceipt: transactionReceipt, @@ -68,26 +71,26 @@ func NewTransactionStatusTask( } // TaskTypeName returns mintingConfirmationTaskName -func (nftc *TransactionStatusTask) TaskTypeName() string { - return TransactionStatusTaskName +func (tst *TransactionStatusTask) TaskTypeName() string { + return EthTXStatusTaskName } // Copy returns a new instance of mintingConfirmationTask -func (nftc *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { +func (tst *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { return &TransactionStatusTask{ - timeout: nftc.timeout, - txHash: nftc.txHash, - accountID: nftc.accountID, - transactionByHash: nftc.transactionByHash, - transactionReceipt: nftc.transactionReceipt, - ethContextInitializer: nftc.ethContextInitializer, - BaseTask: transactions.BaseTask{TxService: nftc.TxService}, + timeout: tst.timeout, + txHash: tst.txHash, + accountID: tst.accountID, + transactionByHash: tst.transactionByHash, + transactionReceipt: tst.transactionReceipt, + ethContextInitializer: tst.ethContextInitializer, + BaseTask: transactions.BaseTask{TxManager: tst.TxManager}, }, nil } // ParseKwargs - define a method to parse CentID -func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (err error) { - err = nftc.ParseTransactionID(kwargs) +func (tst *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (err error) { + err = tst.ParseTransactionID(kwargs) if err != nil { return err } @@ -97,7 +100,7 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e return errors.New("missing account ID") } - nftc.accountID, err = identity.CentIDFromString(accountID) + tst.accountID, err = identity.CentIDFromString(accountID) if err != nil { return err } @@ -107,7 +110,7 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e if !ok { return errors.New("undefined kwarg " + TransactionTxHashParam) } - nftc.txHash, ok = txHash.(string) + tst.txHash, ok = txHash.(string) if !ok { return errors.New("malformed kwarg [%s]", TransactionTxHashParam) } @@ -119,14 +122,14 @@ func (nftc *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (e if err != nil { return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) } - nftc.timeout = td + tst.timeout = td } return nil } -func (nftc *TransactionStatusTask) isTransactionSuccessful(ctx context.Context, txHash string) error { - receipt, err := nftc.transactionReceipt(ctx, common.HexToHash(txHash)) +func (tst *TransactionStatusTask) isTransactionSuccessful(ctx context.Context, txHash string) error { + receipt, err := tst.transactionReceipt(ctx, common.HexToHash(txHash)) if err != nil { return err } @@ -139,14 +142,14 @@ func (nftc *TransactionStatusTask) isTransactionSuccessful(ctx context.Context, } // RunTask calls listens to events from geth related to MintingConfirmationTask#TokenID and records result. -func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { - ctx, cancelF := nftc.ethContextInitializer(nftc.timeout) +func (tst *TransactionStatusTask) RunTask() (resp interface{}, err error) { + ctx, cancelF := tst.ethContextInitializer(tst.timeout) defer cancelF() defer func() { - err = nftc.UpdateTransaction(nftc.accountID, nftc.TaskTypeName(), err) + err = tst.UpdateTransaction(tst.accountID, tst.TaskTypeName(), err) }() - _, isPending, err := nftc.transactionByHash(ctx, common.HexToHash(nftc.txHash)) + _, isPending, err := tst.transactionByHash(ctx, common.HexToHash(tst.txHash)) if err != nil { return nil, err } @@ -155,7 +158,7 @@ func (nftc *TransactionStatusTask) RunTask() (resp interface{}, err error) { return nil, gocelery.ErrTaskRetryable } - err = nftc.isTransactionSuccessful(ctx, nftc.txHash) + err = tst.isTransactionSuccessful(ctx, tst.txHash) if err == nil { return nil, nil } diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go index 0c2b6d072..fd5988c5d 100644 --- a/ethereum/transaction_status_task_integration_test.go +++ b/ethereum/transaction_status_task_integration_test.go @@ -14,38 +14,40 @@ import ( "github.com/stretchr/testify/assert" ) -func enqueueJob(t *testing.T, txHash string) (transactions.Service, identity.CentID, *transactions.Transaction) { +func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, *transactions.Transaction, queue.TaskResult) { queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - txService := ctx[transactions.BootstrappedService].(transactions.Service) + txManager := ctx[transactions.BootstrappedService].(transactions.Manager) cid := identity.RandomCentID() - tx, err := txService.CreateTransaction(cid, "Mint NFT") + tx, err := txManager.CreateTransaction(cid, "Mint NFT") assert.Nil(t, err, "toCentID shouldn't throw an error") - _, err = queueSrv.EnqueueJob(ethereum.TransactionStatusTaskName, map[string]interface{}{ + result, err := queueSrv.EnqueueJob(ethereum.EthTXStatusTaskName, map[string]interface{}{ transactions.TxIDParam: tx.ID.String(), ethereum.TransactionAccountParam: cid.String(), ethereum.TransactionTxHashParam: txHash, }) - time.Sleep(100 * time.Millisecond) - return txService, cid, tx - + return txManager, cid, tx, result } func TestTransactionStatusTask_successful(t *testing.T) { - txService, cid, tx := enqueueJob(t, "0x1") + txManager, cid, tx, result := enqueueJob(t, "0x1") - trans, err := txService.GetTransaction(cid, tx.ID) + _, err := result.Get(time.Second) + assert.NoError(t, err) + trans, err := txManager.GetTransaction(cid, tx.ID) assert.Nil(t, err, "a transaction should be returned") assert.Equal(t, string(transactions.Success), string(trans.Status), "transaction should be successful") } func TestTransactionStatusTask_failed(t *testing.T) { - txService, cid, tx := enqueueJob(t, "0x2") + txManager, cid, tx, result := enqueueJob(t, "0x2") - trans, err := txService.GetTransaction(cid, tx.ID) + _, err := result.Get(time.Second) + assert.Error(t, err) + trans, err := txManager.GetTransaction(cid, tx.ID) assert.Nil(t, err, "a centrifuge transaction should be returned") assert.Equal(t, string(transactions.Failed), string(trans.Status), "transaction should fail") } diff --git a/identity/ethid/ethereum_identity_integration_test.go b/identity/ethid/ethereum_identity_integration_test.go index 3b34ee05a..2f54c27a4 100644 --- a/identity/ethid/ethereum_identity_integration_test.go +++ b/identity/ethid/ethereum_identity_integration_test.go @@ -42,7 +42,7 @@ func TestCreateAndLookupIdentity_Integration(t *testing.T) { wrongCentrifugeIdTyped, _ := identity.ToCentID(wrongCentrifugeId) cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) + id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations @@ -84,7 +84,7 @@ func TestAddKeyFromConfig(t *testing.T) { cfg.Set("identityId", centrifugeId.String()) cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) + _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations @@ -118,7 +118,7 @@ func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) cfg.Set("identityId", centId.String()) centIds[ix] = centId - _, identityConfirmations[ix], err = identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centId) + _, identityConfirmations[ix], err = identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centId) assert.Nil(t, err, "should not error out upon identity creation") } @@ -133,7 +133,7 @@ func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { func TestEthereumIdentityService_GetIdentityAddress(t *testing.T) { centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) cfg.Set("identityId", centrifugeId.String()) - _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) + _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") <-confirmations addr, err := identityService.GetIdentityAddress(centrifugeId) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index 906b02423..b9914bb5b 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -3,6 +3,8 @@ package nft import ( "context" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" @@ -22,6 +24,11 @@ type Bootstrapper struct{} // Bootstrap initializes the payment obligation contract func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + cfg, err := configstore.RetrieveConfig(false, ctx) + if err != nil { + return err + } + if _, ok := ctx[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -41,19 +48,20 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - txService, ok := ctx[transactions.BootstrappedService].(transactions.Service) + txManager, ok := ctx[transactions.BootstrappedService].(transactions.Manager) if !ok { return errors.New("transactions repository not initialised") } client := ethereum.GetClient() payOb := newEthereumPaymentObligation( + cfg, idService, client, queueSrv, docSrv, bindContract, - txService, func() (uint64, error) { + txManager, func() (uint64, error) { h, err := client.GetEthClient().HeaderByNumber(context.Background(), nil) if err != nil { return 0, err diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index b07179843..15cd2a983 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -3,6 +3,7 @@ package nft import ( "context" "math/big" + "time" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" @@ -33,70 +34,76 @@ type ethereumPaymentObligationContract interface { OwnerOf(opts *bind.CallOpts, tokenID *big.Int) (common.Address, error) } +// Config is the config interface for nft package +type Config interface { + GetEthereumContextWaitTimeout() time.Duration +} + // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum type ethereumPaymentObligation struct { - registry *documents.ServiceRegistry + cfg Config identityService identity.Service ethClient ethereum.Client queue queue.TaskQueuer docSrv documents.Service bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) - txService transactions.Service + txManager transactions.Manager blockHeightFunc func() (height uint64, err error) } // newEthereumPaymentObligation creates ethereumPaymentObligation given the parameters func newEthereumPaymentObligation( + cfg Config, identityService identity.Service, ethClient ethereum.Client, queue queue.TaskQueuer, docSrv documents.Service, bindContract func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error), - txService transactions.Service, + txManager transactions.Manager, blockHeightFunc func() (uint64, error)) *ethereumPaymentObligation { return ðereumPaymentObligation{ + cfg: cfg, identityService: identityService, ethClient: ethClient, bindContract: bindContract, queue: queue, docSrv: docSrv, - txService: txService, + txManager: txManager, blockHeightFunc: blockHeightFunc, } } -func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (*MintRequest, error) { - +func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (MintRequest, error) { model, err := s.docSrv.GetCurrentVersion(ctx, documentID) if err != nil { - return nil, err + return MintRequest{}, err } corDoc, err := model.PackCoreDocument() if err != nil { - return nil, err + return MintRequest{}, err } proofs, err := s.docSrv.CreateProofs(ctx, documentID, proofFields) if err != nil { - return nil, err + return MintRequest{}, err } toAddress := common.HexToAddress(depositAddress) anchorID, err := anchors.ToAnchorID(corDoc.CurrentVersion) if err != nil { - return nil, nil + return MintRequest{}, err } rootHash, err := anchors.ToDocumentRoot(corDoc.DocumentRoot) if err != nil { - return nil, nil + return MintRequest{}, err } requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash) if err != nil { - return nil, err + return MintRequest{}, err } return requestData, nil @@ -120,7 +127,8 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, err } - contract, err := s.bindContract(common.HexToAddress(registryAddress), s.ethClient) + registry := common.HexToAddress(registryAddress) + contract, err := s.bindContract(registry, s.ethClient) if err != nil { return nil, err } @@ -135,7 +143,7 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, err } - txID, _, err := s.sendMintTransaction(cid, contract, opts, requestData) + txID, err := s.sendMintTransaction(cid, contract, opts, requestData, registry, documentID) if err != nil { return nil, errors.New("failed to send transaction: %v", err) } @@ -160,18 +168,54 @@ func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []b } // sendMintTransaction sends the actual transaction to mint the NFT -func (s *ethereumPaymentObligation) sendMintTransaction(cid identity.CentID, contract ethereumPaymentObligationContract, opts *bind.TransactOpts, requestData *MintRequest) (*uuid.UUID, *types.Transaction, error) { - tx, ethTx, err := s.ethClient.SubmitTransaction(cid, contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, - requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) +func (s *ethereumPaymentObligation) sendMintTransaction( + cid identity.CentID, + contract ethereumPaymentObligationContract, + opts *bind.TransactOpts, + requestData MintRequest, + registry common.Address, + documentID []byte) (uuid.UUID, error) { + + r := requestData.copy() + + // Run within transaction + // We use context.Background() for now so that the transaction is only limited by ethereum timeouts + txID, _, err := s.txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Minting NFT", func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, r.To, r.TokenID, r.TokenURI, r.AnchorID, + r.MerkleRoot, r.Values, r.Salts, r.Proofs) + if err != nil { + errOut <- err + } - if err != nil { - return nil, nil, err - } + log.Infof("Sent off ethTX to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", + requestData.TokenID, requestData.AnchorID, requestData.To, ethTX.Hash(), ethTX.Nonce(), ethTX.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", ethTX.Hash()) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), true, s.queue) + if err != nil { + errOut <- err + } - log.Infof("Sent off tx to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", - requestData.TokenID, requestData.AnchorID, requestData.To, ethTx.Hash(), ethTx.Nonce(), ethTx.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", ethTx.Hash()) - return tx, ethTx, nil + _, err = res.Get(s.cfg.GetEthereumContextWaitTimeout()) + if err != nil { + errOut <- err + } + + res, err = documents.InitNFTCreatedTask( + s.queue, txID, accountID, documentID, registry, requestData.TokenID.Bytes()) + if err != nil { + errOut <- err + } + + _, err = res.Get(s.cfg.GetEthereumContextWaitTimeout()) + if err != nil { + errOut <- err + } + + errOut <- nil + }) + + return txID, err } // MintRequest holds the data needed to mint and NFT from a Centrifuge document @@ -203,7 +247,7 @@ type MintRequest struct { } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (*MintRequest, error) { +func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { // tokenID is uint256 in Solidity (256 bits | max value is 2^256-1) // tokenID should be random 32 bytes (32 byte = 256 bits) @@ -211,10 +255,10 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo tokenURI := "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" proofData, err := createProofData(proofs) if err != nil { - return nil, err + return MintRequest{}, err } - return &MintRequest{ + return MintRequest{ To: to, TokenID: tokenID, TokenURI: tokenURI, @@ -225,6 +269,19 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo Proofs: proofData.Proofs}, nil } +func (m MintRequest) copy() MintRequest { + return MintRequest{ + m.To, + new(big.Int).Set(m.TokenID), + m.TokenURI, + new(big.Int).Set(m.AnchorID), + m.MerkleRoot, + m.Values, + m.Salts, + m.Proofs, + } +} + type proofData struct { Values []string Salts [][32]byte diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 0e3957121..4ab9f4769 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -3,22 +3,22 @@ package nft import ( + "context" "math/big" "testing" "time" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/satori/go.uuid" - "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -36,6 +36,35 @@ import ( "github.com/stretchr/testify/mock" ) +type MockTxManager struct { + mock.Mock +} + +func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { + args := m.Called(ctx, accountID, existingTxID, desc, work) + return args.Get(0).(uuid.UUID), args.Get(1).(chan bool), args.Error(2) +} + +func (MockTxManager) CreateTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) { + panic("implement me") +} + +func (MockTxManager) GetTransaction(accountID identity.CentID, id uuid.UUID) (*transactions.Transaction, error) { + panic("implement me") +} + +func (MockTxManager) SaveTransaction(tx *transactions.Transaction) error { + panic("implement me") +} + +func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { + panic("implement me") +} + +func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { + panic("implement me") +} + func TestCreateProofData(t *testing.T) { sortedHashes := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} salt := utils.RandomSlice(32) @@ -143,14 +172,14 @@ func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address func TestPaymentObligationService(t *testing.T) { tests := []struct { name string - mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue) + mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *MockTxManager) request *nftpb.NFTMintRequest err error result string }{ { "happypath", - func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue) { + func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *MockTxManager) { coreDoc := coredocument.New() coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) @@ -161,11 +190,11 @@ func TestPaymentObligationService(t *testing.T) { idServiceMock := testingcommons.MockIDService{} ethClientMock := testingcommons.MockEthClient{} ethClientMock.On("GetTxOpts", "ethacc").Return(&bind.TransactOpts{}, nil) - ethClientMock.On("SubmitTransaction", + ethClientMock.On("SubmitTransactionWithRetries", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything, - ).Return(&uuid.UUID{}, &types.Transaction{}, nil) + mock.Anything, mock.Anything, + ).Return(&types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") cid := identity.RandomCentID() @@ -176,7 +205,10 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) - return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv + txMan := &MockTxManager{} + txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(uuid.Nil, make(chan bool), nil) + return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv, txMan }, &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, nil, @@ -184,17 +216,16 @@ func TestPaymentObligationService(t *testing.T) { }, } - txService := ctx[transactions.BootstrappedService].(transactions.Service) - for _, test := range tests { t.Run(test.name, func(t *testing.T) { // get mocks - docService, paymentOb, idService, ethClient, mockCfg, queueSrv := test.mocker() + docService, paymentOb, idService, ethClient, mockCfg, queueSrv, txMan := test.mocker() // with below config the documentType has to be test.name to avoid conflicts since registry is a singleton - service := newEthereumPaymentObligation(&idService, ðClient, queueSrv, &docService, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { + queueSrv.On("EnqueueJobWithMaxTries", mock.Anything, mock.Anything).Return(nil, nil).Once() + service := newEthereumPaymentObligation(&mockCfg, &idService, ðClient, queueSrv, &docService, func(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return &EthereumPaymentObligationContract{}, nil - }, txService, func() (uint64, error) { return 10, nil }) - ctxh := testingconfig.CreateTenantContext(t, &mockCfg) + }, txMan, func() (uint64, error) { return 10, nil }) + ctxh := testingconfig.CreateAccountContext(t, &mockCfg) _, err := service.MintNFT(ctxh, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) @@ -204,9 +235,9 @@ func TestPaymentObligationService(t *testing.T) { docService.AssertExpectations(t) paymentOb.AssertExpectations(t) idService.AssertExpectations(t) - ethClient.AssertExpectations(t) + //ethClient.AssertExpectations(t) mockCfg.AssertExpectations(t) - queueSrv.AssertExpectations(t) + //queueSrv.AssertExpectations(t) }) } } diff --git a/nft/handler.go b/nft/handler.go index 7dfba6d05..dba1b6fcd 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -3,12 +3,10 @@ package nft import ( "context" - "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 651db220d..0bc65e349 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -32,7 +32,7 @@ var registry *documents.ServiceRegistry var cfg config.Configuration var idService identity.Service var payOb nft.PaymentObligation -var txService transactions.Service +var txManager transactions.Manager var tokenRegistry coredocument.TokenRegistry func TestMain(m *testing.M) { @@ -42,7 +42,7 @@ func TestMain(m *testing.M) { idService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) - txService = ctx[transactions.BootstrappedService].(transactions.Service) + txManager = ctx[transactions.BootstrappedService].(transactions.Manager) tokenRegistry = ctx[nft.BootstrappedPayObService].(coredocument.TokenRegistry) result := m.Run() cc.TestFunctionalEthereumTearDown() @@ -57,7 +57,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader := testingconfig.CreateTenantContext(t, cfg) + contextHeader := testingconfig.CreateAccountContext(t, cfg) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) model, err := invoiceService.DeriveFromCreatePayload(contextHeader, &invoicepb.InvoiceCreatePayload{ @@ -72,7 +72,7 @@ func TestPaymentObligationService_mint(t *testing.T) { }) assert.Nil(t, err, "should not error out when creating invoice model") modelUpdated, txID, err := invoiceService.Create(contextHeader, model) - err = txService.WaitForTransaction(cid, txID) + err = txManager.WaitForTransaction(cid, txID) assert.Nil(t, err) // get ID @@ -81,20 +81,30 @@ func TestPaymentObligationService_mint(t *testing.T) { // call mint // assert no error depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" - registry := cfg.GetContractAddress(config.PaymentObligation).String() + registry := cfg.GetContractAddress(config.PaymentObligation) resp, err := payOb.MintNFT( contextHeader, ID, - registry, + registry.String(), depositAddr, []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, ) assert.Nil(t, err, "should not error out when minting an invoice") assert.NotNil(t, resp.TokenID, "token id should be present") - assert.NoError(t, txService.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) + assert.NoError(t, txManager.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) b := new(big.Int) b.SetString(resp.TokenID, 10) - owner, err := tokenRegistry.OwnerOf(common.HexToAddress(registry), b.Bytes()) + owner, err := tokenRegistry.OwnerOf(registry, b.Bytes()) assert.NoError(t, err) assert.Equal(t, common.HexToAddress(depositAddr), owner) + doc, err := invoiceService.GetCurrentVersion(contextHeader, ID) + assert.NoError(t, err) + cd, err := doc.PackCoreDocument() + assert.NoError(t, err) + assert.Len(t, cd.Roles, 2) + assert.Len(t, cd.Roles[1].Nfts, 1) + nft := cd.Roles[1].Nfts[0] + enft, err := coredocument.ConstructNFT(registry, b.Bytes()) + assert.NoError(t, err) + assert.Equal(t, enft, nft) } diff --git a/notification/notification_test.go b/notification/notification_test.go index 76383706e..6d2db4549 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -98,7 +98,7 @@ func TestWebhookSender_Send(t *testing.T) { } cfg.Set("notifications.endpoint", "http://localhost:8090/webhook") - status, err := wb.Send(testingconfig.CreateTenantContext(t, cfg), notif) + status, err := wb.Send(testingconfig.CreateAccountContext(t, cfg), notif) assert.NoError(t, err) assert.Equal(t, status, Success) wg.Wait() diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index a91b41313..a3a500958 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -47,7 +47,7 @@ func TestMain(m *testing.M) { func TestClient_GetSignaturesForDocument(t *testing.T) { tc, _, err := createLocalCollaborator(t, false) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) err = client.GetSignaturesForDocument(ctxh, doc) assert.NoError(t, err) @@ -56,7 +56,7 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) err = client.GetSignaturesForDocument(ctxh, doc) assert.NoError(t, err) @@ -66,7 +66,7 @@ func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { func TestClient_SendAnchoredDocument(t *testing.T) { tc, cid, err := createLocalCollaborator(t, false) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) _, err = client.SendAnchoredDocument(ctxh, cid.CentID(), &p2ppb.AnchorDocumentRequest{Document: doc}) diff --git a/p2p/client_test.go b/p2p/client_test.go index 3a6d0c50c..151afdda7 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -53,7 +53,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) - ctx := testingconfig.CreateTenantContext(t, c) + ctx := testingconfig.CreateAccountContext(t, c) assert.Nil(t, err, "centrifugeId not initialized correctly ") @@ -78,7 +78,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) - ctx := testingconfig.CreateTenantContext(t, c) + ctx := testingconfig.CreateAccountContext(t, c) _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") @@ -100,7 +100,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) - ctx := testingconfig.CreateTenantContext(t, c) + ctx := testingconfig.CreateAccountContext(t, c) assert.Nil(t, err, "centrifugeId not initialized correctly ") diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 2f234a895..82df1a034 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -69,7 +69,7 @@ func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { } func TestHandler_GetDocumentSucceeds(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) centrifugeId := createIdentity(t) doc := prepareDocumentForP2PHandler(t, nil) @@ -109,7 +109,7 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) tc, err := contextutil.Account(ctxh) _, err = cfgService.CreateAccount(tc) assert.NoError(t, err) @@ -135,7 +135,7 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { } func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) doc.SigningRoot = nil req := getSignatureRequest(doc) @@ -148,7 +148,7 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") @@ -160,7 +160,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) resp, err := handler.RequestDocumentSignature(ctxh, req) @@ -184,7 +184,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { } func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) newDoc, err := coredocument.PrepareNewVersion(*doc, nil) assert.Nil(t, err) @@ -201,7 +201,7 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T } func TestHandler_RequestDocumentSignature(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getSignatureRequest(doc) resp, err := handler.RequestDocumentSignature(ctxh, req) @@ -223,7 +223,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) assert.Nil(t, err) @@ -238,7 +238,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { } func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) doc := prepareDocumentForP2PHandler(t, nil) req := getAnchoredRequest(doc) req.Document = nil @@ -250,7 +250,7 @@ func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { } func TestHandler_SendAnchoredDocument(t *testing.T) { - ctxh := testingconfig.CreateTenantContext(t, cfg) + ctxh := testingconfig.CreateAccountContext(t, cfg) centrifugeId := createIdentity(t) doc := prepareDocumentForP2PHandler(t, nil) @@ -287,7 +287,7 @@ func createIdentity(t *testing.T) identity.CentID { // Create Identity centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := idService.CreateIdentity(testingconfig.CreateTenantContext(t, cfg), centrifugeId) + id, confirmations, err := idService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) assert.Nil(t, err, "should not error out when creating identity") watchRegisteredIdentity := <-confirmations assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index a26cbf1c1..899282983 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -100,7 +100,7 @@ func TestHandler_HandleInterceptor_HeaderEmpty(t *testing.T) { } func TestHandler_HandleInterceptor_CentIDNotHex(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("protocolX"), p2pEnv) @@ -110,7 +110,7 @@ func TestHandler_HandleInterceptor_CentIDNotHex(t *testing.T) { } func TestHandler_HandleInterceptor_TenantNotFound(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("0x001100110011"), p2pEnv) @@ -120,7 +120,7 @@ func TestHandler_HandleInterceptor_TenantNotFound(t *testing.T) { } func TestHandler_HandleInterceptor_HandshakeValidationFail(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) @@ -148,7 +148,7 @@ func TestHandler_HandleInterceptor_HandshakeValidationFail(t *testing.T) { } func TestHandler_HandleInterceptor_UnsupportedMessageType(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) @@ -167,7 +167,7 @@ func TestHandler_HandleInterceptor_UnsupportedMessageType(t *testing.T) { } func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) @@ -179,7 +179,7 @@ func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { } func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { - ctx := testingconfig.CreateTenantContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) req := &p2ppb.AnchorDocumentRequest{Document: coredocument.New()} p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDoc, req) assert.NoError(t, err) diff --git a/testingutils/commons/mock_ethclient.go b/testingutils/commons/mock_ethclient.go index 793d4f295..066032271 100644 --- a/testingutils/commons/mock_ethclient.go +++ b/testingutils/commons/mock_ethclient.go @@ -5,9 +5,6 @@ package testingcommons import ( "net/url" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/satori/go.uuid" - "github.com/ethereum/go-ethereum/common" "context" @@ -58,9 +55,3 @@ func (m *MockEthClient) TransactionReceipt(ctx context.Context, txHash common.Ha args := m.Called(ctx, txHash) return args.Get(0).(*types.Receipt), args.Error(1) } - -// SubmitTransaction creates an Ethereum transactions with retries -func (m *MockEthClient) SubmitTransaction(tendantID identity.CentID, contractMethod interface{}, opts *bind.TransactOpts, params ...interface{}) (*uuid.UUID, *types.Transaction, error) { - args := m.Called(tendantID, contractMethod, opts, params) - return args.Get(0).(*uuid.UUID), args.Get(1).(*types.Transaction), args.Error(2) -} diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 57d070874..b8e8df00c 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -162,7 +162,7 @@ func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { return args.Get(0).(string), args.Get(1).(string) } -func CreateTenantContext(t *testing.T, cfg config.Configuration) context.Context { +func CreateAccountContext(t *testing.T, cfg config.Configuration) context.Context { return CreateTenantContextWithContext(t, context.Background(), cfg) } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index e943864e9..204228eb6 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -21,7 +21,7 @@ func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service // only create identity if it doesn't exist id, err := idService.LookupIdentityForID(idConfig.ID) if err != nil { - _, confirmations, _ := idService.CreateIdentity(testingconfig.CreateTenantContext(&testing.T{}, cfg), idConfig.ID) + _, confirmations, _ := idService.CreateIdentity(testingconfig.CreateAccountContext(&testing.T{}, cfg), idConfig.ID) <-confirmations // LookupIdentityForId id, _ = idService.LookupIdentityForID(idConfig.ID) diff --git a/testworld/README.md b/testworld/README.md index 82306a854..c22b8586a 100644 --- a/testworld/README.md +++ b/testworld/README.md @@ -54,5 +54,5 @@ Here you can create, run and test nodes with various behaviours to observe how t #### Speed improvements for local testing At `configs/local/local.json`, - Set `runMigrations` to `false` after the contracts are deployed once at the local geth node. -- Set `createHostConfigs` to `false` after configs have been generated in `peerconfigs` dir, note that if you add new hosts using `hostConfig` you would need this to be set to `true` again to generate the config for the new host. +- Set `createHostConfigs` to `false` after configs have been generated in `hostconfigs` dir, note that if you add new hosts using `hostConfig` you would need this to be set to `true` again to generate the config for the new host. diff --git a/transactions/base_task.go b/transactions/base_task.go index 6e3006860..7dba218a4 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -13,13 +13,21 @@ var log = logging.Logger("transaction") const ( // TxIDParam maps transaction ID in the kwargs. TxIDParam = "transactionID" + + // TxNextTask indicates if there is next task + TxNextTask = "next task" ) // BaseTask holds the required details and helper functions for tasks to update transactions. // should be embedded into the task type BaseTask struct { - TxID uuid.UUID - TxService Service + TxID uuid.UUID + + // TODO [TXManager] remove this update once TX Manager update is complete, i.e. Individual tasks must not be responsible for updating a transactions status + Next bool + + // state + TxManager Manager } // ParseTransactionID parses txID. @@ -35,33 +43,43 @@ func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { return errors.New("invalid transaction ID") } + if b.Next, ok = kwargs[TxNextTask].(bool); !ok { + b.Next = false + } + + log.Infof("Task %v has next task: %v\n", b.TxID.String(), b.Next) return nil } // UpdateTransaction add a new log and updates the status of the transaction based on the error. -func (b *BaseTask) UpdateTransaction(accountID identity.CentID, name string, err error) error { +func (b *BaseTask) UpdateTransaction(accountID identity.CentID, taskTypeName string, err error) error { if err == gocelery.ErrTaskRetryable { return err } if err != nil { log.Infof("Transaction failed: %v\n", b.TxID.String()) - } else { - log.Infof("Transaction successful:%v\n", b.TxID.String()) + return errors.AppendError(err, b.updateStatus(accountID, Failed, taskTypeName, err.Error())) } - tx, erri := b.TxService.GetTransaction(accountID, b.TxID) - if erri != nil { - return errors.AppendError(err, erri) + if b.Next { + return b.updateStatus(accountID, Pending, taskTypeName, "") } - if err == nil { - tx.Status = Success - tx.Logs = append(tx.Logs, NewLog(name, "")) - return b.TxService.SaveTransaction(tx) + log.Infof("Transaction successful:%v\n", b.TxID.String()) + return b.updateStatus(accountID, Success, taskTypeName, "") +} + +func (b *BaseTask) updateStatus(accountID identity.CentID, status Status, taskTypeName, message string) error { + tx, err := b.TxManager.GetTransaction(accountID, b.TxID) + if err != nil { + return err } - tx.Status = Failed - tx.Logs = append(tx.Logs, NewLog(name, err.Error())) - return errors.AppendError(err, b.TxService.SaveTransaction(tx)) + // TODO [TXManager] remove this update once TX Manager update is complete, i.e. Individual tasks must not be responsible for updating a transactions status + tx.Status = status + // status particular to the task + tx.TaskStatus[taskTypeName] = status + tx.Logs = append(tx.Logs, NewLog(taskTypeName, message)) + return b.TxManager.SaveTransaction(tx) } diff --git a/transactions/base_task_test.go b/transactions/base_task_test.go index 1da134f11..ff1dc3e9f 100644 --- a/transactions/base_task_test.go +++ b/transactions/base_task_test.go @@ -5,9 +5,8 @@ package transactions import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" @@ -19,7 +18,7 @@ func TestDocumentAnchorTask_updateTransaction(t *testing.T) { accountID := identity.RandomCentID() name := "some task" task.TxID = uuid.Must(uuid.NewV4()) - task.TxService = NewService(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) + task.TxManager = NewManager(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) // missing transaction with nil error err := task.UpdateTransaction(accountID, name, nil) @@ -32,23 +31,34 @@ func TestDocumentAnchorTask_updateTransaction(t *testing.T) { assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) // no error and success - tx := NewTransaction(accountID, "") - assert.NoError(t, task.TxService.SaveTransaction(tx)) + tx := newTransaction(accountID, "") + assert.NoError(t, task.TxManager.SaveTransaction(tx)) task.TxID = tx.ID assert.NoError(t, task.UpdateTransaction(accountID, name, nil)) - tx, err = task.TxService.GetTransaction(accountID, task.TxID) + tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) assert.Equal(t, tx.Status, Success) assert.Len(t, tx.Logs, 1) // failed task - tx = NewTransaction(accountID, "") - assert.NoError(t, task.TxService.SaveTransaction(tx)) + tx = newTransaction(accountID, "") + assert.NoError(t, task.TxManager.SaveTransaction(tx)) task.TxID = tx.ID err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) assert.EqualError(t, errors.GetErrs(err)[0], "anchor error") - tx, err = task.TxService.GetTransaction(accountID, task.TxID) + tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) assert.Equal(t, tx.Status, Failed) assert.Len(t, tx.Logs, 1) + + // success but pending + tx = newTransaction(accountID, "") + assert.NoError(t, task.TxManager.SaveTransaction(tx)) + task.TxID = tx.ID + task.Next = true + err = task.UpdateTransaction(accountID, name, nil) + tx, err = task.TxManager.GetTransaction(accountID, task.TxID) + assert.NoError(t, err) + assert.Equal(t, tx.Status, Pending) + assert.Len(t, tx.Logs, 1) } diff --git a/transactions/bootstrapper.go b/transactions/bootstrapper.go index 6fd3e57bf..3d5c454fd 100644 --- a/transactions/bootstrapper.go +++ b/transactions/bootstrapper.go @@ -12,7 +12,7 @@ const ( // BootstrappedRepo is the key mapped to transactions.Repository. BootstrappedRepo = "BootstrappedRepo" - // BootstrappedService is the key to mapped transactions.Service + // BootstrappedService is the key to mapped transactions.Manager BootstrappedService = "BootstrappedService" ) @@ -29,7 +29,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { txRepo := NewRepository(repo) ctx[BootstrappedRepo] = txRepo - txSrv := NewService(txRepo) + txSrv := NewManager(txRepo) ctx[BootstrappedService] = txSrv return nil } diff --git a/transactions/handler.go b/transactions/handler.go index 585c5e5f3..4b2643d33 100644 --- a/transactions/handler.go +++ b/transactions/handler.go @@ -21,13 +21,13 @@ const ErrInvalidAccountID = errors.Error("Invalid Tenant ID") var apiLog = logging.Logger("transaction-api") // GRPCHandler returns an implementation of the TransactionServiceServer -func GRPCHandler(srv Service, configService config.Service) transactionspb.TransactionServiceServer { +func GRPCHandler(srv Manager, configService config.Service) transactionspb.TransactionServiceServer { return grpcHandler{srv: srv, configService: configService} } // grpcHandler implements transactionspb.TransactionServiceServer type grpcHandler struct { - srv Service + srv Manager configService config.Service } diff --git a/transactions/handler_test.go b/transactions/handler_test.go index 0042e1ef7..fdf5c8740 100644 --- a/transactions/handler_test.go +++ b/transactions/handler_test.go @@ -18,7 +18,7 @@ import ( func TestGRPCHandler_GetTransactionStatus(t *testing.T) { cService := ctx[config.BootstrappedConfigStorage].(config.Service) - h := GRPCHandler(ctx[BootstrappedService].(Service), cService) + h := GRPCHandler(ctx[BootstrappedService].(Manager), cService) req := new(transactionspb.TransactionStatusRequest) ctxl := testingconfig.HandlerContext(cService) @@ -39,7 +39,7 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { tcs, _ := cService.GetAllAccounts() accID, _ := tcs[0].GetIdentityID() cid, err := identity.ToCentID(accID) - tx := NewTransaction(cid, "") + tx := newTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) assert.Nil(t, res) diff --git a/transactions/manager.go b/transactions/manager.go new file mode 100644 index 000000000..0e766b56e --- /dev/null +++ b/transactions/manager.go @@ -0,0 +1,143 @@ +package transactions + +import ( + "context" + "fmt" + "time" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/satori/go.uuid" +) + +// Manager wraps the repository and exposes specific functions. +type Manager interface { + + // ExecuteWithinTX executes a transaction within a transaction + ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) + + // CreateTransaction + // TODO [TXManager] remove this once TX Manager update is complete + CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) + GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) + SaveTransaction(tx *Transaction) error + GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) + WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error +} + +// NewManager returns a Manager implementation. +func NewManager(repo Repository) Manager { + return &service{repo: repo} +} + +// service implements Manager. +// TODO [TXManager] convert this into an implementation of node.Server and start it at node start so that we can bring down transaction go routines cleanly +type service struct { + repo Repository +} + +// ExecuteWithinTX executes a transaction within a transaction. +func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { + t, err := s.repo.Get(accountID, existingTxID) + if err != nil { + t = newTransaction(accountID, desc) + err := s.SaveTransaction(t) + if err != nil { + return uuid.Nil, nil, err + } + } + done = make(chan bool) + go func(ctx context.Context) { + err := make(chan error) + go work(accountID, t.ID, s, err) + + select { + case e := <-err: + if e != nil { + t.Status = Failed + } else { + t.Status = Success + } + e = s.SaveTransaction(t) + if e != nil { + log.Error(e) + } + case <-ctx.Done(): + msg := fmt.Sprintf("Transaction %s for account %s with description \"%s\" is stopped because of context close", t.ID.String(), t.CID, t.Description) + log.Warningf(msg) + t.Logs = append(t.Logs, NewLog("context closed", msg)) + e := s.SaveTransaction(t) + if e != nil { + log.Error(e) + } + } + done <- true + }(ctx) + return t.ID, done, nil +} + +// SaveTransaction saves the transaction. +func (s *service) SaveTransaction(tx *Transaction) error { + err := s.repo.Save(tx) + if err != nil { + return err + } + return nil +} + +// GetTransaction returns the transaction associated with identity and id. +func (s *service) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) { + return s.repo.Get(accountID, id) +} + +// CreateTransaction creates a new transaction and saves it to the DB. +func (s *service) CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) { + tx := newTransaction(accountID, desc) + return tx, s.SaveTransaction(tx) +} + +// WaitForTransaction blocks until transaction status is moved from pending state. +// Note: use it with caution as this will block. +func (s *service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { + for { + resp, err := s.GetTransactionStatus(accountID, txID) + if err != nil { + return err + } + + switch Status(resp.Status) { + case Failed: + return errors.New("transaction failed: %v", resp.Message) + case Success: + return nil + default: + time.Sleep(10 * time.Millisecond) + continue + } + } +} + +// GetTransactionStatus returns the transaction status associated with identity and id. +func (s *service) GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { + tx, err := s.GetTransaction(identity, id) + if err != nil { + return nil, err + } + + var msg string + lastUpdated := tx.CreatedAt.UTC() + if len(tx.Logs) > 0 { + log := tx.Logs[len(tx.Logs)-1] + msg = log.Message + lastUpdated = log.CreatedAt.UTC() + } + + return &transactionspb.TransactionStatusResponse{ + TransactionId: tx.ID.String(), + Status: string(tx.Status), + Message: msg, + LastUpdated: utils.ToTimestamp(lastUpdated), + }, nil +} diff --git a/transactions/service_test.go b/transactions/manager_test.go similarity index 55% rename from transactions/service_test.go rename to transactions/manager_test.go index cf6baf2ce..fd2b8214a 100644 --- a/transactions/service_test.go +++ b/transactions/manager_test.go @@ -3,23 +3,69 @@ package transactions import ( + "context" "testing" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) +func TestService_ExecuteWithinTX_happy(t *testing.T) { + cid := identity.RandomCentID() + srv := ctx[BootstrappedService].(Manager) + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + err <- nil + }) + <-done + assert.NoError(t, err) + assert.NotNil(t, tid) + trn, err := srv.GetTransaction(cid, tid) + assert.NoError(t, err) + assert.Equal(t, Success, trn.Status) +} + +func TestService_ExecuteWithinTX_err(t *testing.T) { + cid := identity.RandomCentID() + srv := ctx[BootstrappedService].(Manager) + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + err <- errors.New("dummy") + }) + <-done + assert.NoError(t, err) + assert.NotNil(t, tid) + trn, err := srv.GetTransaction(cid, tid) + assert.NoError(t, err) + assert.Equal(t, Failed, trn.Status) +} + +func TestService_ExecuteWithinTX_ctxDone(t *testing.T) { + cid := identity.RandomCentID() + srv := ctx[BootstrappedService].(Manager) + ctx, canc := context.WithCancel(context.Background()) + tid, done, err := srv.ExecuteWithinTX(ctx, cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + // doing nothing + }) + canc() + <-done + assert.NoError(t, err) + assert.NotNil(t, tid) + trn, err := srv.GetTransaction(cid, tid) + assert.NoError(t, err) + assert.Equal(t, Pending, trn.Status) + assert.Contains(t, trn.Logs[0].Message, "stopped because of context close") +} + func TestService_GetTransaction(t *testing.T) { repo := ctx[BootstrappedRepo].(Repository) - srv := ctx[BootstrappedService].(Service) + srv := ctx[BootstrappedService].(Manager) cid := identity.RandomCentID() bytes := utils.RandomSlice(identity.CentIDLength) assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) - txn := NewTransaction(cid, "Some transaction") + txn := newTransaction(cid, "Some transaction") // no transaction txs, err := srv.GetTransactionStatus(cid, txn.ID) @@ -55,7 +101,7 @@ func TestService_GetTransaction(t *testing.T) { } func TestService_CreateTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(Service) + srv := ctx[BootstrappedService].(Manager) cid := identity.RandomCentID() tx, err := srv.CreateTransaction(cid, "test") assert.NoError(t, err) @@ -64,7 +110,7 @@ func TestService_CreateTransaction(t *testing.T) { } func TestService_WaitForTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(Service) + srv := ctx[BootstrappedService].(Manager) repo := ctx[BootstrappedRepo].(Repository) cid := identity.RandomCentID() diff --git a/transactions/repository_test.go b/transactions/repository_test.go index 9198babbb..6af3e64ff 100644 --- a/transactions/repository_test.go +++ b/transactions/repository_test.go @@ -60,7 +60,7 @@ func TestRepository(t *testing.T) { assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) repo := ctx[BootstrappedRepo].(Repository) - tx := NewTransaction(cid, "Some transaction") + tx := newTransaction(cid, "Some transaction") assert.NotNil(t, tx.ID) assert.NotNil(t, tx.CID) assert.Equal(t, Pending, tx.Status) diff --git a/transactions/service.go b/transactions/service.go deleted file mode 100644 index 24e3d9eb2..000000000 --- a/transactions/service.go +++ /dev/null @@ -1,91 +0,0 @@ -package transactions - -import ( - "time" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" -) - -// Service wraps the repository and exposes specific functions. -type Service interface { - CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) - GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) - SaveTransaction(tx *Transaction) error - GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) - WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error -} - -// NewService returns a Service implementation. -func NewService(repo Repository) Service { - return service{repo: repo} -} - -// service implements Service. -type service struct { - repo Repository -} - -// SaveTransaction saves the transaction. -func (s service) SaveTransaction(tx *Transaction) error { - return s.repo.Save(tx) -} - -// GetTransaction returns the transaction associated with identity and id. -func (s service) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) { - return s.repo.Get(accountID, id) -} - -// CreateTransaction creates a new transaction and saves it to the DB. -func (s service) CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) { - tx := NewTransaction(accountID, desc) - return tx, s.SaveTransaction(tx) -} - -// WaitForTransaction blocks until transaction status is moved from pending state. -// Note: use it with caution as this will block. -func (s service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { - for { - resp, err := s.GetTransactionStatus(accountID, txID) - if err != nil { - return err - } - - switch Status(resp.Status) { - case Failed: - return errors.New("transaction failed: %v", resp.Message) - case Success: - return nil - default: - time.Sleep(10 * time.Millisecond) - continue - } - } -} - -// GetTransactionStatus returns the transaction status associated with identity and id. -func (s service) GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { - tx, err := s.GetTransaction(identity, id) - if err != nil { - return nil, err - } - - var msg string - lastUpdated := tx.CreatedAt.UTC() - if len(tx.Logs) > 0 { - log := tx.Logs[len(tx.Logs)-1] - msg = log.Message - lastUpdated = log.CreatedAt.UTC() - } - - return &transactionspb.TransactionStatusResponse{ - TransactionId: tx.ID.String(), - Status: string(tx.Status), - Message: msg, - LastUpdated: utils.ToTimestamp(lastUpdated), - }, nil -} diff --git a/transactions/transaction.go b/transactions/transaction.go index 3e81b3c18..e0037478e 100644 --- a/transactions/transaction.go +++ b/transactions/transaction.go @@ -41,10 +41,16 @@ type Transaction struct { ID uuid.UUID CID identity.CentID Description string - Status Status - Logs []Log - Metadata map[string]string - CreatedAt time.Time + + // Status is the overall status of the transaction + Status Status + + // TaskStatus tracks the status of individual tasks running in the system for this transaction + TaskStatus map[string]Status + + // Logs are transaction log messages + Logs []Log + CreatedAt time.Time } // JSON returns json marshaled transaction. @@ -62,14 +68,14 @@ func (t *Transaction) Type() reflect.Type { return reflect.TypeOf(t) } -// NewTransaction returns a new transaction with a pending state -func NewTransaction(identity identity.CentID, description string) *Transaction { +// newTransaction returns a new transaction with a pending state +func newTransaction(identity identity.CentID, description string) *Transaction { return &Transaction{ ID: uuid.Must(uuid.NewV4()), CID: identity, Description: description, Status: Pending, - Metadata: make(map[string]string), + TaskStatus: make(map[string]Status), CreatedAt: time.Now().UTC(), } } From bf0a094a1a488729525c818bd6bd6801a23a4aff Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 30 Jan 2019 20:31:56 +0100 Subject: [PATCH 169/220] Fixed generate keys + more (#701) * Fixed generate keys + more * remove fmt * added restart test + tempHosts * revert change * missing push * linter lock * give time to host to come back --- Gopkg.toml | 1 - Makefile | 5 +++- config/configstore/service.go | 34 ++++----------------- config/configstore/service_test.go | 5 ---- documents/processor.go | 14 ++------- documents/processor_test.go | 36 ++-------------------- protobufs/gen/swagger.json | 1 + resources/data.go | 4 +-- testworld/document_consensus_test.go | 6 ++-- testworld/park.go | 28 +++++++++++++++++ testworld/park_test.go | 45 ++++++++++++++++++++++++++++ 11 files changed, 93 insertions(+), 86 deletions(-) create mode 100644 protobufs/gen/swagger.json diff --git a/Gopkg.toml b/Gopkg.toml index 30f1fb29f..406068c3d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" [[override]] diff --git a/Makefile b/Makefile index 8eb7be846..f920beca6 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,8 @@ PATH=$(shell printenv PATH):$(GOBIN) # If you need to overwrite PROTOTOOL_BIN, you can set this environment variable. PROTOTOOL_BIN ?=$(shell which prototool) +# Lock metalinter version +GOMETALINTER_VERSION="v2.0.12" .PHONY: help @@ -26,7 +28,7 @@ install-deps: ## Install Dependencies @command -v dep >/dev/null 2>&1 || go get -u github.com/golang/dep/... @dep ensure @npm --prefix ./build install - @curl -L https://git.io/vp6lP | sh + @curl -L https://git.io/vp6lP | sh -s ${GOMETALINTER_VERSION} @mv ./bin/* $(GOPATH)/bin/; rm -rf ./bin lint-check: ## runs linters on go code @@ -56,6 +58,7 @@ vendorinstall: ## Installs all protobuf dependencies with go-vendorinstall go-vendorinstall github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway go-vendorinstall github.com/golang/protobuf/protoc-gen-go go-vendorinstall github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger + go-vendorinstall golang.org/x/tools/cmd/goimports go get -u github.com/jteeuwen/go-bindata/... install: ## Builds and Install binary for development diff --git a/config/configstore/service.go b/config/configstore/service.go index c808309e1..c7f07b4c0 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -72,11 +72,11 @@ func (s service) GenerateAccount() (config.Account, error) { } // copy the main account for basic settings - mtc, err := NewAccount(nc.GetEthereumDefaultAccountName(), nc) + acc, err := NewAccount(nc.GetEthereumDefaultAccountName(), nc) if nil != err { return nil, err } - ctx, err := contextutil.New(context.Background(), mtc) + ctx, err := contextutil.New(context.Background(), acc) if err != nil { return nil, err } @@ -87,22 +87,13 @@ func (s service) GenerateAccount() (config.Account, error) { } <-confirmations - // copy the main account again to create the new account - acc, err := NewAccount(nc.GetEthereumDefaultAccountName(), nc) - if err != nil { - return nil, err - } - CID := id.CentID() acc, err = generateAccountKeys(nc.GetAccountsKeystore(), acc.(*Account), CID) if err != nil { return nil, err } - // minor hack to set same p2p keys as node to account: Set the new account ID to copy of main account and create p2p keys - mtcc := mtc.(*Account) - mtcc.IdentityID = CID[:] - err = s.idService.AddKeyFromConfig(mtcc, identity.KeyPurposeP2P) + err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeP2P) if err != nil { return nil, err } @@ -127,20 +118,9 @@ func (s service) GenerateAccount() (config.Account, error) { return acc, nil } +// generateAccountKeys at the moment generates only ethauth keys func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*Account, error) { acc.IdentityID = CID[:] - Pub, err := createKeyPath(keystore, CID, signingPubKeyName) - if err != nil { - return nil, err - } - Priv, err := createKeyPath(keystore, CID, signingPrivKeyName) - if err != nil { - return nil, err - } - acc.SigningKeyPair = KeyPair{ - Pub: Pub, - Priv: Priv, - } ePub, err := createKeyPath(keystore, CID, ethAuthPubKeyName) if err != nil { return nil, err @@ -153,11 +133,7 @@ func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*A Pub: ePub, Priv: ePriv, } - err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, "ed25519") - if err != nil { - return nil, err - } - err = crypto.GenerateSigningKeyPair(acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv, "secp256k1") + err = crypto.GenerateSigningKeyPair(acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv, crypto.CurveSecp256K1) if err != nil { return nil, err } diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index a6da4eb90..22de30e93 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -157,12 +157,7 @@ func TestService_Deleteaccount(t *testing.T) { func TestGenerateaccountKeys(t *testing.T) { tc, err := generateAccountKeys("/tmp/accounts/", &Account{}, identity.RandomCentID()) assert.Nil(t, err) - assert.NotNil(t, tc.SigningKeyPair) assert.NotNil(t, tc.EthAuthKeyPair) - _, err = os.Stat(tc.SigningKeyPair.Pub) - assert.False(t, os.IsNotExist(err)) - _, err = os.Stat(tc.SigningKeyPair.Priv) - assert.False(t, os.IsNotExist(err)) _, err = os.Stat(tc.EthAuthKeyPair.Pub) assert.False(t, os.IsNotExist(err)) _, err = os.Stat(tc.EthAuthKeyPair.Priv) diff --git a/documents/processor.go b/documents/processor.go index e479d729d..9b51e7259 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -178,16 +178,6 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("failed to get document root: %v", err) } - id, err := dp.config.GetIdentityID() - if err != nil { - return errors.New("failed to get self cent ID: %v", err) - } - - centID, err := identity.ToCentID(id) - if err != nil { - return errors.New("centID invalid: %v", err) - } - anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { return errors.New("failed to get anchor ID: %v", err) @@ -199,13 +189,13 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro } // generate message authentication code for the anchor call - mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, centID, rootHash), self.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) + mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, self.ID, rootHash), self.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { return errors.New("failed to generate ethereum MAC: %v", err) } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) - confirmations, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, centID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) + confirmations, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, self.ID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) if err != nil { return errors.New("failed to commit anchor: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index e8a2be3f5..343a6879f 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -293,48 +293,18 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) assert.Nil(t, err) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - oldID := cfg.GetString("identityId") - cfg.Set("identityId", "wrong id") - err = dp.AnchorDocument(ctxh, model) - model.AssertExpectations(t) - srv.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get self cent ID") - cfg.Set("identityId", "0x0102030405060708") - - // wrong ID - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - - err = dp.AnchorDocument(ctxh, model) + err = dp.AnchorDocument(context.Background(), model) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "centID invalid") - cfg.Set("identityId", oldID) - - // failed anchor commit - model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(5) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - - repo := mockRepo{} - repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("error")).Once() - dp.anchorRepository = repo - err = dp.AnchorDocument(ctxh, model) - model.AssertExpectations(t) - srv.AssertExpectations(t) - repo.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to commit anchor") + assert.Contains(t, err.Error(), "self value not found in the context") // success model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - repo = mockRepo{} + repo := mockRepo{} ch := make(chan *anchors.WatchCommit, 1) ch <- new(anchors.WatchCommit) repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ch, nil).Once() diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json new file mode 100644 index 000000000..eecdecc06 --- /dev/null +++ b/protobufs/gen/swagger.json @@ -0,0 +1 @@ +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/resources/data.go b/resources/data.go index 13234473e..096d1a148 100644 --- a/resources/data.go +++ b/resources/data.go @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1548259859, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1548415387, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547821748, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547976932, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 6aa850c64..078fd5ee5 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -75,10 +75,10 @@ func addExternalCollaborator_withinHost(t *testing.T, documentType string) { getDocumentAndCheck(bob.httpExpect, b, documentType, params) nonExistingDocumentCheck(bob.httpExpect, c, documentType, params) - // Bob updates invoice and shares with Charlie as well - res = updateDocument(bob.httpExpect, bob.id.String(), documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{a, c})) + // b updates invoice and shares with c as well + res = updateDocument(bob.httpExpect, b, documentType, http.StatusOK, docIdentifier, updatedDocumentPayload(documentType, []string{a, c})) txID = getTransactionID(t, res) - waitTillStatus(t, bob.httpExpect, bob.id.String(), txID, "success") + waitTillStatus(t, bob.httpExpect, b, txID, "success") docIdentifier = getDocumentIdentifier(t, res) if docIdentifier == "" { diff --git a/testworld/park.go b/testworld/park.go index 0baa5fd5f..f40321bfa 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -66,6 +66,9 @@ type hostManager struct { // niceHosts are the happy and nice hosts at the Testworld such as Teddy niceHosts map[string]*host + // tempHosts are hosts created at runtime, they should be part of niceHosts/naughtyHosts as well + tempHosts map[string]*host + // TODO create evil hosts such as William (or Eve) // canc is the cancel signal for all hosts @@ -90,6 +93,7 @@ func newHostManager( txPoolAccess: txPoolAccess, contractAddresses: smartContractAddrs, niceHosts: make(map[string]*host), + tempHosts: make(map[string]*host), } } @@ -169,6 +173,30 @@ func (r *hostManager) stop() { r.canc() } +func (r *hostManager) addNiceHost(name string, host *host) { + r.niceHosts[name] = host +} + +func (r *hostManager) createTempHost(name, twConfigName, p2pTimeout string, apiPort, p2pPort int64, createConfig, multiAccount bool, bootstraps []string) *host { + tempHost := r.createHost(name, twConfigName, p2pTimeout, apiPort, p2pPort, createConfig, multiAccount, bootstraps) + r.tempHosts[name] = tempHost + return tempHost +} + +func (r *hostManager) startTempHost(name string) error { + tempHost, ok := r.tempHosts[name] + if !ok { + return errors.New("host %s not found as temp host", name) + } + err := tempHost.init() + if err != nil { + return err + } + go tempHost.live(r.cancCtx) + + return nil +} + func (r *hostManager) createHost(name, twConfigName, p2pTimeout string, apiPort, p2pPort int64, createConfig, multiAccount bool, bootstraps []string) *host { return newHost( name, diff --git a/testworld/park_test.go b/testworld/park_test.go index 8840d777e..b562681aa 100644 --- a/testworld/park_test.go +++ b/testworld/park_test.go @@ -6,6 +6,9 @@ import ( "fmt" "net/http" "testing" + "time" + + "github.com/stretchr/testify/assert" ) func TestHost_Happy(t *testing.T) { @@ -33,3 +36,45 @@ func TestHost_Happy(t *testing.T) { getDocumentAndCheck(charlie.httpExpect, charlie.id.String(), typeInvoice, params) fmt.Println("Host test success") } + +func TestHost_RestartWithAccounts(t *testing.T) { + t.Parallel() + // Name can be randomly generated + tempHostName := "Sleepy" + bootnode, err := doctorFord.bernard.p2pURL() + assert.NoError(t, err) + sleepyHost := doctorFord.createTempHost(tempHostName, doctorFord.twConfigName, defaultP2PTimeout, 8088, 38208, true, true, []string{bootnode}) + doctorFord.addNiceHost(tempHostName, sleepyHost) + err = doctorFord.startTempHost(tempHostName) + assert.NoError(t, err) + up, err := sleepyHost.isLive(10 * time.Second) + assert.NoError(t, err) + assert.True(t, up) + sleepyTS := doctorFord.getHostTestSuite(t, tempHostName) + + // Create accounts for new host + err = sleepyHost.createAccounts(sleepyTS.httpExpect) + assert.NoError(t, err) + err = sleepyHost.loadAccounts(sleepyTS.httpExpect) + assert.NoError(t, err) + + // Verify accounts are created + acc1 := sleepyHost.accounts[0] + res := getAccount(sleepyTS.httpExpect, sleepyTS.id.String(), http.StatusOK, acc1) + acc1Res := res.Value("identity_id").String().NotEmpty() + acc1Res.Equal(acc1) + + // Stop host + sleepyHost.kill() + + // Start host + doctorFord.reLive(t, tempHostName) + up, err = sleepyHost.isLive(10 * time.Second) + assert.NoError(t, err) + assert.True(t, up) + + // Verify accounts are available after restart + res = getAccount(sleepyTS.httpExpect, sleepyTS.id.String(), http.StatusOK, acc1) + acc1Res = res.Value("identity_id").String().NotEmpty() + acc1Res.Equal(acc1) +} From ac0f87a8d4020d81da610dda7d96ce52c185d11e Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 31 Jan 2019 20:11:04 +0100 Subject: [PATCH 170/220] Key separation (#710) * key separation * fixes * fixes * fixes --- build/configs/testing_config.yaml | 3 + build/resources/centrifuge_example.yaml | 6 +- build/resources/p2pKey.key.pem | 4 + build/resources/p2pKey.pub.pem | 3 + cmd/common.go | 4 +- config/configstore/model.go | 28 +++++ config/configstore/model_test.go | 16 +++ config/configstore/service.go | 18 ++- config/configuration.go | 7 ++ coredocument/coredocument_test.go | 2 + documents/model_test.go | 2 + identity/identity.go | 9 +- identity/identity_test.go | 2 + nft/ethereum_payment_obligation_test.go | 1 + p2p/common/protocol_test.go | 4 + p2p/receiver/handler_integration_test.go | 13 +- p2p/receiver/validator.go | 2 +- p2p/server.go | 2 +- p2p/server_test.go | 8 +- protobufs/account/service.proto | 1 + protobufs/gen/go/account/service.pb.go | 119 ++++++++++-------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/account/service.swagger.json | 3 + .../gen/swagger/config/service.swagger.json | 3 + resources/data.go | 4 +- testingutils/config/config.go | 5 + testingutils/setup.go | 2 + 27 files changed, 201 insertions(+), 72 deletions(-) create mode 100644 build/resources/p2pKey.key.pem create mode 100644 build/resources/p2pKey.pub.pem diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index fc27f29c3..69b15a304 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -17,6 +17,9 @@ queue: workerWaitTimeMS: 1 keys: + p2p: + publicKey: ../../build/resources/p2pKey.pub.pem + privateKey: ../../build/resources/p2pKey.key.pem signing: publicKey: ../../build/resources/signingKey.pub.pem privateKey: ../../build/resources/signingKey.key.pem diff --git a/build/resources/centrifuge_example.yaml b/build/resources/centrifuge_example.yaml index 3abe8c7af..9b9346aaa 100644 --- a/build/resources/centrifuge_example.yaml +++ b/build/resources/centrifuge_example.yaml @@ -8,10 +8,10 @@ nodePort: 8082 identityId: "0x010101010101" keys: - signing: - publicKey: ../../build/resources/signingKey.pub.pem - privateKey: ../../build/resources/signingKey.key.pem p2p: + publicKey: ../../build/resources/p2pKey.pub.pem + privateKey: ../../build/resources/p2pKey.key.pem + signing: publicKey: ../../build/resources/signingKey.pub.pem privateKey: ../../build/resources/signingKey.key.pem ethauth: diff --git a/build/resources/p2pKey.key.pem b/build/resources/p2pKey.key.pem new file mode 100644 index 000000000..31413fb27 --- /dev/null +++ b/build/resources/p2pKey.key.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +XE4tQCuKdnL1aCljosI+G8jNnyb9qkwhCqT+Ex5N57EFcphUAFO+O55TAymfJuXl +ybobvNpgvM/znEpOSGg7Iw== +-----END PRIVATE KEY----- diff --git a/build/resources/p2pKey.pub.pem b/build/resources/p2pKey.pub.pem new file mode 100644 index 000000000..9a8b1733b --- /dev/null +++ b/build/resources/p2pKey.pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +BXKYVABTvjueUwMpnybl5cm6G7zaYLzP85xKTkhoOyM= +-----END PUBLIC KEY----- diff --git a/cmd/common.go b/cmd/common.go index 418803d6c..57bdd6dcf 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -34,9 +34,11 @@ func createIdentity(ctx context.Context, idService identity.Service) (identity.C } func generateKeys(config config.Configuration) { - p2pPub, p2pPvt := config.GetSigningKeyPair() + p2pPub, p2pPvt := config.GetP2PKeyPair() + signPub, signPvt := config.GetSigningKeyPair() ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") + crypto.GenerateSigningKeyPair(signPub, signPvt, "ed25519") crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } diff --git a/config/configstore/model.go b/config/configstore/model.go index 5f03341e9..fbdc93fcb 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -246,6 +246,11 @@ func (nc *NodeConfig) GetIdentityID() ([]byte, error) { return nc.MainIdentity.IdentityID, nil } +// GetP2PKeyPair refer the interface +func (nc *NodeConfig) GetP2PKeyPair() (pub, priv string) { + return nc.MainIdentity.P2PKeyPair.Pub, nc.MainIdentity.P2PKeyPair.Priv +} + // GetSigningKeyPair refer the interface func (nc *NodeConfig) GetSigningKeyPair() (pub, priv string) { return nc.MainIdentity.SigningKeyPair.Pub, nc.MainIdentity.SigningKeyPair.Priv @@ -396,6 +401,7 @@ func convertStringMapToSmartContractAddresses(addrs map[string]string) (map[conf func NewNodeConfig(c config.Configuration) config.Configuration { mainAccount, _ := c.GetEthereumAccount(c.GetEthereumDefaultAccountName()) mainIdentity, _ := c.GetIdentityID() + p2pPub, p2pPriv := c.GetP2PKeyPair() signPub, signPriv := c.GetSigningKeyPair() ethAuthPub, ethAuthPriv := c.GetEthAuthKeyPair() @@ -409,6 +415,10 @@ func NewNodeConfig(c config.Configuration) config.Configuration { EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), IdentityID: mainIdentity, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), + P2PKeyPair: KeyPair{ + Pub: p2pPub, + Priv: p2pPriv, + }, SigningKeyPair: KeyPair{ Pub: signPub, Priv: signPriv, @@ -484,6 +494,11 @@ func (acc *Account) GetIdentityID() ([]byte, error) { return acc.IdentityID, nil } +// GetP2PKeyPair gets P2PKeyPair +func (acc *Account) GetP2PKeyPair() (pub, priv string) { + return acc.P2PKeyPair.Pub, acc.P2PKeyPair.Priv +} + // GetSigningKeyPair gets SigningKeyPair func (acc *Account) GetSigningKeyPair() (pub, priv string) { return acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv @@ -533,6 +548,10 @@ func (acc *Account) CreateProtobuf() (*accountpb.AccountData, error) { EthDefaultAccountName: acc.EthereumDefaultAccountName, ReceiveEventNotificationEndpoint: acc.ReceiveEventNotificationEndpoint, IdentityId: hexutil.Encode(acc.IdentityID), + P2PKeyPair: &accountpb.KeyPair{ + Pub: acc.P2PKeyPair.Pub, + Pvt: acc.P2PKeyPair.Priv, + }, SigningKeyPair: &accountpb.KeyPair{ Pub: acc.SigningKeyPair.Pub, Pvt: acc.SigningKeyPair.Priv, @@ -551,6 +570,9 @@ func (acc *Account) loadFromProtobuf(data *accountpb.AccountData) error { if data.EthAccount == nil { return errors.NewTypedError(ErrNilParameter, errors.New("nil EthAccount field")) } + if data.P2PKeyPair == nil { + return errors.NewTypedError(ErrNilParameter, errors.New("nil P2PKeyPair field")) + } if data.SigningKeyPair == nil { return errors.NewTypedError(ErrNilParameter, errors.New("nil SigningKeyPair field")) } @@ -565,6 +587,10 @@ func (acc *Account) loadFromProtobuf(data *accountpb.AccountData) error { acc.EthereumDefaultAccountName = data.EthDefaultAccountName acc.IdentityID, _ = hexutil.Decode(data.IdentityId) acc.ReceiveEventNotificationEndpoint = data.ReceiveEventNotificationEndpoint + acc.P2PKeyPair = KeyPair{ + Pub: data.P2PKeyPair.Pub, + Priv: data.P2PKeyPair.Pvt, + } acc.SigningKeyPair = KeyPair{ Pub: data.SigningKeyPair.Pub, Priv: data.SigningKeyPair.Pvt, @@ -592,6 +618,7 @@ func NewAccount(ethAccountName string, c config.Configuration) (config.Account, EthereumContextWaitTimeout: c.GetEthereumContextWaitTimeout(), IdentityID: id, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), + P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil @@ -608,6 +635,7 @@ func TempAccount(ethAccountName string, c config.Configuration) (config.Account, EthereumDefaultAccountName: c.GetEthereumDefaultAccountName(), IdentityID: []byte{}, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), + P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 0f8561512..0aa29433c 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -236,6 +236,11 @@ func (m *mockConfig) GetIdentityID() ([]byte, error) { return args.Get(0).([]byte), args.Error(1) } +func (m *mockConfig) GetP2PKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} + func (m *mockConfig) GetSigningKeyPair() (pub, priv string) { args := m.Called() return args.Get(0).(string), args.Get(1).(string) @@ -259,6 +264,7 @@ func TestNewAccountConfig(t *testing.T) { c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() @@ -293,6 +299,7 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { c.On("GetEthereumDefaultAccountName").Return("dummyAcc") c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier") c.On("GetIdentityID").Return(utils.RandomSlice(6), nil) + c.On("GetP2PKeyPair").Return("pub", "priv") c.On("GetSigningKeyPair").Return("pub", "priv") c.On("GetEthAuthKeyPair").Return("pub", "priv") c.On("GetEthereumContextWaitTimeout").Return(time.Second) @@ -323,6 +330,13 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { assert.Error(t, err) accpb.EthAccount = ethacc.(*accountpb.EthereumAccount) + // Nil P2PKeyPair + p2pKey := proto.Clone(accpb.P2PKeyPair) + accpb.P2PKeyPair = nil + err = tco.loadFromProtobuf(accpb) + assert.Error(t, err) + accpb.P2PKeyPair = p2pKey.(*accountpb.KeyPair) + // Nil SigningKeyPair signKey := proto.Clone(accpb.SigningKeyPair) accpb.SigningKeyPair = nil @@ -344,6 +358,7 @@ func TestAccountConfigProtobuf(t *testing.T) { c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() @@ -381,6 +396,7 @@ func createMockConfig() *mockConfig { c.On("GetWorkerWaitTimeMS").Return(1).Once() c.On("GetEthereumNodeURL").Return("dummyNode").Once() c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() diff --git a/config/configstore/service.go b/config/configstore/service.go index c7f07b4c0..da2da1776 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -118,9 +118,21 @@ func (s service) GenerateAccount() (config.Account, error) { return acc, nil } -// generateAccountKeys at the moment generates only ethauth keys +// generateAccountKeys generates signing and ethauth keys func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*Account, error) { acc.IdentityID = CID[:] + sPub, err := createKeyPath(keystore, CID, signingPubKeyName) + if err != nil { + return nil, err + } + sPriv, err := createKeyPath(keystore, CID, signingPrivKeyName) + if err != nil { + return nil, err + } + acc.SigningKeyPair = KeyPair{ + Pub: sPub, + Priv: sPriv, + } ePub, err := createKeyPath(keystore, CID, ethAuthPubKeyName) if err != nil { return nil, err @@ -133,6 +145,10 @@ func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*A Pub: ePub, Priv: ePriv, } + err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, crypto.CurveEd25519) + if err != nil { + return nil, err + } err = crypto.GenerateSigningKeyPair(acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv, crypto.CurveSecp256K1) if err != nil { return nil, err diff --git a/config/configuration.go b/config/configuration.go index 77496cedb..95d1bdd7c 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -102,6 +102,7 @@ type Configuration interface { GetEthereumDefaultAccountName() string GetReceiveEventNotificationEndpoint() string GetIdentityID() ([]byte, error) + GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) @@ -120,6 +121,7 @@ type Account interface { GetEthereumDefaultAccountName() string GetReceiveEventNotificationEndpoint() string GetIdentityID() ([]byte, error) + GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration @@ -385,6 +387,11 @@ func (c *configuration) GetIdentityID() ([]byte, error) { return id, err } +// GetP2PKeyPair returns the P2P key pair. +func (c *configuration) GetP2PKeyPair() (pub, priv string) { + return c.GetString("keys.p2p.publicKey"), c.GetString("keys.p2p.privateKey") +} + // GetSigningKeyPair returns the signing key pair. func (c *configuration) GetSigningKeyPair() (pub, priv string) { return c.GetString("keys.signing.publicKey"), c.GetString("keys.signing.privateKey") diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 41e90a81c..de2c37961 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -32,6 +32,8 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") + cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/documents/model_test.go b/documents/model_test.go index 2dc922277..c0cdab28d 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -46,6 +46,8 @@ func TestMain(m *testing.M) { bootstrap.RunTestBootstrappers(ibootstappers, ctx) ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") + cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/identity/identity.go b/identity/identity.go index e5ab0ee13..36da39a4d 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -78,6 +78,7 @@ func (c CentID) BigInt() *big.Int { type Config interface { GetEthereumDefaultAccountName() string GetIdentityID() ([]byte, error) + GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration @@ -155,11 +156,17 @@ func GetIdentityConfig(config Config) (*IDConfig, error) { //ed25519 keys keys := map[int]IDKey{} - pk, sk, err := ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + + pk, sk, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) if err != nil { return nil, err } keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} + + pk, sk, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + if err != nil { + return nil, err + } keys[KeyPurposeSigning] = IDKey{PublicKey: pk, PrivateKey: sk} //secp256k1 keys diff --git a/identity/identity_test.go b/identity/identity_test.go index baaa92c7b..13388b8bd 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -23,6 +23,8 @@ func TestMain(m *testing.M) { } bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") + cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 4ab9f4769..b7519456f 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -202,6 +202,7 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetEthereumAccount").Return(&config.AccountConfig{}, nil) configMock.On("GetEthereumContextWaitTimeout").Return(time.Second) configMock.On("GetReceiveEventNotificationEndpoint").Return("") + configMock.On("GetP2PKeyPair").Return("", "") configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index d70db0d01..84fbb5cc8 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -91,6 +91,10 @@ func TestPrepareP2PEnvelope(t *testing.T) { spk, ssk := cfg.GetSigningKeyPair() acc := &configstore.Account{ IdentityID: id, + P2PKeyPair: configstore.KeyPair{ + Priv: ssk, + Pub: spk, + }, SigningKeyPair: configstore.KeyPair{ Priv: ssk, Pub: spk, diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 82df1a034..0ac3c3e74 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -117,7 +117,7 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { req := getSignatureRequest(doc) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, req) - pub, _ := cfg.GetSigningKeyPair() + pub, _ := cfg.GetP2PKeyPair() publicKey, err := cented25519.GetPublicSigningKey(pub) assert.NoError(t, err) var bPk [32]byte @@ -295,13 +295,20 @@ func createIdentity(t *testing.T) identity.CentID { idConfig, err := identity.GetIdentityConfig(cfg) // Add Keys - pubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey - confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeSigning, pubKey) + pubKey := idConfig.Keys[identity.KeyPurposeP2P].PublicKey + confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeP2P, pubKey) assert.Nil(t, err, "should not error out when adding key to identity") assert.NotNil(t, confirmations, "confirmations channel should not be nil") watchReceivedIdentity := <-confirmations assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") + sPubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey + confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeSigning, sPubKey) + assert.Nil(t, err, "should not error out when adding key to identity") + assert.NotNil(t, confirmations, "confirmations channel should not be nil") + watchReceivedIdentity = <-confirmations + assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") + secPubKey := idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, secPubKey) assert.Nil(t, err, "should not error out when adding key to identity") diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 83dd35ea4..5f976c55b 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -92,7 +92,7 @@ func peerValidator(idService identity.Service) Validator { if err != nil { return err } - return idService.ValidateKey(*centID, idKey, identity.KeyPurposeSigning) + return idService.ValidateKey(*centID, idKey, identity.KeyPurposeP2P) }) } diff --git a/p2p/server.go b/p2p/server.go index 8f93983e1..ab64c7aae 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -73,7 +73,7 @@ func (s *peer) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan<- // Make a host that listens on the given multiaddress // first obtain the keys configured - priv, pub, err := s.createSigningKey(nc.GetSigningKeyPair()) + priv, pub, err := s.createSigningKey(nc.GetP2PKeyPair()) if err != nil { startupErr <- err return diff --git a/p2p/server_test.go b/p2p/server_test.go index 1694b54e1..d89003734 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -109,7 +109,7 @@ func TestCentP2PServer_makeBasicHostNoExternalIP(t *testing.T) { c = updateKeys(c) listenPort := 38202 cp2p := &peer{config: cfg} - pu, pr := c.GetSigningKeyPair() + pu, pr := c.GetP2PKeyPair() priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, "", listenPort) assert.Nil(t, err) @@ -123,7 +123,7 @@ func TestCentP2PServer_makeBasicHostWithExternalIP(t *testing.T) { externalIP := "100.100.100.100" listenPort := 38202 cp2p := &peer{config: cfg} - pu, pr := c.GetSigningKeyPair() + pu, pr := c.GetP2PKeyPair() priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.Nil(t, err) @@ -141,7 +141,7 @@ func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { externalIP := "100.200.300.400" listenPort := 38202 cp2p := &peer{config: cfg} - pu, pr := c.GetSigningKeyPair() + pu, pr := c.GetP2PKeyPair() priv, pub, err := cp2p.createSigningKey(pu, pr) h, err := makeBasicHost(priv, pub, externalIP, listenPort) assert.NotNil(t, err) @@ -150,6 +150,8 @@ func TestCentP2PServer_makeBasicHostWithWrongExternalIP(t *testing.T) { func updateKeys(c config.Configuration) config.Configuration { n := c.(*configstore.NodeConfig) + n.MainIdentity.P2PKeyPair.Pub = "../build/resources/p2pKey.pub.pem" + n.MainIdentity.P2PKeyPair.Priv = "../build/resources/p2pKey.key.pem" n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" n.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" n.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" diff --git a/protobufs/account/service.proto b/protobufs/account/service.proto index 85b3e53ad..28e4090af 100644 --- a/protobufs/account/service.proto +++ b/protobufs/account/service.proto @@ -88,4 +88,5 @@ message AccountData { string identity_id = 4; KeyPair signing_key_pair = 5; KeyPair ethauth_key_pair = 6; + KeyPair p2p_key_pair = 7; } diff --git a/protobufs/gen/go/account/service.pb.go b/protobufs/gen/go/account/service.pb.go index 8fe29fcd3..31a0417bf 100644 --- a/protobufs/gen/go/account/service.pb.go +++ b/protobufs/gen/go/account/service.pb.go @@ -37,7 +37,7 @@ func (m *GetAccountRequest) Reset() { *m = GetAccountRequest{} } func (m *GetAccountRequest) String() string { return proto.CompactTextString(m) } func (*GetAccountRequest) ProtoMessage() {} func (*GetAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{0} + return fileDescriptor_service_55a49b82a8becf96, []int{0} } func (m *GetAccountRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAccountRequest.Unmarshal(m, b) @@ -75,7 +75,7 @@ func (m *GetAllAccountResponse) Reset() { *m = GetAllAccountResponse{} } func (m *GetAllAccountResponse) String() string { return proto.CompactTextString(m) } func (*GetAllAccountResponse) ProtoMessage() {} func (*GetAllAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{1} + return fileDescriptor_service_55a49b82a8becf96, []int{1} } func (m *GetAllAccountResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllAccountResponse.Unmarshal(m, b) @@ -114,7 +114,7 @@ func (m *UpdateAccountRequest) Reset() { *m = UpdateAccountRequest{} } func (m *UpdateAccountRequest) String() string { return proto.CompactTextString(m) } func (*UpdateAccountRequest) ProtoMessage() {} func (*UpdateAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{2} + return fileDescriptor_service_55a49b82a8becf96, []int{2} } func (m *UpdateAccountRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateAccountRequest.Unmarshal(m, b) @@ -161,7 +161,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{3} + return fileDescriptor_service_55a49b82a8becf96, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -214,7 +214,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{4} + return fileDescriptor_service_55a49b82a8becf96, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -255,6 +255,7 @@ type AccountData struct { IdentityId string `protobuf:"bytes,4,opt,name=identity_id,json=identityId,proto3" json:"identity_id,omitempty"` SigningKeyPair *KeyPair `protobuf:"bytes,5,opt,name=signing_key_pair,json=signingKeyPair,proto3" json:"signing_key_pair,omitempty"` EthauthKeyPair *KeyPair `protobuf:"bytes,6,opt,name=ethauth_key_pair,json=ethauthKeyPair,proto3" json:"ethauth_key_pair,omitempty"` + P2PKeyPair *KeyPair `protobuf:"bytes,7,opt,name=p2p_key_pair,json=p2pKeyPair,proto3" json:"p2p_key_pair,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -264,7 +265,7 @@ func (m *AccountData) Reset() { *m = AccountData{} } func (m *AccountData) String() string { return proto.CompactTextString(m) } func (*AccountData) ProtoMessage() {} func (*AccountData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_6af6824e0a923133, []int{5} + return fileDescriptor_service_55a49b82a8becf96, []int{5} } func (m *AccountData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AccountData.Unmarshal(m, b) @@ -326,6 +327,13 @@ func (m *AccountData) GetEthauthKeyPair() *KeyPair { return nil } +func (m *AccountData) GetP2PKeyPair() *KeyPair { + if m != nil { + return m.P2PKeyPair + } + return nil +} + func init() { proto.RegisterType((*GetAccountRequest)(nil), "account.GetAccountRequest") proto.RegisterType((*GetAllAccountResponse)(nil), "account.GetAllAccountResponse") @@ -539,53 +547,54 @@ var _AccountService_serviceDesc = grpc.ServiceDesc{ Metadata: "account/service.proto", } -func init() { proto.RegisterFile("account/service.proto", fileDescriptor_service_6af6824e0a923133) } - -var fileDescriptor_service_6af6824e0a923133 = []byte{ - // 710 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xd1, 0x6e, 0xd3, 0x4a, - 0x10, 0x95, 0xdb, 0xde, 0xf6, 0x66, 0x7c, 0x9b, 0xe6, 0xae, 0xd2, 0xca, 0x72, 0xef, 0x2d, 0x96, - 0x91, 0x50, 0x54, 0x68, 0x22, 0xb5, 0x0f, 0x40, 0x1e, 0x10, 0x29, 0x8d, 0x2a, 0x84, 0xa8, 0xaa, - 0x20, 0x1e, 0x40, 0x42, 0x61, 0x13, 0x4f, 0xed, 0x55, 0x93, 0xb5, 0xf1, 0x6e, 0x52, 0x45, 0x08, - 0x1e, 0xf8, 0x84, 0xf0, 0xce, 0x4f, 0xf1, 0x0b, 0xbc, 0xf0, 0x11, 0x48, 0xc8, 0xeb, 0xb5, 0xe3, - 0x90, 0x44, 0x88, 0xa7, 0x64, 0x77, 0xe6, 0x9c, 0x33, 0x67, 0x76, 0xc6, 0xb0, 0x4b, 0xfb, 0xfd, - 0x70, 0xc4, 0x65, 0x43, 0x60, 0x3c, 0x66, 0x7d, 0xac, 0x47, 0x71, 0x28, 0x43, 0xb2, 0xa5, 0xaf, - 0xed, 0xff, 0xfc, 0x30, 0xf4, 0x07, 0xd8, 0xa0, 0x11, 0x6b, 0x50, 0xce, 0x43, 0x49, 0x25, 0x0b, - 0xb9, 0x48, 0xd3, 0xec, 0x7d, 0x1d, 0x55, 0xa7, 0xde, 0xe8, 0xaa, 0x81, 0xc3, 0x48, 0x4e, 0x74, - 0xf0, 0x9e, 0xfa, 0xe9, 0x1f, 0xf9, 0xc8, 0x8f, 0xc4, 0x0d, 0xf5, 0x7d, 0x8c, 0x1b, 0x61, 0xa4, - 0xe0, 0x8b, 0x54, 0xee, 0x09, 0xfc, 0x7b, 0x8e, 0xb2, 0x95, 0xca, 0x76, 0xf0, 0xdd, 0x08, 0x85, - 0x24, 0x07, 0x00, 0xcc, 0x43, 0x2e, 0xd9, 0x15, 0xc3, 0xd8, 0x32, 0x1c, 0xa3, 0x56, 0xea, 0x14, - 0x6e, 0xdc, 0x16, 0xec, 0x26, 0xa0, 0xc1, 0x20, 0xc7, 0x89, 0x28, 0xe4, 0x02, 0x49, 0x0d, 0x36, - 0x3c, 0x2a, 0xa9, 0x65, 0x38, 0xeb, 0x35, 0xf3, 0xb8, 0x5a, 0xd7, 0x76, 0xea, 0x3a, 0xef, 0x8c, - 0x4a, 0xda, 0x51, 0x19, 0xee, 0x5b, 0xa8, 0xbe, 0x8c, 0x3c, 0x2a, 0xf1, 0xcf, 0xa4, 0x73, 0x85, - 0x35, 0xc7, 0xf8, 0x8d, 0xc2, 0x2b, 0xd8, 0x69, 0xcb, 0x00, 0x63, 0x1c, 0x0d, 0x75, 0x90, 0x58, - 0xb0, 0x45, 0x3d, 0x2f, 0x46, 0x21, 0x34, 0x73, 0x76, 0x24, 0x15, 0x58, 0xbf, 0xc6, 0x89, 0x62, - 0x2d, 0x75, 0x92, 0xbf, 0xc4, 0x86, 0xbf, 0x23, 0x2a, 0xc4, 0x4d, 0x18, 0x7b, 0xd6, 0xba, 0xba, - 0xce, 0xcf, 0xee, 0x11, 0x6c, 0x3d, 0xc3, 0xc9, 0x25, 0x65, 0x71, 0x02, 0x8c, 0x46, 0x3d, 0x4d, - 0x97, 0xfc, 0x55, 0x37, 0x63, 0x99, 0x51, 0x45, 0x63, 0xe9, 0x7e, 0x5f, 0x03, 0xb3, 0x50, 0x1f, - 0x79, 0x08, 0x26, 0xca, 0xa0, 0xab, 0x4b, 0x57, 0x58, 0xf3, 0xd8, 0xca, 0xad, 0xfc, 0x52, 0x75, - 0x07, 0x50, 0x06, 0x99, 0x83, 0xfb, 0x60, 0x25, 0x50, 0x0f, 0xaf, 0xe8, 0x68, 0x20, 0x33, 0x8a, - 0x2e, 0xa7, 0x43, 0xd4, 0x8a, 0xbb, 0x28, 0x83, 0xb3, 0x34, 0xac, 0x41, 0x17, 0x74, 0x88, 0xe4, - 0x39, 0xdc, 0x8e, 0xb1, 0x8f, 0x6c, 0x8c, 0x5d, 0x1c, 0x63, 0x02, 0x09, 0x93, 0x8e, 0xf6, 0xd5, - 0x30, 0x74, 0x91, 0x7b, 0x51, 0xc8, 0xb8, 0xd4, 0x4e, 0x1d, 0x9d, 0xda, 0x4e, 0x32, 0x2f, 0x0a, - 0x89, 0x6d, 0x9d, 0x47, 0x6e, 0x81, 0x99, 0x3e, 0x8a, 0x9c, 0x74, 0x99, 0x67, 0x6d, 0x14, 0xdf, - 0x49, 0x4e, 0x9e, 0x7a, 0xa4, 0x09, 0x15, 0xc1, 0x7c, 0xce, 0xb8, 0xdf, 0xbd, 0xc6, 0x49, 0x37, - 0xa2, 0x2c, 0xb6, 0xfe, 0x52, 0x46, 0x2b, 0xb9, 0x51, 0xdd, 0xc3, 0x4e, 0x59, 0x67, 0x66, 0x3d, - 0x6d, 0x42, 0x05, 0x65, 0x40, 0x47, 0x32, 0x98, 0x61, 0x37, 0x57, 0x61, 0x75, 0xa6, 0x3e, 0x1f, - 0xff, 0xd8, 0x80, 0xb2, 0xf6, 0xfd, 0x22, 0x5d, 0x2d, 0xc2, 0x01, 0x66, 0x23, 0x4e, 0xec, 0x9c, - 0x62, 0x61, 0xee, 0xed, 0xa5, 0xe3, 0xe4, 0xd6, 0xa7, 0xad, 0x6d, 0xdb, 0x3c, 0x47, 0xe9, 0xe8, - 0xdb, 0x4f, 0x5f, 0xbf, 0x7d, 0x5e, 0xb3, 0xc8, 0x5e, 0x43, 0x67, 0x8b, 0xc6, 0xfb, 0xd9, 0x84, - 0x7e, 0x20, 0x11, 0x94, 0xe7, 0xb6, 0x43, 0x90, 0xbd, 0x7a, 0xba, 0xb0, 0xf5, 0x6c, 0x61, 0xeb, - 0xed, 0x64, 0x61, 0xed, 0x83, 0xb9, 0x5a, 0x16, 0xd6, 0xc9, 0xbd, 0x33, 0x6d, 0x11, 0xbb, 0xa2, - 0x94, 0x07, 0x83, 0x4c, 0x5d, 0x28, 0x79, 0x93, 0x94, 0x72, 0x79, 0x12, 0xc0, 0xf6, 0x93, 0x18, - 0x67, 0xcb, 0x44, 0x96, 0x1a, 0x59, 0x61, 0xef, 0xee, 0xb4, 0x55, 0xb5, 0x49, 0x8a, 0x17, 0x0e, - 0xe5, 0x73, 0x2e, 0xcb, 0xee, 0x4c, 0xa6, 0x69, 0x1c, 0x92, 0x2f, 0x06, 0xec, 0x9c, 0x23, 0xc7, - 0xb8, 0x20, 0xb6, 0xca, 0xdd, 0x72, 0xb9, 0x37, 0xd3, 0xd6, 0x63, 0xfb, 0x51, 0xc6, 0x51, 0x14, - 0x74, 0x24, 0xbd, 0x66, 0xdc, 0x77, 0xf4, 0x70, 0x0b, 0xa7, 0x47, 0x05, 0x7a, 0x4e, 0xc8, 0x1d, - 0x19, 0xa0, 0x33, 0xa4, 0x8c, 0x3b, 0xb4, 0x50, 0x5a, 0xd5, 0x25, 0xb3, 0x07, 0xf0, 0x35, 0x1f, - 0xf9, 0x08, 0xdb, 0x73, 0xdf, 0x15, 0xf2, 0x7f, 0x5e, 0xc5, 0xb2, 0xef, 0xcd, 0x8a, 0x22, 0x1f, - 0xa8, 0x9e, 0xa4, 0x80, 0x85, 0x9e, 0xec, 0xdb, 0x2b, 0x5e, 0xbe, 0x69, 0x1c, 0x9e, 0xd6, 0xc0, - 0xec, 0x87, 0xc3, 0x8c, 0xf4, 0xf4, 0x1f, 0x3d, 0x84, 0x97, 0x49, 0x6b, 0x2e, 0x8d, 0xd7, 0x25, - 0x1d, 0x88, 0x7a, 0xbd, 0x4d, 0xd5, 0xae, 0x93, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb4, 0xaa, - 0x95, 0x34, 0x0b, 0x06, 0x00, 0x00, +func init() { proto.RegisterFile("account/service.proto", fileDescriptor_service_55a49b82a8becf96) } + +var fileDescriptor_service_55a49b82a8becf96 = []byte{ + // 724 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xd1, 0x6a, 0xdb, 0x48, + 0x14, 0x45, 0x71, 0x36, 0x5e, 0x5f, 0x25, 0x8e, 0x77, 0x70, 0x82, 0x50, 0x76, 0xb3, 0x42, 0x0b, + 0x8b, 0xc9, 0x6e, 0x6c, 0x70, 0x1e, 0x76, 0xeb, 0x87, 0x52, 0xa7, 0x31, 0xa1, 0x94, 0x86, 0xe0, + 0xd2, 0x87, 0x16, 0x8a, 0x3b, 0xb6, 0x6e, 0xa4, 0x21, 0xf6, 0x68, 0xaa, 0x19, 0x3b, 0x98, 0xd2, + 0x3e, 0xf4, 0x13, 0xdc, 0xe7, 0xf6, 0xa7, 0xfa, 0x0b, 0xfd, 0x8d, 0x42, 0x91, 0x34, 0x92, 0xed, + 0xda, 0xa6, 0xf4, 0x49, 0x33, 0x73, 0xef, 0xb9, 0xe7, 0x9e, 0x3b, 0x73, 0x04, 0x07, 0x74, 0x30, + 0x08, 0xc7, 0x5c, 0x35, 0x24, 0x46, 0x13, 0x36, 0xc0, 0xba, 0x88, 0x42, 0x15, 0x92, 0xa2, 0x3e, + 0xb6, 0x7f, 0xf7, 0xc3, 0xd0, 0x1f, 0x62, 0x83, 0x0a, 0xd6, 0xa0, 0x9c, 0x87, 0x8a, 0x2a, 0x16, + 0x72, 0x99, 0xa6, 0xd9, 0x47, 0x3a, 0x9a, 0xec, 0xfa, 0xe3, 0x9b, 0x06, 0x8e, 0x84, 0x9a, 0xea, + 0xe0, 0xbf, 0xc9, 0x67, 0x70, 0xea, 0x23, 0x3f, 0x95, 0x77, 0xd4, 0xf7, 0x31, 0x6a, 0x84, 0x22, + 0x81, 0xaf, 0x96, 0x72, 0xcf, 0xe0, 0xb7, 0x4b, 0x54, 0xed, 0x94, 0xb6, 0x8b, 0xaf, 0xc7, 0x28, + 0x15, 0x39, 0x06, 0x60, 0x1e, 0x72, 0xc5, 0x6e, 0x18, 0x46, 0x96, 0xe1, 0x18, 0xb5, 0x52, 0x77, + 0xe1, 0xc4, 0x6d, 0xc3, 0x41, 0x0c, 0x1a, 0x0e, 0x73, 0x9c, 0x14, 0x21, 0x97, 0x48, 0x6a, 0xb0, + 0xed, 0x51, 0x45, 0x2d, 0xc3, 0x29, 0xd4, 0xcc, 0x66, 0xb5, 0xae, 0xe5, 0xd4, 0x75, 0xde, 0x05, + 0x55, 0xb4, 0x9b, 0x64, 0xb8, 0xaf, 0xa0, 0xfa, 0x4c, 0x78, 0x54, 0xe1, 0xcf, 0x51, 0xe7, 0x0c, + 0x5b, 0x8e, 0xf1, 0x03, 0x86, 0xe7, 0xb0, 0xdf, 0x51, 0x01, 0x46, 0x38, 0x1e, 0xe9, 0x20, 0xb1, + 0xa0, 0x48, 0x3d, 0x2f, 0x42, 0x29, 0x75, 0xe5, 0x6c, 0x4b, 0x2a, 0x50, 0xb8, 0xc5, 0x69, 0x52, + 0xb5, 0xd4, 0x8d, 0x97, 0xc4, 0x86, 0x5f, 0x05, 0x95, 0xf2, 0x2e, 0x8c, 0x3c, 0xab, 0x90, 0x1c, + 0xe7, 0x7b, 0xf7, 0x14, 0x8a, 0x8f, 0x71, 0x7a, 0x4d, 0x59, 0x14, 0x03, 0xc5, 0xb8, 0xaf, 0xcb, + 0xc5, 0xcb, 0xe4, 0x64, 0xa2, 0xb2, 0x52, 0x62, 0xa2, 0xdc, 0x8f, 0x05, 0x30, 0x17, 0xfa, 0x23, + 0xf7, 0xc0, 0x44, 0x15, 0xf4, 0x74, 0xeb, 0x09, 0xd6, 0x6c, 0x5a, 0xb9, 0x94, 0xef, 0xba, 0xee, + 0x02, 0xaa, 0x20, 0x53, 0xf0, 0x1f, 0x58, 0x31, 0xd4, 0xc3, 0x1b, 0x3a, 0x1e, 0xaa, 0xac, 0x44, + 0x8f, 0xd3, 0x11, 0x6a, 0xc6, 0x03, 0x54, 0xc1, 0x45, 0x1a, 0xd6, 0xa0, 0x2b, 0x3a, 0x42, 0xf2, + 0x04, 0xfe, 0x8a, 0x70, 0x80, 0x6c, 0x82, 0x3d, 0x9c, 0x60, 0x0c, 0x09, 0xe3, 0x89, 0x0e, 0x92, + 0xc7, 0xd0, 0x43, 0xee, 0x89, 0x90, 0x71, 0xa5, 0x95, 0x3a, 0x3a, 0xb5, 0x13, 0x67, 0x5e, 0x2d, + 0x24, 0x76, 0x74, 0x1e, 0xf9, 0x13, 0xcc, 0xf4, 0x52, 0xd4, 0xb4, 0xc7, 0x3c, 0x6b, 0x7b, 0xf1, + 0x9e, 0xd4, 0xf4, 0x91, 0x47, 0x5a, 0x50, 0x91, 0xcc, 0xe7, 0x8c, 0xfb, 0xbd, 0x5b, 0x9c, 0xf6, + 0x04, 0x65, 0x91, 0xf5, 0x4b, 0x22, 0xb4, 0x92, 0x0b, 0xd5, 0x33, 0xec, 0x96, 0x75, 0x66, 0x36, + 0xd3, 0x16, 0x54, 0x50, 0x05, 0x74, 0xac, 0x82, 0x39, 0x76, 0x67, 0x13, 0x56, 0x67, 0x66, 0xd8, + 0x26, 0xec, 0x8a, 0xa6, 0x98, 0xe3, 0x8a, 0x1b, 0x70, 0x20, 0x9a, 0x42, 0xaf, 0x9b, 0x5f, 0xb7, + 0xa1, 0xac, 0x67, 0xf5, 0x34, 0xb5, 0x23, 0xe1, 0x00, 0x73, 0x5b, 0x10, 0x3b, 0x87, 0xaf, 0x78, + 0xc5, 0x5e, 0xfb, 0x04, 0xdd, 0xfa, 0xac, 0xbd, 0x67, 0x9b, 0x97, 0xa8, 0x1c, 0x7d, 0xfa, 0xfe, + 0xf3, 0x97, 0x0f, 0x5b, 0x16, 0x39, 0x6c, 0xe8, 0x6c, 0xd9, 0x78, 0x33, 0x7f, 0xd5, 0x6f, 0x89, + 0x80, 0xf2, 0x92, 0xa3, 0x24, 0x39, 0xac, 0xa7, 0x26, 0xaf, 0x67, 0x26, 0xaf, 0x77, 0x62, 0x93, + 0xdb, 0xc7, 0x4b, 0xbd, 0xac, 0x58, 0xd0, 0xfd, 0x7b, 0xd6, 0x26, 0x76, 0x25, 0x61, 0x1e, 0x0e, + 0x33, 0x76, 0x99, 0xd0, 0x9b, 0xa4, 0x94, 0xd3, 0x93, 0x00, 0xf6, 0x1e, 0x46, 0x38, 0x37, 0x20, + 0x59, 0x2b, 0x64, 0x83, 0xbc, 0x7f, 0x66, 0xed, 0xaa, 0x4d, 0x52, 0xbc, 0x74, 0x28, 0x5f, 0x52, + 0x59, 0x76, 0xe7, 0x34, 0x2d, 0xe3, 0x84, 0x7c, 0x32, 0x60, 0xff, 0x12, 0x39, 0x46, 0x0b, 0x64, + 0x9b, 0xd4, 0xad, 0xa7, 0x7b, 0x39, 0x6b, 0x3f, 0xb0, 0xef, 0x67, 0x35, 0x16, 0x09, 0x1d, 0x45, + 0x6f, 0x19, 0xf7, 0x1d, 0x6d, 0x08, 0xe9, 0xf4, 0xa9, 0x44, 0xcf, 0x09, 0xb9, 0xa3, 0x02, 0x74, + 0x46, 0x94, 0x71, 0x87, 0x2e, 0xb4, 0x56, 0x75, 0xc9, 0xfc, 0x02, 0x7c, 0x5d, 0x8f, 0xbc, 0x83, + 0xbd, 0xa5, 0x7f, 0x11, 0xf9, 0x23, 0xef, 0x62, 0xdd, 0x3f, 0x6a, 0x43, 0x93, 0xff, 0x27, 0x33, + 0x49, 0x01, 0x2b, 0x33, 0x39, 0xb2, 0x37, 0xdc, 0x7c, 0xcb, 0x38, 0x39, 0xaf, 0x81, 0x39, 0x08, + 0x47, 0x59, 0xd1, 0xf3, 0x5d, 0xfd, 0x08, 0xaf, 0xe3, 0xd1, 0x5c, 0x1b, 0x2f, 0x4a, 0x3a, 0x20, + 0xfa, 0xfd, 0x9d, 0x64, 0x5c, 0x67, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x75, 0xab, 0xa4, + 0x3f, 0x06, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index eecdecc06..cf8024866 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/account/service.swagger.json b/protobufs/gen/swagger/account/service.swagger.json index 92399f5c6..2810765e6 100644 --- a/protobufs/gen/swagger/account/service.swagger.json +++ b/protobufs/gen/swagger/account/service.swagger.json @@ -152,6 +152,9 @@ }, "ethauth_key_pair": { "$ref": "#/definitions/accountKeyPair" + }, + "p2p_key_pair": { + "$ref": "#/definitions/accountKeyPair" } } }, diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index ebbdf78a8..216d3b45b 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -54,6 +54,9 @@ }, "ethauth_key_pair": { "$ref": "#/definitions/accountKeyPair" + }, + "p2p_key_pair": { + "$ref": "#/definitions/accountKeyPair" } } }, diff --git a/resources/data.go b/resources/data.go index 096d1a148..4022448bd 100644 --- a/resources/data.go +++ b/resources/data.go @@ -89,7 +89,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\x3b\x6f\xe4\x36\x10\xee\xf5\x2b\x88\x49\xe1\x66\x1f\x7c\x8a\x8f\x2e\x65\x70\x48\x9a\x04\xb8\x7a\x48\x0e\xd7\xc2\x7a\xb5\x0a\x49\xd9\xb7\x38\xdc\x7f\x0f\xb4\xb7\x8e\x53\x3a\x50\x33\x33\xfa\x1e\x33\xd2\x97\x68\xee\x75\x2a\xeb\x89\xfe\xa0\xfe\x76\xad\xe7\xc0\x3a\xb5\x3e\xcd\xa7\x81\xfa\x33\x55\x5a\x2f\x61\x60\x0c\x53\xba\xae\x73\x6f\x5b\xcd\xd8\x05\xa7\x39\xb0\x7b\xc9\xd8\x99\x6e\x81\x3d\x7d\x07\xcc\xb9\x52\x6b\x10\xc0\xf9\xc8\xd1\x8d\xc6\xa9\xa4\xb5\xd6\x98\x4a\xb6\x22\xea\x51\x11\xcf\x2a\x19\x83\x24\xb4\x90\x68\x60\x07\xa9\xde\x96\x7e\x85\xf0\x1d\xd2\xb4\x3c\x53\x85\x00\x48\x6d\x2f\xa4\xdb\xa7\x5e\x37\xc0\x7d\xdc\xe9\x5b\x87\x00\xc9\x5a\x5f\x9c\xb2\x3e\x5b\xcb\xb3\x97\xa9\x24\x91\x73\xd6\xe8\x8a\x12\xd9\x20\xc7\x9c\x5c\x91\xc8\xa3\x44\xa1\xb9\x50\x96\x67\x35\x2a\x5e\x94\x4b\x3c\x39\xfc\x57\x6f\xc1\x8a\x97\xb6\xd9\x4e\xaf\x10\x40\x8d\x49\x8c\x8e\xac\x8a\xc5\x3b\x5e\xc8\x9a\xc8\xad\xb4\xc5\x79\x8e\x56\x60\x86\x1f\x3b\x38\xe7\x02\x01\xda\x7d\x61\xb8\xb7\x1f\x22\xf9\xfc\x42\x33\x04\x25\x77\x30\x43\x90\xa3\x14\x5a\xef\x60\x81\x20\x76\x50\x21\xb8\x1d\x34\x7c\xd9\x0e\xc8\x24\x22\x89\x91\x54\xf2\x4e\x78\xad\xb3\xa0\x84\x32\xba\x28\x2d\x69\x1a\x89\x47\x13\x4b\xd4\x2a\x12\x57\x76\x44\x93\x9d\x73\xbe\xe0\x68\x3d\x4a\x27\xa4\xdc\x16\xb9\x60\xda\x3e\x45\x12\xd2\x45\x27\x8c\x31\x26\xa2\x20\xcc\x36\x21\x79\x3e\x72\x72\x4e\x4b\x2c\x09\x9d\x32\x63\xe6\xa3\x36\x26\x66\x8f\xc6\x1a\x19\x71\x2c\x29\x71\x2f\xa9\x6c\x4a\x53\x86\x00\xda\x10\x1f\x39\x8e\xfb\x2c\x91\xf6\x5a\x45\xb7\xf7\x52\x96\xbd\xd6\x4e\x7a\xed\x7d\x56\x36\xc3\x0e\x5e\xa9\xb6\xe9\xba\x1d\xf9\xe3\xe9\xf1\xe3\x17\x6c\xed\xed\x5a\x73\x60\x4f\xef\xa3\x47\x06\x02\xfb\x6c\x04\x86\x61\xca\x34\xf7\xa9\xdf\x7e\xcb\x81\x01\xff\xc6\xc5\xc7\x03\xc3\xf0\x0b\xfb\xf5\x91\xbc\x2d\x67\xac\xf5\x6b\xc5\x13\x0d\xff\x8d\xe3\x99\x6e\xdb\x98\x02\x3b\xf6\xcb\x72\x7c\x7f\x35\x0c\x7f\xaf\xb4\xd2\x86\x98\xd7\xcb\xd7\x6b\x3d\x53\x6d\x81\xc9\x81\xb1\xb7\x7b\xf3\x15\xa7\xfe\xd7\x74\xa1\xdf\xff\x0c\x4c\x0c\xc3\x26\xb3\x81\xdb\x74\x9a\xa7\xf9\xf4\x33\xe8\xcb\x1a\x5f\xa6\xf4\x65\x4b\xf8\xe1\x70\x3c\x1c\x8e\x71\x9d\x5e\xf2\xb1\x52\xbb\xae\x35\x51\x3b\x3e\xd0\x5f\xe8\x76\x58\xd6\x78\x58\xe8\xf2\x93\x57\xa7\x57\xec\xf4\x39\xe2\x79\x23\xdf\x89\xd4\x9f\x71\xed\xcf\x9f\xf4\x7e\xa0\xff\xa7\xf1\x3b\xeb\xdd\xf5\x9f\x00\x00\x00\xff\xff\x6a\x9a\xa9\xc9\x01\x04\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x88\x49\x71\xcd\x3e\xf8\x14\x1f\x5d\xca\xc0\x48\x9a\x04\x70\x3d\x24\x87\x7b\xc2\xde\x4a\x0a\x45\xdd\x79\x61\xf8\xbf\x07\x5a\xef\xe6\xdc\xf9\x0c\x35\x33\xa3\xef\x31\x23\x7d\x89\xc6\x56\x87\xb2\x9e\xe8\x2f\x6a\x6f\x53\x3d\x07\xd6\x68\x69\xc3\x78\xea\xa8\x3d\x53\xa5\xf5\x12\x3a\xc6\x30\xa5\x69\x1d\xdb\xb2\xd5\x8c\x5d\x70\x18\x03\xbb\x95\x8c\x9d\xe9\x1a\xd8\xd3\x57\xc0\x9c\x2b\x2d\x0b\x04\x70\x3e\x72\x74\xbd\x71\x2a\x69\xad\x35\xa6\x92\xad\x88\xba\x57\xc4\xb3\x4a\xc6\x20\x09\x2d\x24\x1a\xd8\x41\xaa\xd7\xb9\x4d\x10\xbe\x42\x1a\xe6\x67\xaa\x10\x00\x69\xd9\x0b\xe9\xf6\xa9\xd5\x0d\x70\x1b\x37\xfa\xd2\x20\x40\xb2\xd6\x17\xa7\xac\xcf\xd6\xf2\xec\x65\x2a\x49\xe4\x9c\x35\xba\xa2\x44\x36\xc8\x31\x27\x57\x24\xf2\x28\x51\x68\x2e\x94\xe5\x59\xf5\x8a\x17\xe5\x12\x4f\x0e\xff\xd7\x9b\xb1\xe2\x65\xd9\x6c\x87\x57\x08\xa0\xfa\x24\x7a\x47\x56\xc5\xe2\x1d\x2f\x64\x4d\xe4\x56\xda\xe2\x3c\x47\x2b\x30\xc3\xb7\x1d\x9c\x73\x81\x00\xcb\x6d\x61\xb8\xb5\xef\x22\xf9\xfc\x42\x23\x04\x25\x77\x30\x42\x90\xbd\x14\x5a\xef\x60\x86\x20\x76\x50\x21\xb8\x1d\x2c\xf8\xb2\x1d\x90\x49\x44\x12\x3d\xa9\xe4\x9d\xf0\x5a\x67\x41\x09\x65\x74\x51\x5a\xd2\xd4\x13\x8f\x26\x96\xa8\x55\x24\xae\x6c\x8f\x26\x3b\xe7\x7c\xc1\xde\x7a\x94\x4e\x48\xb9\x2d\x72\xc1\xb4\x7d\x8a\x24\xa4\x8b\x4e\x18\x63\x4c\x44\x41\x98\x6d\x42\xf2\xbc\xe7\xe4\x9c\x96\x58\x12\x3a\x65\xfa\xcc\x7b\x6d\x4c\xcc\x1e\x8d\x35\x32\x62\x5f\x52\xe2\x5e\x52\xd9\x94\x86\x0c\x01\xb4\x21\xde\x73\xec\xf7\x59\x22\xed\xb5\x8a\x6e\xef\xa5\x2c\x7b\xad\x9d\xf4\xda\xfb\xac\x6c\x86\x1d\xbc\x52\x5d\x86\x69\x3b\xf2\xdb\xd3\xfd\xc7\xcf\xb8\x2c\x6f\x53\xcd\x81\x3d\x3d\x46\xf7\x0c\x04\xf6\xd1\x08\x74\xdd\x90\x69\x6c\x43\xbb\xfe\x91\x03\x03\xfe\x85\x8b\xf7\x07\xba\xee\x37\xf6\xfb\x3d\x79\x5b\xce\xd8\xd2\xa6\x8a\x27\xea\x7e\x8c\xe3\x99\xae\xdb\x98\x02\x3b\xb6\xcb\x7c\x7c\xbc\xea\xba\x7f\x57\x5a\x69\x43\x8c\xeb\xe5\xf3\x54\xcf\x54\x97\xc0\x64\xc7\xd8\xdb\xad\xf9\x8c\x43\xfb\x67\xb8\xd0\x9f\x7f\x07\x26\xba\x6e\x93\xd9\xc0\xb3\x9c\xbf\x87\x7c\x5e\xe3\xcb\x90\x3e\x6d\xe9\x3e\x1c\x8e\x87\xc3\x31\xae\xc3\x4b\x3e\x56\x5a\xa6\xb5\x26\x5a\x8e\xb3\x9c\x3f\xd1\xf5\x30\xaf\xf1\x30\xd3\xe5\x3b\xa7\x0e\xaf\xd8\xe8\xe7\xa4\xf3\x46\xbc\x91\x96\xe1\x34\x0e\xe3\xe9\x83\x9e\x77\xf4\xaf\xfb\xfe\x40\x7c\xf7\xa6\xf6\x8c\x6b\x7b\xfe\xa0\xf7\x1d\xfd\x8b\xc6\x0f\xd6\xc3\xf5\xbf\x00\x00\x00\xff\xff\x7b\xa2\x4f\x3f\x71\x04\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1025, mode: os.FileMode(420), modTime: time.Unix(1547976932, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1137, mode: os.FileMode(420), modTime: time.Unix(1548944078, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testingutils/config/config.go b/testingutils/config/config.go index b8e8df00c..fc8aee376 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -152,6 +152,11 @@ func (m *MockConfig) GetIdentityID() ([]byte, error) { return args.Get(0).([]byte), args.Error(1) } +func (m *MockConfig) GetP2PKeyPair() (pub, priv string) { + args := m.Called() + return args.Get(0).(string), args.Get(1).(string) +} + func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { args := m.Called() return args.Get(0).(string), args.Get(1).(string) diff --git a/testingutils/setup.go b/testingutils/setup.go index 5c71fce80..cde119210 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -144,6 +144,8 @@ func BuildIntegrationTestingContext() map[string]interface{} { RunSmartContractMigrations() addresses := GetSmartContractAddresses() cfg := LoadTestConfig() + cfg.Set("keys.p2p.publicKey", fmt.Sprintf("%s/build/resources/p2pKey.pub.pem", projDir)) + cfg.Set("keys.p2p.privateKey", fmt.Sprintf("%s/build/resources/p2pKey.key.pem", projDir)) cfg.Set("keys.signing.publicKey", fmt.Sprintf("%s/build/resources/signingKey.pub.pem", projDir)) cfg.Set("keys.signing.privateKey", fmt.Sprintf("%s/build/resources/signingKey.key.pem", projDir)) cfg.Set("keys.ethauth.publicKey", fmt.Sprintf("%s/build/resources/ethauth.pub.pem", projDir)) From ac541f2e6b980ebc4643153572f06ea0c4868cb5 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 4 Feb 2019 15:34:16 +0100 Subject: [PATCH 171/220] Fix NFT rule/role update order (#711) * Fix NFT role update order * Update services to use tx manager * Fix return for work func * Fix token ID error * Fix token ID error * Fix tests * Fix tests * Fix tests * Fix lint * Review comments --- documents/anchor_task.go | 52 +++-- documents/bootstrapper.go | 8 - documents/bootstrapper_test.go | 2 +- documents/invoice/handler.go | 4 +- documents/invoice/handler_test.go | 8 +- documents/invoice/model_test.go | 22 ++- documents/invoice/service.go | 40 ++-- documents/invoice/service_test.go | 12 +- documents/nft_created_task.go | 173 ---------------- documents/nft_created_task_test.go | 52 ----- documents/purchaseorder/handler.go | 4 +- documents/purchaseorder/handler_test.go | 8 +- documents/purchaseorder/model_test.go | 9 +- documents/purchaseorder/service.go | 32 ++- documents/purchaseorder/service_test.go | 12 +- documents/service.go | 12 +- ethereum/geth_client.go | 2 - ethereum/transaction_status_task.go | 2 +- ...ransaction_status_task_integration_test.go | 42 ++-- nft/ethereum_payment_obligation.go | 186 ++++++++++-------- nft/ethereum_payment_obligation_test.go | 44 +---- nft/handler.go | 5 +- nft/handler_test.go | 4 +- nft/payment_obligation.go | 52 ++++- nft/payment_obligation_integration_test.go | 14 +- testingutils/testingtx/mocktx.go | 43 ++++ testworld/nft_test.go | 10 - transactions/base_task.go | 37 +--- transactions/base_task_test.go | 21 +- transactions/bootstrapper.go | 8 +- transactions/bootstrapper_test.go | 9 +- transactions/manager.go | 92 ++++++--- transactions/manager_test.go | 15 +- 33 files changed, 459 insertions(+), 577 deletions(-) delete mode 100644 documents/nft_created_task.go delete mode 100644 documents/nft_created_task_test.go create mode 100644 testingutils/testingtx/mocktx.go diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 8cae7fd68..1985b9901 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -50,7 +50,7 @@ func (d *documentAnchorTask) TaskTypeName() string { // ParseKwargs parses the kwargs. func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { - err := d.ParseTransactionID(kwargs) + err := d.ParseTransactionID(d.TaskTypeName(), kwargs) if err != nil { return err } @@ -90,7 +90,7 @@ func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { // RunTask anchors the document. func (d *documentAnchorTask) RunTask() (res interface{}, err error) { - log.Infof("starting anchor task: %v\n", d.TxID.String()) + log.Infof("starting anchor task for transaction: %s\n", d.TxID) defer func() { err = d.UpdateTransaction(d.accountID, d.TaskTypeName(), err) }() @@ -119,31 +119,41 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { return true, nil } -// InitDocumentAnchorTask enqueues a new document anchor task and returns the txID. -// TODO [TXManager] migrate this to use TxManager -func InitDocumentAnchorTask(tq queue.TaskQueuer, txService transactions.Manager, accountID identity.CentID, modelID []byte, txID uuid.UUID) (uuid.UUID, error) { - var tx *transactions.Transaction - var err error - if txID != uuid.Nil { - tx, err = txService.GetTransaction(accountID, txID) - } else { - tx, err = txService.CreateTransaction(accountID, documentAnchorTaskName) - } - - if err != nil { - return uuid.Nil, err - } - +// InitDocumentAnchorTask enqueues a new document anchor task for a given combination of accountID/modelID/txID. +func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, accountID identity.CentID, modelID []byte, txID uuid.UUID) (queue.TaskResult, error) { params := map[string]interface{}{ - transactions.TxIDParam: tx.ID.String(), + transactions.TxIDParam: txID.String(), DocumentIDParam: hexutil.Encode(modelID), AccountIDParam: accountID.String(), } - _, err = tq.EnqueueJob(documentAnchorTaskName, params) + err := txMan.UpdateTaskStatus(accountID, txID, transactions.Pending, documentAnchorTaskName, "init") if err != nil { - return uuid.Nil, err + return nil, err } - return tx.ID, nil + tr, err := tq.EnqueueJob(documentAnchorTaskName, params) + if err != nil { + return nil, err + } + + return tr, nil +} + +// CreateAnchorTransaction creates a transaction for anchoring a document using transaction manager +func CreateAnchorTransaction(txMan transactions.Manager, tq queue.TaskQueuer, self identity.CentID, txID uuid.UUID, documentID []byte) (uuid.UUID, chan bool, error) { + txID, done, err := txMan.ExecuteWithinTX(context.Background(), self, txID, "anchor document", func(accountID identity.CentID, TID uuid.UUID, txMan transactions.Manager, errChan chan<- error) { + tr, err := InitDocumentAnchorTask(txMan, tq, accountID, documentID, TID) + if err != nil { + errChan <- err + return + } + _, err = tr.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errChan <- err + return + } + errChan <- nil + }) + return txID, done, err } diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 8f098da69..a55499cbe 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -102,14 +102,6 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { modelSaveFunc: repo.Update, } - nftTask := &nftCreatedTask{ - BaseTask: transactions.BaseTask{ - TxManager: txMan, - }, - docSrv: ctx[BootstrappedDocumentService].(Service), - cfgSrv: cfgService, - } queueSrv.RegisterTaskType(documentAnchorTaskName, anchorTask) - queueSrv.RegisterTaskType(nftCreatedTaskName, nftTask) return nil } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 4a43a6bd6..06b35a8a6 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -25,7 +25,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { repo := leveldb.NewLevelDBRepository(db) ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo - ctx[transactions.BootstrappedService] = transactions.NewManager(transactions.NewRepository(repo)) + ctx[transactions.BootstrappedService] = transactions.NewManager(&testingconfig.MockConfig{}, transactions.NewRepository(repo)) ctx[identity.BootstrappedIDService] = new(testingcommons.MockIDService) ctx[anchors.BootstrappedAnchorRepo] = new(testinganchors.MockAnchorRepo) err = Bootstrapper{}.Bootstrap(ctx) diff --git a/documents/invoice/handler.go b/documents/invoice/handler.go index 0e787e324..7bb837705 100644 --- a/documents/invoice/handler.go +++ b/documents/invoice/handler.go @@ -44,7 +44,7 @@ func (h *grpcHandler) Create(ctx context.Context, req *clientinvoicepb.InvoiceCr } // validate and persist - doc, txID, err := h.service.Create(cctx, doc) + doc, txID, _, err := h.service.Create(cctx, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not create document") @@ -75,7 +75,7 @@ func (h *grpcHandler) Update(ctx context.Context, payload *clientinvoicepb.Invoi return nil, centerrors.Wrap(err, "could not derive update payload") } - doc, txID, err := h.service.Update(ctxHeader, doc) + doc, txID, _, err := h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not update document") diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 2ae1b5f8c..04153ce04 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -31,10 +31,10 @@ func (m *mockService) DeriveFromCreatePayload(ctx context.Context, payload *clie return model, args.Error(1) } -func (m *mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { +func (m *mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) - return model, contextutil.TX(ctx), args.Error(2) + return model, contextutil.TX(ctx), nil, args.Error(2) } func (m *mockService) GetCurrentVersion(ctx context.Context, documentID []byte) (documents.Model, error) { @@ -61,10 +61,10 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { +func (m *mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { args := m.Called(ctx, model) doc1, _ := args.Get(0).(documents.Model) - return doc1, contextutil.TX(ctx), args.Error(2) + return doc1, contextutil.TX(ctx), nil, args.Error(2) } func (m *mockService) DeriveFromUpdatePayload(ctx context.Context, payload *clientinvoicepb.InvoiceUpdatePayload) (documents.Model, error) { diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 8d1170c23..a6340b2af 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -8,15 +8,8 @@ import ( "reflect" "testing" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/identity/ethid" - - "github.com/centrifuge/go-centrifuge/config/configstore" - - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/mock" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" @@ -24,15 +17,21 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -48,13 +47,16 @@ func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetEthClient").Return(nil) ctx[ethereum.BootstrappedEthereumClient] = ethClient + txMan := &testingtx.MockTxManager{} + ctx[transactions.BootstrappedService] = txMan + done := make(chan bool) + txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, done, nil) ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, &queue.Bootstrapper{}, - transactions.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 6a8629903..592d054d1 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -122,68 +122,58 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { +func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } inv, err = s.calculateDataRoot(ctx, nil, inv, CreateValidator()) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } cd, err := inv.PackCoreDocument() if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, err = documents.InitDocumentAnchorTask( - s.queueSrv, - s.txManager, - self.ID, - cd.CurrentVersion, txID) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } - - return inv, txID, nil + return inv, txID, done, nil } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, error) { +func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } cd, err := inv.PackCoreDocument() if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } inv, err = s.calculateDataRoot(ctx, old, inv, UpdateValidator()) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, err = documents.InitDocumentAnchorTask( - s.queueSrv, - s.txManager, - self.ID, - cd.CurrentVersion, txID) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } - - return inv, txID, nil + return inv, txID, done, nil } // DeriveInvoiceResponse returns create response from invoice model diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index d94d86108..f8743f13d 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -235,7 +235,7 @@ func TestService_Create(t *testing.T) { invSrv := srv.(service) // calculate data root fails - m, _, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) + m, _, _, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -243,7 +243,7 @@ func TestService_Create(t *testing.T) { // anchor success po, err := invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - m, _, err = invSrv.Create(ctxh, po) + m, _, _, err = invSrv.Create(ctxh, po) assert.Nil(t, err) newCD, err := m.PackCoreDocument() assert.Nil(t, err) @@ -374,7 +374,7 @@ func TestService_Update(t *testing.T) { // pack failed model := &mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, err := invSrv.Update(ctxh, model) + _, _, _, err := invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -383,7 +383,7 @@ func TestService_Update(t *testing.T) { model = &mockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, _, err = invSrv.Update(ctxh, model) + _, _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -401,7 +401,7 @@ func TestService_Update(t *testing.T) { // calculate data root fails model = &mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, _, err = invSrv.Update(ctxh, model) + _, _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -421,7 +421,7 @@ func TestService_Update(t *testing.T) { newData, err := invSrv.DeriveInvoiceData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - inv, _, err = invSrv.Update(ctxh, newInv) + inv, _, _, err = invSrv.Update(ctxh, newInv) assert.Nil(t, err) assert.NotNil(t, inv) newCD, err := inv.PackCoreDocument() diff --git a/documents/nft_created_task.go b/documents/nft_created_task.go deleted file mode 100644 index 2864e8065..000000000 --- a/documents/nft_created_task.go +++ /dev/null @@ -1,173 +0,0 @@ -package documents - -import ( - "context" - "fmt" - - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/code" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" -) - -const ( - // nftCreatedTaskName is the name of the NFT Task - nftCreatedTaskName string = "NFT created task" - - // TokenRegistryParam maps to token registry address - TokenRegistryParam string = "Token Registry" - - // TokenIDParam maps to NFT token ID - TokenIDParam string = "Token ID" -) - -type nftCreatedTask struct { - transactions.BaseTask - accountID identity.CentID - documentID []byte - tokenRegistry common.Address - tokenID []byte - - // state - docSrv Service - cfgSrv config.Service -} - -func (t *nftCreatedTask) ParseKwargs(kwargs map[string]interface{}) (err error) { - err = t.ParseTransactionID(kwargs) - if err != nil { - return err - } - - acc, ok := kwargs[AccountIDParam].(string) - if !ok { - return errors.New("account identifier not set") - } - - t.accountID, err = identity.CentIDFromString(acc) - if err != nil { - return errors.New("invalid accountID") - } - - vr, ok := kwargs[DocumentIDParam].(string) - if !ok { - return errors.New("model identifier not set") - } - - t.documentID, err = hexutil.Decode(vr) - if err != nil { - return err - } - - tr, ok := kwargs[TokenRegistryParam].(string) - if !ok { - return errors.New("token registry not set") - } - - t.tokenRegistry = common.HexToAddress(tr) - - tidr, ok := kwargs[TokenIDParam].(string) - if !ok { - return errors.New("token ID not set") - } - - t.tokenID, err = hexutil.Decode(tidr) - if err != nil { - return err - } - - return nil -} - -func (t *nftCreatedTask) Copy() (gocelery.CeleryTask, error) { - return &nftCreatedTask{ - BaseTask: t.BaseTask, - docSrv: t.docSrv, - cfgSrv: t.cfgSrv, - }, nil -} - -func (t *nftCreatedTask) RunTask() (result interface{}, err error) { - defer func() { - err = t.UpdateTransaction(t.accountID, t.TaskTypeName(), err) - }() - - tc, err := t.cfgSrv.GetAccount(t.accountID[:]) - if err != nil { - apiLog.Error(err) - return nil, centerrors.New(code.Unknown, fmt.Sprintf("failed to get header: %v", err)) - } - - ctx, err := contextutil.New(context.Background(), tc) - if err != nil { - return false, errors.New("failed to get context header: %v", err) - } - - model, err := t.docSrv.GetCurrentVersion(ctx, t.documentID) - if err != nil { - return nil, err - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - - data := cd.EmbeddedData - cd, err = coredocument.PrepareNewVersion(*cd, nil) - if err != nil { - return nil, err - } - - cd.EmbeddedData = data - err = coredocument.AddNFTToReadRules(cd, t.tokenRegistry, t.tokenID) - if err != nil { - return nil, err - } - - model, err = t.docSrv.DeriveFromCoreDocument(cd) - if err != nil { - return nil, err - } - - _, _, err = t.docSrv.Update(contextutil.WithTX(ctx, t.TxID), model) - if err != nil { - return nil, err - } - - return nil, nil -} - -func (t *nftCreatedTask) TaskTypeName() string { - return nftCreatedTaskName -} - -// InitNFTCreatedTask initiates a new nft created task -func InitNFTCreatedTask( - queuer queue.TaskQueuer, - txID uuid.UUID, - cid identity.CentID, - documentID []byte, - registry common.Address, - tokenID []byte, -) (queue.TaskResult, error) { - log.Infof("Starting NFT created task: %v\n", txID.String()) - return queuer.EnqueueJob(nftCreatedTaskName, map[string]interface{}{ - transactions.TxIDParam: txID.String(), - transactions.TxNextTask: true, - AccountIDParam: cid.String(), - DocumentIDParam: hexutil.Encode(documentID), - TokenRegistryParam: registry.String(), - TokenIDParam: hexutil.Encode(tokenID), - }) -} diff --git a/documents/nft_created_task_test.go b/documents/nft_created_task_test.go deleted file mode 100644 index d7d2bcc58..000000000 --- a/documents/nft_created_task_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// +build unit - -package documents - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" - "github.com/stretchr/testify/assert" -) - -func TestNftCreatedTask_ParseKwargs(t *testing.T) { - task := new(nftCreatedTask) - m := make(map[string]interface{}) - - // no transactions - assert.Error(t, task.ParseKwargs(m)) - - // no account - m[transactions.TxIDParam] = uuid.Must(uuid.NewV4()).String() - assert.Error(t, task.ParseKwargs(m)) - - // wrong format - m[AccountIDParam] = "0x1002030405" - assert.Error(t, task.ParseKwargs(m)) - - // no document - m[AccountIDParam] = "0x010203040506" - assert.Error(t, task.ParseKwargs(m)) - - // hex fails - m[DocumentIDParam] = "sfkvfj" - assert.Error(t, task.ParseKwargs(m)) - - // missing registry - m[DocumentIDParam] = hexutil.Encode(utils.RandomSlice(32)) - assert.Error(t, task.ParseKwargs(m)) - - // missing token ID - m[TokenRegistryParam] = "0xf72855759a39fb75fc7341139f5d7a3974d4da08" - assert.Error(t, task.ParseKwargs(m)) - - // hex util fails - m[TokenIDParam] = "lkfv" - assert.Error(t, task.ParseKwargs(m)) - - m[TokenIDParam] = hexutil.Encode(utils.RandomSlice(32)) - assert.NoError(t, task.ParseKwargs(m)) -} diff --git a/documents/purchaseorder/handler.go b/documents/purchaseorder/handler.go index 72be3f60b..89af0fd3c 100644 --- a/documents/purchaseorder/handler.go +++ b/documents/purchaseorder/handler.go @@ -43,7 +43,7 @@ func (h grpcHandler) Create(ctx context.Context, req *clientpurchaseorderpb.Purc } // validate, persist, and anchor - doc, txID, err := h.service.Create(ctxh, doc) + doc, txID, _, err := h.service.Create(ctxh, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not create document") @@ -74,7 +74,7 @@ func (h grpcHandler) Update(ctx context.Context, payload *clientpurchaseorderpb. return nil, centerrors.Wrap(err, "could not derive update payload") } - doc, txID, err := h.service.Update(ctxHeader, doc) + doc, txID, _, err := h.service.Update(ctxHeader, doc) if err != nil { apiLog.Error(err) return nil, centerrors.Wrap(err, "could not update document") diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index 48234c19d..a0faef797 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -25,16 +25,16 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { +func (m mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) - return model, contextutil.TX(ctx), args.Error(2) + return model, contextutil.TX(ctx), nil, args.Error(2) } -func (m mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, error) { +func (m mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) - return model, contextutil.TX(ctx), args.Error(2) + return model, contextutil.TX(ctx), nil, args.Error(2) } func (m mockService) DeriveFromCreatePayload(ctx context.Context, payload *clientpopb.PurchaseOrderCreatePayload) (documents.Model, error) { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 87a8e4de9..f74dbff7d 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -8,6 +8,10 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/testingtx" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/mock" + "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -48,13 +52,16 @@ func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetEthClient").Return(nil) ctx[ethereum.BootstrappedEthereumClient] = ethClient + txMan := &testingtx.MockTxManager{} + ctx[transactions.BootstrappedService] = txMan + done := make(chan bool) + txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, done, nil) ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, &queue.Bootstrapper{}, - transactions.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 432016c40..650710cc9 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -102,60 +102,58 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { +func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } po, err = s.calculateDataRoot(ctx, nil, po, CreateValidator()) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } cd, err := po.PackCoreDocument() if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, err = documents.InitDocumentAnchorTask(s.queueSrv, s.txManager, self.ID, cd.CurrentVersion, txID) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, nil } - - return po, txID, nil + return po, txID, done, nil } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, error) { +func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } cd, err := po.PackCoreDocument() if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) if err != nil { - return nil, uuid.Nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } po, err = s.calculateDataRoot(ctx, old, po, UpdateValidator()) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, err = documents.InitDocumentAnchorTask(s.queueSrv, s.txManager, self.ID, cd.CurrentVersion, txID) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) if err != nil { - return nil, uuid.Nil, err + return nil, uuid.Nil, nil, err } - - return po, txID, nil + return po, txID, done, nil } // DeriveFromCreatePayload derives purchase order from create payload diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 7f64ffda5..95d55d286 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -66,7 +66,7 @@ func TestService_Update(t *testing.T) { // pack failed model := &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, err := poSrv.Update(ctxh, model) + _, _, _, err := poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pack error") @@ -75,7 +75,7 @@ func TestService_Update(t *testing.T) { model = &testingdocuments.MockModel{} cd := coredocument.New() model.On("PackCoreDocument").Return(cd, nil).Once() - _, _, err = poSrv.Update(ctxh, model) + _, _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document not found") @@ -93,7 +93,7 @@ func TestService_Update(t *testing.T) { // calculate data root fails model = &testingdocuments.MockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() - _, _, err = poSrv.Update(ctxh, model) + _, _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -113,7 +113,7 @@ func TestService_Update(t *testing.T) { newData, err := poSrv.DerivePurchaseOrderData(newInv) assert.Nil(t, err) assert.Equal(t, data, newData) - po, _, err = poSrv.Update(ctxh, newInv) + po, _, _, err = poSrv.Update(ctxh, newInv) assert.Nil(t, err) assert.NotNil(t, po) @@ -273,7 +273,7 @@ func TestService_Create(t *testing.T) { _, poSrv := getServiceWithMockedLayers() // calculate data root fails - m, _, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) + m, _, _, err := poSrv.Create(ctxh, &testingdocuments.MockModel{}) assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -281,7 +281,7 @@ func TestService_Create(t *testing.T) { // anchor fails po, err := poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - m, _, err = poSrv.Create(ctxh, po) + m, _, _, err = poSrv.Create(ctxh, po) assert.Nil(t, err) assert.NotNil(t, m) diff --git a/documents/service.go b/documents/service.go index 77ba232e3..00bd1244a 100644 --- a/documents/service.go +++ b/documents/service.go @@ -58,10 +58,10 @@ type Service interface { ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error // Create validates and persists Model and returns a Updated model - Create(ctx context.Context, model Model) (Model, uuid.UUID, error) + Create(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) // Update validates and updates the model and return the updated model - Update(ctx context.Context, model Model) (Model, uuid.UUID, error) + Update(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) } // service implements Service @@ -289,19 +289,19 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, return srv.DeriveFromCoreDocument(cd) } -func (s service) Create(ctx context.Context, model Model) (Model, uuid.UUID, error) { +func (s service) Create(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) { srv, err := s.getService(model) if err != nil { - return nil, uuid.Nil, errors.New("failed to get service: %v", err) + return nil, uuid.Nil, nil, errors.New("failed to get service: %v", err) } return srv.Create(ctx, model) } -func (s service) Update(ctx context.Context, model Model) (Model, uuid.UUID, error) { +func (s service) Update(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) { srv, err := s.getService(model) if err != nil { - return nil, uuid.Nil, errors.New("failed to get service: %v", err) + return nil, uuid.Nil, nil, errors.New("failed to get service: %v", err) } return srv.Update(ctx, model) diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index d18dc2331..34ec146b3 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -205,13 +205,11 @@ func QueueEthTXStatusTask( accountID identity.CentID, txID uuid.UUID, txHash common.Hash, - next bool, queuer queue.TaskQueuer) (res queue.TaskResult, err error) { return queuer.EnqueueJobWithMaxTries(EthTXStatusTaskName, map[string]interface{}{ transactions.TxIDParam: txID.String(), TransactionAccountParam: accountID.String(), TransactionTxHashParam: txHash.String(), - transactions.TxNextTask: next, }) } diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 1d4a3166a..8e36eb7e9 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -90,7 +90,7 @@ func (tst *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { // ParseKwargs - define a method to parse CentID func (tst *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (err error) { - err = tst.ParseTransactionID(kwargs) + err = tst.ParseTransactionID(tst.TaskTypeName(), kwargs) if err != nil { return err } diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go index fd5988c5d..f0c65711b 100644 --- a/ethereum/transaction_status_task_integration_test.go +++ b/ethereum/transaction_status_task_integration_test.go @@ -3,41 +3,49 @@ package ethereum_test import ( + "context" "testing" - "time" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) -func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, *transactions.Transaction, queue.TaskResult) { +func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, uuid.UUID, chan bool) { queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) cid := identity.RandomCentID() - tx, err := txManager.CreateTransaction(cid, "Mint NFT") - - assert.Nil(t, err, "toCentID shouldn't throw an error") - - result, err := queueSrv.EnqueueJob(ethereum.EthTXStatusTaskName, map[string]interface{}{ - transactions.TxIDParam: tx.ID.String(), - ethereum.TransactionAccountParam: cid.String(), - ethereum.TransactionTxHashParam: txHash, + tx, done, err := txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Check TX status", func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errChan chan<- error) { + result, err := queueSrv.EnqueueJob(ethereum.EthTXStatusTaskName, map[string]interface{}{ + transactions.TxIDParam: txID.String(), + ethereum.TransactionAccountParam: cid.String(), + ethereum.TransactionTxHashParam: txHash, + }) + if err != nil { + errChan <- err + } + _, err = result.Get(txManager.GetDefaultTaskTimeout()) + if err != nil { + errChan <- err + } + errChan <- nil }) + assert.NoError(t, err) - return txManager, cid, tx, result + return txManager, cid, tx, done } func TestTransactionStatusTask_successful(t *testing.T) { txManager, cid, tx, result := enqueueJob(t, "0x1") - _, err := result.Get(time.Second) - assert.NoError(t, err) - trans, err := txManager.GetTransaction(cid, tx.ID) + r := <-result + assert.True(t, r) + trans, err := txManager.GetTransaction(cid, tx) assert.Nil(t, err, "a transaction should be returned") assert.Equal(t, string(transactions.Success), string(trans.Status), "transaction should be successful") } @@ -45,9 +53,9 @@ func TestTransactionStatusTask_successful(t *testing.T) { func TestTransactionStatusTask_failed(t *testing.T) { txManager, cid, tx, result := enqueueJob(t, "0x2") - _, err := result.Get(time.Second) - assert.Error(t, err) - trans, err := txManager.GetTransaction(cid, tx.ID) + r := <-result + assert.True(t, r) + trans, err := txManager.GetTransaction(cid, tx) assert.Nil(t, err, "a centrifuge transaction should be returned") assert.Equal(t, string(transactions.Failed), string(trans.Status), "transaction should fail") } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 15cd2a983..6beae3948 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -5,6 +5,10 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" @@ -73,7 +77,7 @@ func newEthereumPaymentObligation( } } -func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, documentID []byte, depositAddress string, proofFields []string) (MintRequest, error) { +func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, tokenID TokenID, documentID []byte, depositAddress string, proofFields []string) (MintRequest, error) { model, err := s.docSrv.GetCurrentVersion(ctx, documentID) if err != nil { return MintRequest{}, err @@ -101,7 +105,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, docu return MintRequest{}, err } - requestData, err := NewMintRequest(toAddress, anchorID, proofs.FieldProofs, rootHash) + requestData, err := NewMintRequest(tokenID, toAddress, anchorID, proofs.FieldProofs, rootHash) if err != nil { return MintRequest{}, err } @@ -111,111 +115,149 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, docu } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { +func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) { tc, err := contextutil.Account(ctx) if err != nil { - return nil, err - } - - requestData, err := s.prepareMintRequest(ctx, documentID, depositAddress, proofFields) - if err != nil { - return nil, errors.New("failed to prepare mint request: %v", err) - } - - opts, err := s.ethClient.GetTxOpts(tc.GetEthereumDefaultAccountName()) - if err != nil { - return nil, err - } - - registry := common.HexToAddress(registryAddress) - contract, err := s.bindContract(registry, s.ethClient) - if err != nil { - return nil, err + return nil, nil, err } cidBytes, err := tc.GetIdentityID() if err != nil { - return nil, err + return nil, nil, err } cid, err := identity.ToCentID(cidBytes) if err != nil { - return nil, err + return nil, nil, err } - txID, err := s.sendMintTransaction(cid, contract, opts, requestData, registry, documentID) + tokenID := NewTokenID() + // Mint NFT within transaction + // We use context.Background() for now so that the transaction is only limited by ethereum timeouts + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Minting NFT", + s.minter(ctx, tokenID, documentID, registryAddress, depositAddress, proofFields)) + if err != nil { - return nil, errors.New("failed to send transaction: %v", err) + return nil, nil, err } return &MintNFTResponse{ TransactionID: txID.String(), - TokenID: requestData.TokenID.String(), - }, nil + TokenID: tokenID.String(), + }, done, nil } -// OwnerOf returns the owner of the NFT token on ethereum chain -func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []byte) (owner common.Address, err error) { - contract, err := s.bindContract(registry, s.ethClient) - if err != nil { - return owner, errors.New("failed to bind the registry contract: %v", err) - } +func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, documentID []byte, registryAddress, depositAddress string, proofFields []string) func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + tc, err := contextutil.Account(ctx) + if err != nil { + errOut <- err + return + } - opts, cancF := s.ethClient.GetGethCallOpts(false) - defer cancF() + // registry address + registry := common.HexToAddress(registryAddress) - return contract.OwnerOf(opts, utils.ByteSliceToBigInt(tokenID)) -} + model, err := s.docSrv.GetCurrentVersion(ctx, documentID) + if err != nil { + errOut <- err + return + } -// sendMintTransaction sends the actual transaction to mint the NFT -func (s *ethereumPaymentObligation) sendMintTransaction( - cid identity.CentID, - contract ethereumPaymentObligationContract, - opts *bind.TransactOpts, - requestData MintRequest, - registry common.Address, - documentID []byte) (uuid.UUID, error) { + cd, err := model.PackCoreDocument() + if err != nil { + errOut <- err + return + } - r := requestData.copy() + data := cd.EmbeddedData + cd, err = coredocument.PrepareNewVersion(*cd, nil) + if err != nil { + errOut <- err + return + } - // Run within transaction - // We use context.Background() for now so that the transaction is only limited by ethereum timeouts - txID, _, err := s.txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Minting NFT", func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, r.To, r.TokenID, r.TokenURI, r.AnchorID, - r.MerkleRoot, r.Values, r.Salts, r.Proofs) + cd.EmbeddedData = data + err = coredocument.AddNFTToReadRules(cd, registry, tokenID.BigInt().Bytes()) + if err != nil { + errOut <- err + return + } + + model, err = s.docSrv.DeriveFromCoreDocument(cd) + if err != nil { + errOut <- err + return + } + + _, _, done, err := s.docSrv.Update(contextutil.WithTX(ctx, txID), model) if err != nil { errOut <- err + return } - log.Infof("Sent off ethTX to mint [tokenID: %x, anchor: %x, registry: %x] to payment obligation contract. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", - requestData.TokenID, requestData.AnchorID, requestData.To, ethTX.Hash(), ethTX.Nonce(), ethTX.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", ethTX.Hash()) + isDone := <-done + if !isDone { + // some problem occured in a child task + errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(documentID), txID) + return + } - res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), true, s.queue) + requestData, err := s.prepareMintRequest(ctx, tokenID, documentID, depositAddress, proofFields) + if err != nil { + errOut <- errors.New("failed to prepare mint request: %v", err) + return + } + + opts, err := s.ethClient.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { errOut <- err + return } - _, err = res.Get(s.cfg.GetEthereumContextWaitTimeout()) + contract, err := s.bindContract(registry, s.ethClient) if err != nil { errOut <- err + return } - res, err = documents.InitNFTCreatedTask( - s.queue, txID, accountID, documentID, registry, requestData.TokenID.Bytes()) + ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, + requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { errOut <- err + return } - _, err = res.Get(s.cfg.GetEthereumContextWaitTimeout()) + log.Infof("Sent off ethTX to mint [tokenID: %s, anchor: %x, registry: %s] to payment obligation contract. Ethereum transaction hash [%s] and Nonce [%d] and Check [%v]", + requestData.TokenID, requestData.AnchorID, requestData.To.String(), ethTX.Hash().String(), ethTX.Nonce(), ethTX.CheckNonce()) + log.Infof("Transfer pending: %s\n", ethTX.Hash().String()) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), s.queue) if err != nil { errOut <- err + return } + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } errOut <- nil - }) + } +} - return txID, err +// OwnerOf returns the owner of the NFT token on ethereum chain +func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []byte) (owner common.Address, err error) { + contract, err := s.bindContract(registry, s.ethClient) + if err != nil { + return owner, errors.New("failed to bind the registry contract: %v", err) + } + + opts, cancF := s.ethClient.GetGethCallOpts(false) + defer cancF() + + return contract.OwnerOf(opts, utils.ByteSliceToBigInt(tokenID)) } // MintRequest holds the data needed to mint and NFT from a Centrifuge document @@ -247,12 +289,7 @@ type MintRequest struct { } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { - - // tokenID is uint256 in Solidity (256 bits | max value is 2^256-1) - // tokenID should be random 32 bytes (32 byte = 256 bits) - tokenID := utils.ByteSliceToBigInt(utils.RandomSlice(32)) - tokenURI := "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" +func NewMintRequest(tokenID TokenID, to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { proofData, err := createProofData(proofs) if err != nil { return MintRequest{}, err @@ -260,8 +297,8 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo return MintRequest{ To: to, - TokenID: tokenID, - TokenURI: tokenURI, + TokenID: tokenID.BigInt(), + TokenURI: tokenID.URI(), AnchorID: anchorID.BigInt(), MerkleRoot: rootHash, Values: proofData.Values, @@ -269,19 +306,6 @@ func NewMintRequest(to common.Address, anchorID anchors.AnchorID, proofs []*proo Proofs: proofData.Proofs}, nil } -func (m MintRequest) copy() MintRequest { - return MintRequest{ - m.To, - new(big.Int).Set(m.TokenID), - m.TokenURI, - new(big.Int).Set(m.AnchorID), - m.MerkleRoot, - m.Values, - m.Salts, - m.Proofs, - } -} - type proofData struct { Values []string Salts [][32]byte diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index b7519456f..286f49b0c 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -3,12 +3,11 @@ package nft import ( - "context" "math/big" "testing" "time" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/satori/go.uuid" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" @@ -24,7 +23,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -36,35 +34,6 @@ import ( "github.com/stretchr/testify/mock" ) -type MockTxManager struct { - mock.Mock -} - -func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { - args := m.Called(ctx, accountID, existingTxID, desc, work) - return args.Get(0).(uuid.UUID), args.Get(1).(chan bool), args.Error(2) -} - -func (MockTxManager) CreateTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) { - panic("implement me") -} - -func (MockTxManager) GetTransaction(accountID identity.CentID, id uuid.UUID) (*transactions.Transaction, error) { - panic("implement me") -} - -func (MockTxManager) SaveTransaction(tx *transactions.Transaction) error { - panic("implement me") -} - -func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { - panic("implement me") -} - -func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { - panic("implement me") -} - func TestCreateProofData(t *testing.T) { sortedHashes := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} salt := utils.RandomSlice(32) @@ -172,14 +141,14 @@ func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address func TestPaymentObligationService(t *testing.T) { tests := []struct { name string - mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *MockTxManager) + mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) request *nftpb.NFTMintRequest err error result string }{ { "happypath", - func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *MockTxManager) { + func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) { coreDoc := coredocument.New() coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) @@ -206,7 +175,7 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetSigningKeyPair").Return("", "") configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) - txMan := &MockTxManager{} + txMan := &testingtx.MockTxManager{} txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, make(chan bool), nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv, txMan @@ -227,18 +196,15 @@ func TestPaymentObligationService(t *testing.T) { return &EthereumPaymentObligationContract{}, nil }, txMan, func() (uint64, error) { return 10, nil }) ctxh := testingconfig.CreateAccountContext(t, &mockCfg) - _, err := service.MintNFT(ctxh, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + _, _, err := service.MintNFT(ctxh, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { panic(err) } - docService.AssertExpectations(t) paymentOb.AssertExpectations(t) idService.AssertExpectations(t) - //ethClient.AssertExpectations(t) mockCfg.AssertExpectations(t) - //queueSrv.AssertExpectations(t) }) } } diff --git a/nft/handler.go b/nft/handler.go index dba1b6fcd..32f594109 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -38,12 +38,13 @@ func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) if err != nil { return nil, err } + identifier, err := hexutil.Decode(request.Identifier) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } - resp, err := g.service.MintNFT(ctxHeader, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) + resp, _, err := g.service.MintNFT(ctxHeader, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -55,7 +56,6 @@ func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) } func validateParameters(request *nftpb.NFTMintRequest) error { - if !common.IsHexAddress(request.RegistryAddress) { return centerrors.New(code.Unknown, "registryAddress is not a valid Ethereum address") } @@ -63,7 +63,6 @@ func validateParameters(request *nftpb.NFTMintRequest) error { if !common.IsHexAddress(request.DepositAddress) { return centerrors.New(code.Unknown, "DepositAddress is not a valid Ethereum address") } - return nil } diff --git a/nft/handler_test.go b/nft/handler_test.go index db221c161..1ed5a1aa9 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -24,10 +24,10 @@ type mockPaymentObligationService struct { mock.Mock } -func (m *mockPaymentObligationService) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) { +func (m *mockPaymentObligationService) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) { args := m.Called(ctx, documentID, registryAddress, depositAddress, proofFields) resp, _ := args.Get(0).(*MintNFTResponse) - return resp, args.Error(1) + return resp, nil, args.Error(1) } func TestNFTMint_success(t *testing.T) { diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index 6a9f93049..db7b28125 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -2,12 +2,62 @@ package nft import ( "context" + "math/big" + + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/centrifuge/go-centrifuge/utils" ) +// TokenIDLength is the length of an NFT token ID +const TokenIDLength = 32 + +// TokenID is uint256 in Solidity (256 bits | max value is 2^256-1) +// tokenID should be random 32 bytes (32 byte = 256 bits) +type TokenID [TokenIDLength]byte + +// NewTokenID returns a new random TokenID +func NewTokenID() TokenID { + var tid [TokenIDLength]byte + copy(tid[:], utils.RandomSlice(TokenIDLength)) + return tid +} + +// FromString converts given hex string to a TokenID +func FromString(hexStr string) (TokenID, error) { + tokenIDBytes, err := hexutil.Decode(hexStr) + if err != nil { + return NewTokenID(), err + } + if len(tokenIDBytes) != TokenIDLength { + return NewTokenID(), errors.New("the provided hex string doesn't match the TokenID representation length") + } + var tid [TokenIDLength]byte + copy(tid[:], tokenIDBytes) + return tid, nil +} + +// BigInt converts tokenID to big int +func (t TokenID) BigInt() *big.Int { + return utils.ByteSliceToBigInt(t[:]) +} + +// URI gets the URI for this token +func (t TokenID) URI() string { + // TODO please fix this + return "http:=//www.centrifuge.io/DUMMY_URI_SERVICE" +} + +func (t TokenID) String() string { + return hexutil.Encode(t[:]) +} + // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, error) + MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) } // MintNFTResponse holds tokenID and transaction ID. diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 0bc65e349..ad7300f36 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,7 +3,6 @@ package nft_test import ( - "math/big" "os" "testing" "time" @@ -71,7 +70,7 @@ func TestPaymentObligationService_mint(t *testing.T) { }, }) assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, txID, err := invoiceService.Create(contextHeader, model) + modelUpdated, txID, _, err := invoiceService.Create(contextHeader, model) err = txManager.WaitForTransaction(cid, txID) assert.Nil(t, err) @@ -82,7 +81,7 @@ func TestPaymentObligationService_mint(t *testing.T) { // assert no error depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" registry := cfg.GetContractAddress(config.PaymentObligation) - resp, err := payOb.MintNFT( + resp, done, err := payOb.MintNFT( contextHeader, ID, registry.String(), @@ -91,10 +90,11 @@ func TestPaymentObligationService_mint(t *testing.T) { ) assert.Nil(t, err, "should not error out when minting an invoice") assert.NotNil(t, resp.TokenID, "token id should be present") + tokenID, err := nft.FromString(resp.TokenID) + assert.Nil(t, err, "should not error out when getting tokenID hex") + <-done assert.NoError(t, txManager.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) - b := new(big.Int) - b.SetString(resp.TokenID, 10) - owner, err := tokenRegistry.OwnerOf(registry, b.Bytes()) + owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) assert.NoError(t, err) assert.Equal(t, common.HexToAddress(depositAddr), owner) doc, err := invoiceService.GetCurrentVersion(contextHeader, ID) @@ -104,7 +104,7 @@ func TestPaymentObligationService_mint(t *testing.T) { assert.Len(t, cd.Roles, 2) assert.Len(t, cd.Roles[1].Nfts, 1) nft := cd.Roles[1].Nfts[0] - enft, err := coredocument.ConstructNFT(registry, b.Bytes()) + enft, err := coredocument.ConstructNFT(registry, tokenID.BigInt().Bytes()) assert.NoError(t, err) assert.Equal(t, enft, nft) } diff --git a/testingutils/testingtx/mocktx.go b/testingutils/testingtx/mocktx.go new file mode 100644 index 000000000..c29b6be08 --- /dev/null +++ b/testingutils/testingtx/mocktx.go @@ -0,0 +1,43 @@ +// +build integration unit + +package testingtx + +import ( + "context" + "time" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/satori/go.uuid" + "github.com/stretchr/testify/mock" +) + +type MockTxManager struct { + mock.Mock +} + +func (m MockTxManager) GetDefaultTaskTimeout() time.Duration { + panic("implement me") +} + +func (m MockTxManager) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status transactions.Status, taskName, message string) error { + panic("implement me") +} + +func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { + args := m.Called(ctx, accountID, existingTxID, desc, work) + return args.Get(0).(uuid.UUID), args.Get(1).(chan bool), args.Error(2) +} + +func (MockTxManager) GetTransaction(accountID identity.CentID, id uuid.UUID) (*transactions.Transaction, error) { + panic("implement me") +} + +func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { + panic("implement me") +} + +func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { + panic("implement me") +} diff --git a/testworld/nft_test.go b/testworld/nft_test.go index fb25d4c03..f059aa1da 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -100,16 +100,6 @@ func TestPaymentObligationMint_errors(t *testing.T) { "depositAddress": "abc", }, }, - { - "document not found in the system database", - http.StatusInternalServerError, - map[string]interface{}{ - - "identifier": "0x12121212", - "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address - "depositAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address - }, - }, } for _, test := range tests { t.Run(test.errorMsg, func(t *testing.T) { diff --git a/transactions/base_task.go b/transactions/base_task.go index 7dba218a4..cb8334842 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -13,9 +13,6 @@ var log = logging.Logger("transaction") const ( // TxIDParam maps transaction ID in the kwargs. TxIDParam = "transactionID" - - // TxNextTask indicates if there is next task - TxNextTask = "next task" ) // BaseTask holds the required details and helper functions for tasks to update transactions. @@ -23,15 +20,12 @@ const ( type BaseTask struct { TxID uuid.UUID - // TODO [TXManager] remove this update once TX Manager update is complete, i.e. Individual tasks must not be responsible for updating a transactions status - Next bool - // state TxManager Manager } // ParseTransactionID parses txID. -func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { +func (b *BaseTask) ParseTransactionID(taskTypeName string, kwargs map[string]interface{}) error { txID, ok := kwargs[TxIDParam].(string) if !ok { return errors.New("missing transaction ID") @@ -43,11 +37,7 @@ func (b *BaseTask) ParseTransactionID(kwargs map[string]interface{}) error { return errors.New("invalid transaction ID") } - if b.Next, ok = kwargs[TxNextTask].(bool); !ok { - b.Next = false - } - - log.Infof("Task %v has next task: %v\n", b.TxID.String(), b.Next) + log.Infof("Task %s parsed for tx: %s\n", taskTypeName, b.TxID) return nil } @@ -57,29 +47,12 @@ func (b *BaseTask) UpdateTransaction(accountID identity.CentID, taskTypeName str return err } + // TODO this TaskStatus map update assumes that a single transaction has only one execution of a certain task type, which can be wrong, use the taskID or another unique identifier instead. if err != nil { log.Infof("Transaction failed: %v\n", b.TxID.String()) - return errors.AppendError(err, b.updateStatus(accountID, Failed, taskTypeName, err.Error())) - } - - if b.Next { - return b.updateStatus(accountID, Pending, taskTypeName, "") + return errors.AppendError(err, b.TxManager.UpdateTaskStatus(accountID, b.TxID, Failed, taskTypeName, err.Error())) } log.Infof("Transaction successful:%v\n", b.TxID.String()) - return b.updateStatus(accountID, Success, taskTypeName, "") -} - -func (b *BaseTask) updateStatus(accountID identity.CentID, status Status, taskTypeName, message string) error { - tx, err := b.TxManager.GetTransaction(accountID, b.TxID) - if err != nil { - return err - } - - // TODO [TXManager] remove this update once TX Manager update is complete, i.e. Individual tasks must not be responsible for updating a transactions status - tx.Status = status - // status particular to the task - tx.TaskStatus[taskTypeName] = status - tx.Logs = append(tx.Logs, NewLog(taskTypeName, message)) - return b.TxManager.SaveTransaction(tx) + return b.TxManager.UpdateTaskStatus(accountID, b.TxID, Success, taskTypeName, "") } diff --git a/transactions/base_task_test.go b/transactions/base_task_test.go index ff1dc3e9f..a5849538e 100644 --- a/transactions/base_task_test.go +++ b/transactions/base_task_test.go @@ -18,7 +18,7 @@ func TestDocumentAnchorTask_updateTransaction(t *testing.T) { accountID := identity.RandomCentID() name := "some task" task.TxID = uuid.Must(uuid.NewV4()) - task.TxManager = NewManager(NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) + task.TxManager = NewManager(&mockConfig{}, NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) // missing transaction with nil error err := task.UpdateTransaction(accountID, name, nil) @@ -32,33 +32,24 @@ func TestDocumentAnchorTask_updateTransaction(t *testing.T) { // no error and success tx := newTransaction(accountID, "") - assert.NoError(t, task.TxManager.SaveTransaction(tx)) + assert.NoError(t, task.TxManager.(extendedManager).saveTransaction(tx)) task.TxID = tx.ID assert.NoError(t, task.UpdateTransaction(accountID, name, nil)) tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) - assert.Equal(t, tx.Status, Success) + assert.Equal(t, tx.Status, Pending) + assert.Equal(t, tx.TaskStatus[name], Success) assert.Len(t, tx.Logs, 1) // failed task tx = newTransaction(accountID, "") - assert.NoError(t, task.TxManager.SaveTransaction(tx)) + assert.NoError(t, task.TxManager.(extendedManager).saveTransaction(tx)) task.TxID = tx.ID err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) assert.EqualError(t, errors.GetErrs(err)[0], "anchor error") tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) - assert.Equal(t, tx.Status, Failed) - assert.Len(t, tx.Logs, 1) - - // success but pending - tx = newTransaction(accountID, "") - assert.NoError(t, task.TxManager.SaveTransaction(tx)) - task.TxID = tx.ID - task.Next = true - err = task.UpdateTransaction(accountID, name, nil) - tx, err = task.TxManager.GetTransaction(accountID, task.TxID) - assert.NoError(t, err) assert.Equal(t, tx.Status, Pending) + assert.Equal(t, tx.TaskStatus[name], Failed) assert.Len(t, tx.Logs, 1) } diff --git a/transactions/bootstrapper.go b/transactions/bootstrapper.go index 3d5c454fd..70e5faa18 100644 --- a/transactions/bootstrapper.go +++ b/transactions/bootstrapper.go @@ -1,6 +1,7 @@ package transactions import ( + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" ) @@ -21,6 +22,11 @@ type Bootstrapper struct{} // Bootstrap adds transaction.Repository into context. func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { + cfg, err := configstore.RetrieveConfig(false, ctx) + if err != nil { + return err + } + repo, ok := ctx[storage.BootstrappedDB].(storage.Repository) if !ok { return ErrTransactionBootstrap @@ -29,7 +35,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { txRepo := NewRepository(repo) ctx[BootstrappedRepo] = txRepo - txSrv := NewManager(txRepo) + txSrv := NewManager(cfg, txRepo) ctx[BootstrappedService] = txSrv return nil } diff --git a/transactions/bootstrapper_test.go b/transactions/bootstrapper_test.go index 57fa0d622..4dfb8b957 100644 --- a/transactions/bootstrapper_test.go +++ b/transactions/bootstrapper_test.go @@ -5,6 +5,12 @@ package transactions import ( "testing" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/go-centrifuge/bootstrap" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/storage/leveldb" @@ -17,11 +23,12 @@ func TestBootstrapper_Bootstrap(t *testing.T) { b := Bootstrapper{} ctx := make(map[string]interface{}) err := b.Bootstrap(ctx) - assert.True(t, errors.IsOfType(ErrTransactionBootstrap, err)) + assert.True(t, errors.IsOfType(config.ErrConfigRetrieve, err)) randomPath := leveldb.GetRandomTestStoragePath() db, err := leveldb.NewLevelDBStorage(randomPath) assert.Nil(t, err) + ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = leveldb.NewLevelDBRepository(db) err = b.Bootstrap(ctx) assert.Nil(t, err) diff --git a/transactions/manager.go b/transactions/manager.go index 0e766b56e..2ecd95b11 100644 --- a/transactions/manager.go +++ b/transactions/manager.go @@ -12,30 +12,61 @@ import ( "github.com/satori/go.uuid" ) -// Manager wraps the repository and exposes specific functions. -type Manager interface { +// Config is the config interface for transactions package +type Config interface { + GetEthereumContextWaitTimeout() time.Duration +} +// Manager is a manager for centrifuge transactions. +type Manager interface { // ExecuteWithinTX executes a transaction within a transaction ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) - - // CreateTransaction - // TODO [TXManager] remove this once TX Manager update is complete - CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) - SaveTransaction(tx *Transaction) error + UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status Status, taskName, message string) error GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error + GetDefaultTaskTimeout() time.Duration +} + +// extendedManager exposes package specific functions. +type extendedManager interface { + Manager + + // saveTransaction only exposed for testing within package. + // DO NOT use this outside of the package, use ExecuteWithinTX to initiate a transaction with management. + saveTransaction(tx *Transaction) error + + // createTransaction only exposed for testing within package. + // DO NOT use this outside of the package, use ExecuteWithinTX to initiate a transaction with management. + createTransaction(accountID identity.CentID, desc string) (*Transaction, error) } // NewManager returns a Manager implementation. -func NewManager(repo Repository) Manager { - return &service{repo: repo} +func NewManager(config Config, repo Repository) Manager { + return &service{config: config, repo: repo} } // service implements Manager. // TODO [TXManager] convert this into an implementation of node.Server and start it at node start so that we can bring down transaction go routines cleanly type service struct { - repo Repository + config Config + repo Repository +} + +func (s *service) GetDefaultTaskTimeout() time.Duration { + return s.config.GetEthereumContextWaitTimeout() +} + +func (s *service) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status Status, taskName, message string) error { + tx, err := s.GetTransaction(accountID, id) + if err != nil { + return err + } + + // status particular to the task + tx.TaskStatus[taskName] = status + tx.Logs = append(tx.Logs, NewLog(taskName, message)) + return s.saveTransaction(tx) } // ExecuteWithinTX executes a transaction within a transaction. @@ -43,7 +74,7 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID t, err := s.repo.Get(accountID, existingTxID) if err != nil { t = newTransaction(accountID, desc) - err := s.SaveTransaction(t) + err := s.saveTransaction(t) if err != nil { return uuid.Nil, nil, err } @@ -55,20 +86,34 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID select { case e := <-err: - if e != nil { - t.Status = Failed - } else { - t.Status = Success + tempTx, err := s.repo.Get(accountID, t.ID) + if err != nil { + log.Error(e, err) + break } - e = s.SaveTransaction(t) + // update tx success status only if this wasn't an existing TX. + // Otherwise if might update an existing tx pending status to success without actually being a success, + // it is assumed that status updated is already handles per task in that case. + // Checking individual task success is upto the transaction manager calling code. + if e == nil && existingTxID == uuid.Nil { + tempTx.Status = Success + } else if e != nil { + tempTx.Status = Failed + } + e = s.saveTransaction(tempTx) if e != nil { log.Error(e) } case <-ctx.Done(): msg := fmt.Sprintf("Transaction %s for account %s with description \"%s\" is stopped because of context close", t.ID.String(), t.CID, t.Description) log.Warningf(msg) - t.Logs = append(t.Logs, NewLog("context closed", msg)) - e := s.SaveTransaction(t) + tempTx, err := s.repo.Get(accountID, t.ID) + if err != nil { + log.Error(err) + break + } + tempTx.Logs = append(tempTx.Logs, NewLog("context closed", msg)) + e := s.saveTransaction(tempTx) if e != nil { log.Error(e) } @@ -78,8 +123,8 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID return t.ID, done, nil } -// SaveTransaction saves the transaction. -func (s *service) SaveTransaction(tx *Transaction) error { +// saveTransaction saves the transaction. +func (s *service) saveTransaction(tx *Transaction) error { err := s.repo.Save(tx) if err != nil { return err @@ -92,15 +137,16 @@ func (s *service) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Tran return s.repo.Get(accountID, id) } -// CreateTransaction creates a new transaction and saves it to the DB. -func (s *service) CreateTransaction(accountID identity.CentID, desc string) (*Transaction, error) { +// createTransaction creates a new transaction and saves it to the DB. +func (s *service) createTransaction(accountID identity.CentID, desc string) (*Transaction, error) { tx := newTransaction(accountID, desc) - return tx, s.SaveTransaction(tx) + return tx, s.saveTransaction(tx) } // WaitForTransaction blocks until transaction status is moved from pending state. // Note: use it with caution as this will block. func (s *service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { + // TODO change this to use a pre-saved done channel from ExecuteWithinTX, instead of a for loop, may require significant refactoring to handle the case of restarted node for { resp, err := s.GetTransactionStatus(accountID, txID) if err != nil { diff --git a/transactions/manager_test.go b/transactions/manager_test.go index fd2b8214a..4ad0e326e 100644 --- a/transactions/manager_test.go +++ b/transactions/manager_test.go @@ -5,6 +5,7 @@ package transactions import ( "context" "testing" + "time" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -13,6 +14,12 @@ import ( "github.com/stretchr/testify/assert" ) +type mockConfig struct{} + +func (mockConfig) GetEthereumContextWaitTimeout() time.Duration { + panic("implement me") +} + func TestService_ExecuteWithinTX_happy(t *testing.T) { cid := identity.RandomCentID() srv := ctx[BootstrappedService].(Manager) @@ -101,21 +108,21 @@ func TestService_GetTransaction(t *testing.T) { } func TestService_CreateTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(Manager) + srv := ctx[BootstrappedService].(extendedManager) cid := identity.RandomCentID() - tx, err := srv.CreateTransaction(cid, "test") + tx, err := srv.createTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) assert.Equal(t, cid.String(), tx.CID.String()) } func TestService_WaitForTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(Manager) + srv := ctx[BootstrappedService].(extendedManager) repo := ctx[BootstrappedRepo].(Repository) cid := identity.RandomCentID() // failed - tx, err := srv.CreateTransaction(cid, "test") + tx, err := srv.createTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) assert.Equal(t, cid.String(), tx.CID.String()) From de7701c5b16217070f88eafc0d3f724792a43a00 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 5 Feb 2019 09:06:42 +0100 Subject: [PATCH 172/220] identity: bind identity service to did (#712) * added testworld tests for proofs * bind identity service to did * removed identity init from bootstrapper --- identity/did/bootstrapper.go | 7 ------ identity/did/execute_integration_test.go | 12 ++++----- identity/did/identity.go | 30 ++++++++++++----------- identity/did/identity_integration_test.go | 21 ++++++++++------ 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index 5af96eef1..b7dad253a 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -20,9 +20,6 @@ type Bootstrapper struct{} // BootstrappedDIDService stores the id of the service const BootstrappedDIDService string = "BootstrappedDIDService" -// BootstrappedDID stores the id of the identity -const BootstrappedDID string = "BootstrappedDID" - var smartContractAddresses *config.SmartContractAddresses // Bootstrap initializes the factory contract @@ -47,10 +44,6 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { service := NewService(cfg, factoryContract, client) context[BootstrappedDIDService] = service - - identity := NewIdentity(cfg, client) - context[BootstrappedDID] = identity - return nil } diff --git a/identity/did/execute_integration_test.go b/identity/did/execute_integration_test.go index 222c469d7..ea4748ca8 100644 --- a/identity/did/execute_integration_test.go +++ b/identity/did/execute_integration_test.go @@ -26,8 +26,8 @@ import ( ) func TestExecute_successful(t *testing.T) { - idSrv := ctx[BootstrappedDID].(Identity) did := deployIdentityContract(t) + idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) anchorAddress := getAnchorAddress() // init params @@ -36,7 +36,7 @@ func TestExecute_successful(t *testing.T) { testRootHash, _ := anchors.ToDocumentRoot(rootHash) proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) assert.Nil(t, err, "Execute method calls should be successful") txStatus := <-watchTrans @@ -47,8 +47,8 @@ func TestExecute_successful(t *testing.T) { } func TestExecute_fail_falseMethodName(t *testing.T) { - idSrv := ctx[BootstrappedDID].(Identity) did := deployIdentityContract(t) + idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) @@ -57,21 +57,21 @@ func TestExecute_fail_falseMethodName(t *testing.T) { proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) + watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) assert.Error(t, err, "should throw an error because method is not existing in abi") assert.Nil(t, watchTrans, "no channel should be returned") } func TestExecute_fail_MissingParam(t *testing.T) { - idSrv := ctx[BootstrappedDID].(Identity) did := deployIdentityContract(t) + idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) - watchTrans, err := idSrv.Execute(did, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) + watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) assert.Error(t, err, "should throw an error because method is not existing in abi") assert.Nil(t, watchTrans, "no channel should be returned") } diff --git a/identity/did/identity.go b/identity/did/identity.go index ae2b03fb8..b3e338b19 100644 --- a/identity/did/identity.go +++ b/identity/did/identity.go @@ -36,16 +36,16 @@ func NewDIDFromString(address string) DID { // Identity interface contains the methods to interact with the identity contract type Identity interface { // AddKey adds a key to identity contract - AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, error) + AddKey(key Key) (chan *ethereum.WatchTransaction, error) // GetKey return a key from the identity contract - GetKey(did *DID, key [32]byte) (*KeyResponse, error) + GetKey(key [32]byte) (*KeyResponse, error) // RawExecute calls the execute method on the identity contract - RawExecute(did *DID, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) + RawExecute(to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) // Execute creates the abi encoding an calls the execute method on the identity contract - Execute(did *DID, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) + Execute(to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) } type contract interface { @@ -66,6 +66,7 @@ type contract interface { type identity struct { config id.Config client ethereum.Client + did *DID } func (i identity) prepareTransaction(did DID) (contract, *bind.TransactOpts, error) { @@ -107,8 +108,9 @@ func (i identity) bindContract(did DID) (contract, error) { } // NewIdentity creates a instance of an identity -func NewIdentity(config id.Config, client ethereum.Client) Identity { - return identity{config: config, client: client} +func NewIdentity(config id.Config, client ethereum.Client, did *DID) Identity { + // TODO use DID stored in config file + return identity{config: config, client: client, did: did} } // TODO: will be replaced with statusTask @@ -127,8 +129,8 @@ func logTxHash(tx *types.Transaction) { log.Infof("Transfer pending: 0x%x\n", tx.Hash()) } -func (i identity) AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, error) { - contract, opts, err := i.prepareTransaction(*did) +func (i identity) AddKey(key Key) (chan *ethereum.WatchTransaction, error) { + contract, opts, err := i.prepareTransaction(*i.did) if err != nil { return nil, err } @@ -149,8 +151,8 @@ func (i identity) AddKey(did *DID, key Key) (chan *ethereum.WatchTransaction, er } -func (i identity) GetKey(did *DID, key [32]byte) (*KeyResponse, error) { - contract, opts, _, err := i.prepareCall(*did) +func (i identity) GetKey(key [32]byte) (*KeyResponse, error) { + contract, opts, _, err := i.prepareCall(*i.did) if err != nil { return nil, err } @@ -165,8 +167,8 @@ func (i identity) GetKey(did *DID, key [32]byte) (*KeyResponse, error) { } -func (i identity) RawExecute(did *DID, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { - contract, opts, err := i.prepareTransaction(*did) +func (i identity) RawExecute(to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { + contract, opts, err := i.prepareTransaction(*i.did) if err != nil { return nil, err } @@ -189,7 +191,7 @@ func (i identity) RawExecute(did *DID, to common.Address, data []byte) (chan *et } -func (i identity) Execute(did *DID, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { +func (i identity) Execute(to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { abi, err := abi.JSON(strings.NewReader(contractAbi)) if err != nil { return nil, err @@ -200,5 +202,5 @@ func (i identity) Execute(did *DID, to common.Address, contractAbi, methodName s if err != nil { return nil, err } - return i.RawExecute(did, to, data) + return i.RawExecute(to, data) } diff --git a/identity/did/identity_integration_test.go b/identity/did/identity_integration_test.go index d46930cd7..b45786994 100644 --- a/identity/did/identity_integration_test.go +++ b/identity/did/identity_integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/ethereum" @@ -17,6 +19,10 @@ func getTestKey() Key { return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} } +func initIdentity(config config.Configuration, client ethereum.Client, did *DID) Identity { + return NewIdentity(config, client, did) +} + func deployIdentityContract(t *testing.T) *DID { service := ctx[BootstrappedDIDService].(Service) did, _, err := service.CreateIdentity(context.Background()) @@ -35,35 +41,36 @@ func deployIdentityContract(t *testing.T) *DID { } func TestAddKey_successful(t *testing.T) { - idSrv := ctx[BootstrappedDID].(Identity) did := deployIdentityContract(t) + idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) + testKey := getTestKey() - watchTrans, err := idSrv.AddKey(did, testKey) + watchTrans, err := idSrv.AddKey(testKey) assert.Nil(t, err, "add key should be successful") txStatus := <-watchTrans assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions should be successful") - response, err := idSrv.GetKey(did, testKey.GetKey()) + response, err := idSrv.GetKey(testKey.GetKey()) assert.Nil(t, err, "get Key should be successful") assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") } func TestAddKey_fail(t *testing.T) { - did := NewDIDFromString("0x1234") testKey := getTestKey() - idSrv := ctx[BootstrappedDID].(Identity) + did := NewDIDFromString("0x123") + idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), &did) - watchTrans, err := idSrv.AddKey(&did, testKey) + watchTrans, err := idSrv.AddKey(testKey) assert.Nil(t, err, "add key should be successful") txStatus := <-watchTrans // contract is not existing but status is successful assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions") - _, err = idSrv.GetKey(&did, testKey.GetKey()) + _, err = idSrv.GetKey(testKey.GetKey()) assert.Error(t, err, "no contract code at given address") } From 5423a3e31d5c9a2e4fcd70422d010791fa2c8557 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 5 Feb 2019 12:04:09 +0100 Subject: [PATCH 173/220] Fixed dynamic evaluation of TAG attribute (#722) * Fixed dynamic evaluation of TAG attribute * Fixed dynamic evaluation of TAG attribute --- Makefile | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index f920beca6..c46438a3f 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,16 @@ TRAVIS_BRANCH?=`git rev-parse --abbrev-ref HEAD` GIT_COMMIT=`git rev-parse HEAD` GIT_SHORT_COMMIT=`git rev-parse --short HEAD` -TIMESTAMP=`date -u +%Y%m%d%H` +TIMESTAMP=`date -u +%Y%m%d%H%M%S` TAG="${TRAVIS_BRANCH}-${TIMESTAMP}-${GIT_SHORT_COMMIT}" IMAGE_NAME?=centrifugeio/go-centrifuge LD_FLAGS?="-X github.com/centrifuge/go-centrifuge/version.gitCommit=${GIT_COMMIT}" GCLOUD_SERVICE?="./build/peak-vista-185616-9f70002df7eb.json" -# GOBIN needs to be set to ensure govendor can actually be found and executed +# Default TAGINSTANCE for standalone targets +TAGINSTANCE="${TAG}" + +# GOBIN needs to be set to ensure govendor can actually be found and executed PATH=$(shell printenv PATH):$(GOBIN) # If you need to overwrite PROTOTOOL_BIN, you can set this environment variable. @@ -75,20 +78,21 @@ build-linux-amd64: install-xgo @mkdir -p build/linux-amd64 @xgo -go 1.11.x -dest build/linux-amd64 -targets=linux/amd64 -ldflags=${LD_FLAGS} ./cmd/centrifuge/ @mv build/linux-amd64/centrifuge-linux-amd64 build/linux-amd64/centrifuge - @tar -zcvf cent-api-linux-amd64-${TAG}.tar.gz -C build/linux-amd64/ . + $(eval TAGINSTANCE := $(shell echo ${TAG})) + @tar -zcvf cent-api-linux-amd64-${TAGINSTANCE}.tar.gz -C build/linux-amd64/ . build-docker: ## Build Docker Image build-docker: @echo "Building Docker Image" - @docker build -t ${IMAGE_NAME}:${TAG} . + @docker build -t ${IMAGE_NAME}:${TAGINSTANCE} . build-ci: ## Builds + Push all artifacts build-ci: build-linux-amd64 build-docker @echo "Building/Pushing Artifacts for CI" @gcloud auth activate-service-account --key-file ${GCLOUD_SERVICE} - @gsutil cp cent-api-*-${TAG}.tar.gz gs://centrifuge-artifact-releases/ - @gsutil acl ch -u AllUsers:R gs://centrifuge-artifact-releases/cent-api-*-${TAG}.tar.gz + @gsutil cp cent-api-*-${TAGINSTANCE}.tar.gz gs://centrifuge-artifact-releases/ + @gsutil acl ch -u AllUsers:R gs://centrifuge-artifact-releases/cent-api-*-${TAGINSTANCE}.tar.gz @echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin - @docker tag "${IMAGE_NAME}:${TAG}" "${IMAGE_NAME}:latest" + @docker tag "${IMAGE_NAME}:${TAGINSTANCE}" "${IMAGE_NAME}:latest" @docker push ${IMAGE_NAME}:latest - @docker push ${IMAGE_NAME}:${TAG} + @docker push ${IMAGE_NAME}:${TAGINSTANCE} From 8aa26db5f70e29fd5be713db230ead2c9144ce81 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 6 Feb 2019 18:00:05 +0530 Subject: [PATCH 174/220] retry when txhash not found (#727) Since infura load balances between multiple nodes, if the transaction is not propagated to the current node, it will return "not found". We should retry in this scenario instead of marking the transaction to be failed --- ethereum/transaction_status_task.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 8e36eb7e9..74799b5ef 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -4,14 +4,14 @@ import ( "context" "time" - "github.com/ethereum/go-ethereum/core/types" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/gocelery" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) const ( @@ -151,6 +151,12 @@ func (tst *TransactionStatusTask) RunTask() (resp interface{}, err error) { _, isPending, err := tst.transactionByHash(ctx, common.HexToHash(tst.txHash)) if err != nil { + // if the tx is not propagated, this will error out with "Not found" + // lets retry in this scenario as well + if err == ethereum.NotFound { + err = gocelery.ErrTaskRetryable + } + return nil, err } From fab9b96bd5ba8e63508778b9a89ecf09d6d33211 Mon Sep 17 00:00:00 2001 From: Charly Date: Wed, 6 Feb 2019 13:34:32 +0100 Subject: [PATCH 175/220] CoreDocModel + PrepareNewVersion (#725) * added CoreDocumentModel * add fetchUniqueCollaborators test * add docModel/readACLs files --- documents/model.go | 121 +++++++++++++++++++++++++++++ documents/model_test.go | 95 ++++++++++++++++++++++- documents/read_acls.go | 148 ++++++++++++++++++++++++++++++++++++ documents/read_acls_test.go | 125 ++++++++++++++++++++++++++++++ 4 files changed, 487 insertions(+), 2 deletions(-) create mode 100644 documents/read_acls.go create mode 100644 documents/read_acls_test.go diff --git a/documents/model.go b/documents/model.go index 66b9c8d35..dd5efcdd8 100644 --- a/documents/model.go +++ b/documents/model.go @@ -2,12 +2,18 @@ package documents import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common/hexutil" ) // Model is an interface to abstract away model specificness like invoice or purchaseOrder // The interface can cast into the type specified by the model if required +// It should only handle protocol-level Document actions type Model interface { storage.Model @@ -25,3 +31,118 @@ type Model interface { // CreateProofs creates precise-proofs for given fields CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) } + +// CoreDocumentModel contains methods which handle all interactions mutating or reading from a core document +// Access to a core document should always go through this model +type CoreDocumentModel struct { + Document *coredocumentpb.CoreDocument +} + +// NewCoreDocModel returns a new CoreDocumentModel +// Note: collaborators and salts are to be filled by the caller +func NewCoreDocModel() *CoreDocumentModel { + id := utils.RandomSlice(32) + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: id, + CurrentVersion: id, + NextVersion: utils.RandomSlice(32), + } + return &CoreDocumentModel{ + cd, + } +} + +// PrepareNewVersion creates a new CoreDocumentModel with the version fields updated +// Adds collaborators and fills salts +// Note: new collaborators are added to the list with old collaborators. +//TODO: this will change when collaborators are moved down to next level +func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocumentModel, error) { + ndm := NewCoreDocModel() + ncd := ndm.Document + ocd := m.Document + ucs, err := fetchUniqueCollaborators(ocd.Collaborators, collaborators) + if err != nil { + return nil, errors.New("failed to decode collaborator: %v", err) + } + + cs := ncd.Collaborators + for _, c := range ucs { + c := c + cs = append(cs, c[:]) + } + + ncd.Collaborators = cs + + // copy read rules and roles + ncd.Roles = m.Document.Roles + ncd.ReadRules = m.Document.ReadRules + addCollaboratorsToReadSignRules(ncd, ucs) + + err = ndm.fillSalts() + if err != nil { + return nil, err + } + + if ocd.DocumentIdentifier == nil { + return nil, errors.New("coredocument.DocumentIdentifier is nil") + } + ncd.DocumentIdentifier = ocd.DocumentIdentifier + + if ocd.CurrentVersion == nil { + return nil, errors.New("coredocument.CurrentVersion is nil") + } + ncd.PreviousVersion = ocd.CurrentVersion + + if ocd.NextVersion == nil { + return nil, errors.New("coredocument.NextVersion is nil") + } + + ncd.CurrentVersion = ocd.NextVersion + ncd.NextVersion = utils.RandomSlice(32) + if ocd.DocumentRoot == nil { + return nil, errors.New("DocumentRoot is nil") + } + ncd.PreviousRoot = ocd.DocumentRoot + + return ndm, nil +} + +// FillSalts creates a new coredocument.Salts and fills it +func (m *CoreDocumentModel) fillSalts() error { + salts := new(coredocumentpb.CoreDocumentSalts) + cd := m.Document + err := proofs.FillSalts(cd, salts) + if err != nil { + return errors.New("failed to fill coredocument salts: %v", err) + } + + cd.CoredocumentSalts = salts + return nil +} + +func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.CentID, err error) { + ocsm := make(map[string]struct{}) + for _, c := range oldCollabs { + ocsm[hexutil.Encode(c)] = struct{}{} + } + + var uc []string + for _, c := range newCollabs { + if _, ok := ocsm[c]; ok { + continue + } + + uc = append(uc, c) + } + + for _, c := range uc { + id, err := identity.CentIDFromString(c) + if err != nil { + return nil, err + } + + ids = append(ids, id) + } + + return ids, nil +} diff --git a/documents/model_test.go b/documents/model_test.go index c0cdab28d..d56ae41d1 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -6,12 +6,13 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/config/configstore" @@ -20,7 +21,9 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/queue" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/stretchr/testify/assert" ) var ctx map[string]interface{} @@ -56,3 +59,91 @@ func TestMain(m *testing.M) { bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) } + +func Test_fetchUniqueCollaborators(t *testing.T) { + + tests := []struct { + old [][]byte + new []string + result []identity.CentID + err bool + }{ + { + new: []string{"0x010203040506"}, + result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}}, + new: []string{"0x010203040506"}, + result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + new: []string{"0x010203040506"}, + }, + + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + }, + + // new collaborator with wrong format + { + old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + new: []string{"0x0102030405"}, + err: true, + }, + } + + for _, c := range tests { + uc, err := fetchUniqueCollaborators(c.old, c.new) + if err != nil { + if c.err { + continue + } + + t.Fatal(err) + } + + assert.Equal(t, c.result, uc) + } +} + +func TestCoreDocumentModel_PrepareNewVersion(t *testing.T) { + dm := NewCoreDocModel() + cd := dm.Document + assert.NotNil(t, cd) + + //collaborators need to be hex string + collabs := []string{"some ID"} + newDocModel, err := dm.PrepareNewVersion(collabs) + assert.Error(t, err) + assert.Nil(t, newDocModel) + + // missing DocumentRoot + c1 := utils.RandomSlice(6) + c2 := utils.RandomSlice(6) + c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} + ndm, err := dm.PrepareNewVersion(c) + assert.NotNil(t, err) + assert.Nil(t, ndm) + + // successful preparation of new version upon addition of DocumentRoot + cd.DocumentRoot = utils.RandomSlice(32) + ndm, err = dm.PrepareNewVersion(c) + assert.Nil(t, err) + assert.NotNil(t, ndm) + + // successful updating of version in new Document + ncd := ndm.Document + ocd := dm.Document + assert.Equal(t, ncd.PreviousVersion, ocd.CurrentVersion) + assert.Equal(t, ncd.CurrentVersion, ocd.NextVersion) + + // DocumentIdentifier has not changed + assert.Equal(t, ncd.DocumentIdentifier, ocd.DocumentIdentifier) + + // DocumentRoot was updated + assert.Equal(t, ncd.PreviousRoot, ocd.DocumentRoot) +} diff --git a/documents/read_acls.go b/documents/read_acls.go new file mode 100644 index 000000000..36d8808ff --- /dev/null +++ b/documents/read_acls.go @@ -0,0 +1,148 @@ +package documents + +import ( + "bytes" + + "github.com/centrifuge/go-centrifuge/utils" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/ethereum/go-ethereum/common" +) + +const ( + // ErrZeroCollaborators error when no collaborators are passed + ErrZeroCollaborators = errors.Error("require at least one collaborator") + + // nftByteCount is the length of combined bytes of registry and tokenID + nftByteCount = 52 +) + +// TokenRegistry defines NFT retrieval functions. +type TokenRegistry interface { + // OwnerOf to retrieve owner of the tokenID + OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) +} + +// initReadRules initiates the read rules for a given coredocument. +// Collaborators are given Read_Sign action. +// if the rules are created already, this is a no-op. +func initReadRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { + if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { + return nil + } + + if len(collabs) < 1 { + return ErrZeroCollaborators + } + + return addCollaboratorsToReadSignRules(cd, collabs) +} + +func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { + if len(collabs) == 0 { + return nil + } + + // create a role for given collaborators + role := new(coredocumentpb.Role) + rk, err := utils.ConvertIntToByte32(len(cd.Roles)) + if err != nil { + return err + } + role.RoleKey = rk[:] + for _, c := range collabs { + c := c + role.Collaborators = append(role.Collaborators, c[:]) + } + + addNewRule(cd, role, coredocumentpb.Action_ACTION_READ_SIGN) + + return nil +} + +// addNewRule creates a new rule as per the role and action. +func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, action coredocumentpb.Action) { + cd.Roles = append(cd.Roles, role) + + rule := new(coredocumentpb.ReadRule) + rule.Roles = append(rule.Roles, role.RoleKey) + rule.Action = action + cd.ReadRules = append(cd.ReadRules, rule) +} + +// ReadAccessValidator defines validator functions for account . +type ReadAccessValidator interface { + AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool +} + +// readAccessValidator implements ReadAccessValidator. +type readAccessValidator struct { + tokenRegistry TokenRegistry +} + +// AccountCanRead validate if the core document can be read by the account . +// Returns an error if not. +func (r readAccessValidator) AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool { + // loop though read rules + return findRole(cd, coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { + return isAccountInRole(role, account) + }) +} + +func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { + for _, role := range roles { + if utils.IsSameByteSlice(role.RoleKey, key) { + return role, nil + } + } + + return nil, errors.New("role %d not found", key) +} + +// isAccountInRole returns true if account is in the given role as collaborators. +func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { + for _, id := range role.Collaborators { + if bytes.Equal(id, account[:]) { + return true + } + } + + return false +} + +// AccountValidator returns the ReadAccessValidator to verify account . +func AccountValidator() ReadAccessValidator { + return readAccessValidator{} +} + +// findRole calls OnRole for every role, +// if onRole returns true, returns true +// else returns false +func findRole( + cd *coredocumentpb.CoreDocument, + action coredocumentpb.Action, + onRole func(role *coredocumentpb.Role) bool) bool { + for _, rule := range cd.ReadRules { + if rule.Action != action { + continue + } + + for _, rk := range rule.Roles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + + if onRole(role) { + return true + } + + } + } + + return false +} diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go new file mode 100644 index 000000000..d57fb5ab0 --- /dev/null +++ b/documents/read_acls_test.go @@ -0,0 +1,125 @@ +// +build unit + +package documents + +import ( + "testing" + + "github.com/centrifuge/go-centrifuge/coredocument" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestReadACLs_initReadRules(t *testing.T) { + cd := coredocument.New() + err := initReadRules(cd, nil) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) + + cs := []identity.CentID{identity.RandomCentID()} + err = initReadRules(cd, cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) + + err = initReadRules(cd, cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) +} + +func TestReadAccessValidator_AccountCanRead(t *testing.T) { + pv := AccountValidator() + account, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + cd, err := coredocument.NewWithCollaborators([]string{account.String()}) + assert.NoError(t, err) + assert.NotNil(t, cd.ReadRules) + assert.NotNil(t, cd.Roles) + + // account who cant access + rcid := identity.RandomCentID() + assert.False(t, pv.AccountCanRead(cd, rcid)) + + // account can access + assert.True(t, pv.AccountCanRead(cd, account)) +} + +func Test_addNFTToReadRules(t *testing.T) { + // wrong registry or token format + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(34) + + err := coredocument.AddNFTToReadRules(nil, registry, tokenID) + assert.Error(t, err) + + cd, err := coredocument.NewWithCollaborators([]string{"0x010203040506"}) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) + assert.Len(t, cd.Roles, 1) + + tokenID = utils.RandomSlice(32) + err = coredocument.AddNFTToReadRules(cd, registry, tokenID) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 2) + assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) + assert.Len(t, cd.Roles, 2) +} + +type mockRegistry struct { + mock.Mock +} + +func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { + args := m.Called(registry, tokenID) + addr, _ := args.Get(0).(common.Address) + return addr, args.Error(1) +} + +func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { + account, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + cd, err := coredocument.NewWithCollaborators([]string{account.String()}) + assert.NoError(t, err) + + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + + // account can read + validator := coredocument.NftValidator(nil) + err = validator.NFTOwnerCanRead(cd, registry, nil, account) + assert.NoError(t, err) + + // account not in read rules and nft missing + account, err = identity.CentIDFromString("0x010203040505") + assert.NoError(t, err) + tokenID := utils.RandomSlice(32) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) + assert.Error(t, err) + + tr := mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() + coredocument.AddNFTToReadRules(cd, registry, tokenID) + validator = coredocument.NftValidator(tr) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) + assert.Error(t, err) + assert.Contains(t, err, "failed to get owner of") + tr.AssertExpectations(t) + + // not the same owner + owner := common.BytesToAddress(utils.RandomSlice(20)) + tr = mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + validator = coredocument.NftValidator(tr) + err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) + assert.Error(t, err) + tr.AssertExpectations(t) +} From c435118e0e7d3660686d38804ee54a0f4a5914e7 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 6 Feb 2019 13:44:19 +0100 Subject: [PATCH 176/220] identity: create identity uses txManager (#724) * added testworld tests for proofs * bind identity service to did * removed identity init from bootstrapper * added account context to create identity * added waitingTransaction task * create identity uses task manager * refactored add key and execute tests * correct usage of done flag --- identity/did/bootstrapper.go | 47 +++++++-- identity/did/identity_integration_test.go | 5 +- identity/did/service.go | 116 ++++++++++++++++++---- identity/did/service_integration_test.go | 9 +- 4 files changed, 143 insertions(+), 34 deletions(-) diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index b7dad253a..6ff8a0d70 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -6,6 +6,10 @@ import ( "os/exec" "path" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" @@ -42,7 +46,17 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return err } - service := NewService(cfg, factoryContract, client) + txManager, ok := context[transactions.BootstrappedService].(transactions.Manager) + if !ok { + return errors.New("transactions repository not initialised") + } + + queueSrv, ok := context[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue hasn't been initialized") + } + + service := NewService(cfg, factoryContract, client, txManager, queueSrv) context[BootstrappedDIDService] = service return nil } @@ -101,17 +115,15 @@ func getSmartContractAddresses() *config.SmartContractAddresses { anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") return &config.SmartContractAddresses{ - IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), - AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), - PaymentObligationAddr: getOpAddr(payObAddrOp, dat), + IdentityFactoryAddr: getOpField(idFactoryAddrOp, dat), + AnchorRepositoryAddr: getOpField(anchorRepoAddrOp, dat), + PaymentObligationAddr: getOpField(payObAddrOp, dat), } } - -// TODO: func will be removed after migration -func findContractDeployJSON() ([]byte, error) { +func getFileFromContractRepo(filePath string) ([]byte, error) { gp := os.Getenv("GOPATH") projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") - deployJSONFile := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + deployJSONFile := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts", filePath) dat, err := ioutil.ReadFile(deployJSONFile) if err != nil { return nil, err @@ -119,6 +131,23 @@ func findContractDeployJSON() ([]byte, error) { return dat, nil } +// TODO: func will be refactored after migration +func getIdentityByteCode() string { + dat, err := findContractDeployJSON() + if err != nil { + panic(err) + } + optByte := getOpForContract(".contracts.Identity.bytecode") + byteCodeHex := getOpField(optByte, dat) + return byteCodeHex + +} + +// TODO: func will be removed after migration +func findContractDeployJSON() ([]byte, error) { + return getFileFromContractRepo(path.Join("deployments", "localgeth.json")) +} + // TODO: func will be removed after migration func getOpForContract(selector string) jq.Op { addrOp, err := jq.Parse(selector) @@ -129,7 +158,7 @@ func getOpForContract(selector string) jq.Op { } // TODO: func will be removed after migration -func getOpAddr(addrOp jq.Op, dat []byte) string { +func getOpField(addrOp jq.Op, dat []byte) string { addr, err := addrOp.Apply(dat) if err != nil { panic(err) diff --git a/identity/did/identity_integration_test.go b/identity/did/identity_integration_test.go index b45786994..4da98b006 100644 --- a/identity/did/identity_integration_test.go +++ b/identity/did/identity_integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/utils" @@ -25,7 +27,8 @@ func initIdentity(config config.Configuration, client ethereum.Client, did *DID) func deployIdentityContract(t *testing.T) *DID { service := ctx[BootstrappedDIDService].(Service) - did, _, err := service.CreateIdentity(context.Background()) + accountCtx := testingconfig.CreateAccountContext(t, cfg) + did, err := service.CreateIdentity(accountCtx) assert.Nil(t, err, "create identity should be successful") client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) diff --git a/identity/did/service.go b/identity/did/service.go index 34f48f1c5..ce884f55a 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -3,6 +3,14 @@ package did import ( "context" + "github.com/centrifuge/go-centrifuge/errors" + + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/satori/go.uuid" + "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/common" @@ -14,19 +22,21 @@ var log = logging.Logger("identity") // Service is the interface for identity related interactions type Service interface { - CreateIdentity(ctx context.Context) (id *DID, confirmations chan *id.WatchIdentity, err error) + CreateIdentity(ctx context.Context) (id *DID, err error) } type service struct { config id.Config factoryContract *FactoryContract client ethereum.Client + txManager transactions.Manager + queue *queue.Server } // NewService returns a new identity service -func NewService(config id.Config, factoryContract *FactoryContract, client ethereum.Client) Service { +func NewService(config id.Config, factoryContract *FactoryContract, client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Service { - return &service{config: config, factoryContract: factoryContract, client: client} + return &service{config: config, factoryContract: factoryContract, client: client, txManager: txManager, queue: queue} } func (s *service) getNonceAt(ctx context.Context, address common.Address) (uint64, error) { @@ -41,34 +51,100 @@ func CalculateCreatedAddress(address common.Address, nonce uint64) common.Addres return crypto.CreateAddress(address, nonce) } -func (s *service) CreateIdentity(ctx context.Context) (id *DID, confirmations chan *id.WatchIdentity, err error) { - opts, err := s.client.GetTxOpts(s.config.GetEthereumDefaultAccountName()) +func (s *service) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + ethTX, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) + if err != nil { + errOut <- err + log.Infof("Failed to send identity for creation [txHash: %s] : %v", ethTX.Hash(), err) + return + } + + log.Infof("Sent off identity creation Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", ethTX.Hash(), ethTX.Nonce(), ethTX.CheckNonce()) + log.Infof("Transfer pending: 0x%x\n", ethTX.Hash()) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), s.queue) + if err != nil { + errOut <- err + return + } + + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } + errOut <- nil + } + +} + +func (s *service) calculateIdentityAddress(ctx context.Context) (*common.Address, error) { + factoryAddress := getFactoryAddress() + nonce, err := s.getNonceAt(ctx, factoryAddress) if err != nil { - log.Infof("Failed to get txOpts from Ethereum client: %v", err) - return nil, nil, err + return nil, err } - tx, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) + identityAddress := CalculateCreatedAddress(factoryAddress, nonce) + log.Infof("Calculated Address of the identity contract: 0x%x\n", identityAddress) + return &identityAddress, nil +} + +func (s *service) isIdentityContract(identityAddress common.Address) error { + contractCode, err := s.client.GetEthClient().CodeAt(context.Background(), identityAddress, nil) if err != nil { - log.Infof("Failed to send identity for creation [txHash: %s] : %v", tx.Hash(), err) - return nil, nil, err + return err } - log.Infof("Sent off identity creation Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", tx.Hash(), tx.Nonce(), tx.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", tx.Hash()) + deployedContractByte := common.Bytes2Hex(contractCode) + identityContractByte := getIdentityByteCode()[2:] // remove 0x prefix + if deployedContractByte != identityContractByte { + return errors.New("deployed identity contract bytecode not correct") + } + return nil - // TODO use transactionStatusTask and following code as a statusHandler +} - factoryAddress := getFactoryAddress() - nonce, err := s.getNonceAt(ctx, factoryAddress) +func (s *service) CreateIdentity(ctx context.Context) (did *DID, err error) { + tc, err := contextutil.Account(ctx) if err != nil { - return nil, nil, err + return nil, err } - identityAddress := CalculateCreatedAddress(factoryAddress, nonce) - log.Infof("Address of created identity contract: 0x%x\n", identityAddress) + opts, err := s.client.GetTxOpts(tc.GetEthereumDefaultAccountName()) + if err != nil { + log.Infof("Failed to get txOpts from Ethereum client: %v", err) + return nil, err + } + + idConfig, err := contextutil.Self(ctx) + if err != nil { + return nil, err + } + + identityAddress, err := s.calculateIdentityAddress(ctx) + if err != nil { + return nil, err + } - did := NewDID(identityAddress) + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), idConfig.ID, uuid.Nil, "Check TX for create identity status", s.createIdentityTX(opts)) + if err != nil { + return nil, err + } + + isDone := <-done + // non async task + if !isDone { + return nil, errors.New("Create Identity TX failed: txID:%s", txID.String()) + + } + + err = s.isIdentityContract(*identityAddress) + if err != nil { + return nil, err + } - return &did, nil, nil + createdDID := NewDID(*identityAddress) + return &createdDID, nil } diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index 3ed1242cd..4c38994ae 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -7,7 +7,6 @@ import ( "fmt" "os" "testing" - "time" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -17,6 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -47,13 +47,14 @@ func TestMain(m *testing.M) { func TestCreateIdentity_successful(t *testing.T) { service := ctx[BootstrappedDIDService].(Service) - did, _, err := service.CreateIdentity(context.Background()) + + accountCtx := testingconfig.CreateAccountContext(t, cfg) + + did, err := service.CreateIdentity(accountCtx) assert.Nil(t, err, "create identity should be successful") client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - time.Sleep(2000 * time.Millisecond) - contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") From 1ab57e385484a26dc412710493990dbda1207a2d Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 6 Feb 2019 16:45:08 +0100 Subject: [PATCH 177/220] Make dataroot part of signing tree (#708) * Make dataroot part of signing tree * Removing use of Dataroot and tests for proofs * Fix tests * Fix tests * fix tests * remove test --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- coredocument/coredocument.go | 95 +++++++++++++++++------ coredocument/coredocument_test.go | 90 +++++++++++++++++++-- documents/documents_test/service_test.go | 9 ++- documents/invoice/model.go | 7 +- documents/invoice/model_test.go | 9 +-- documents/invoice/service.go | 14 +--- documents/invoice/service_test.go | 9 +-- documents/invoice/validator.go | 42 ---------- documents/invoice/validator_test.go | 65 +--------------- documents/model.go | 3 + documents/processor.go | 7 +- documents/processor_test.go | 24 +++++- documents/purchaseorder/model.go | 9 +-- documents/purchaseorder/model_test.go | 9 +-- documents/purchaseorder/service.go | 14 +--- documents/purchaseorder/service_test.go | 10 +-- documents/purchaseorder/validator.go | 42 ---------- documents/purchaseorder/validator_test.go | 65 +--------------- documents/validator.go | 11 +-- documents/validator_test.go | 47 +---------- p2p/client_integration_test.go | 37 +++++++-- p2p/receiver/handler_integration_test.go | 28 ++++++- testingutils/coredocument/coredocument.go | 11 ++- 25 files changed, 303 insertions(+), 360 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 8115aec07..faafc1a56 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:5616d244073fc94efbff79cd244cb3553a8bcf130f97e0e84d94ee6a68073fc1" + digest = "1:9ae859e0e06b1ef79ebe8e7a6ae62bc696bde18d142de253097edb58cad17984" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" + revision = "569fc37a1acbc443894362b51b2e42496c5ad59c" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 406068c3d..caf5fe95a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "4b3f2f725dbef3290b1cd95620b955a771c38da4" + revision = "569fc37a1acbc443894362b51b2e42496c5ad59c" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index 772a5bca7..8c03b4003 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -16,8 +16,8 @@ import ( // getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used // to create field proofs -func getDataProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { - tree, err := GetDocumentSigningTree(document) +func getDataProofHashes(document *coredocumentpb.CoreDocument, dataRoot []byte) (hashes [][]byte, err error) { + tree, err := GetDocumentSigningTree(document, dataRoot) if err != nil { return } @@ -27,7 +27,7 @@ func getDataProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, return } - rootProofHashes, err := getSigningProofHashes(document) + rootProofHashes, err := getSigningRootProofHashes(document) if err != nil { return } @@ -35,9 +35,9 @@ func getDataProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, return append(signingProof.SortedHashes, rootProofHashes...), err } -// getSigningProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DataRoot. This method is used +// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. This method is used // to create field proofs -func getSigningProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { +func getSigningRootProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { tree, err := GetDocumentRootTree(document) if err != nil { return @@ -50,8 +50,8 @@ func getSigningProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]by } // CalculateSigningRoot calculates the signing root of the core document -func CalculateSigningRoot(doc *coredocumentpb.CoreDocument) error { - tree, err := GetDocumentSigningTree(doc) +func CalculateSigningRoot(doc *coredocumentpb.CoreDocument, dataRoot []byte) error { + tree, err := GetDocumentSigningTree(doc, dataRoot) if err != nil { return err } @@ -94,7 +94,10 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do Salt: make([]byte, 32), Value: fmt.Sprintf("%d", len(document.Signatures)), } - sigLengthNode.HashNode(h, false) + err = sigLengthNode.HashNode(h, false) + if err != nil { + return nil, err + } sigLeafList[0] = sigLengthNode for i, sig := range document.Signatures { payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) @@ -103,7 +106,10 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do Hashed: true, Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), } - leaf.HashNode(h, false) + err = leaf.HashNode(h, false) + if err != nil { + return nil, err + } sigLeafList[i+1] = leaf } err = tree.AddLeaves(sigLeafList) @@ -117,8 +123,8 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do return tree, nil } -// GetDocumentSigningTree returns the merkle tree for the signing root -func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { +// GetCoreDocTree returns the merkle tree for the coredoc root +func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { h := sha256.New() t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) tree = &t @@ -136,7 +142,12 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs Salt: make([]byte, 32), Value: document.EmbeddedData.TypeUrl, } - documentTypeNode.HashNode(h, false) + + err = documentTypeNode.HashNode(h, false) + if err != nil { + return nil, err + } + err = tree.AddLeaf(documentTypeNode) if err != nil { return nil, err @@ -149,6 +160,44 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument) (tree *proofs return tree, nil } +// GetDocumentSigningTree returns the merkle tree for the signing root +func GetDocumentSigningTree(document *coredocumentpb.CoreDocument, dataRoot []byte) (tree *proofs.DocumentTree, err error) { + h := sha256.New() + + // coredoc tree + coreDocTree, err := GetCoreDocTree(document) + if err != nil { + return nil, err + } + + // create the signing tree with data root and coredoc root as siblings + t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + tree = &t2 + err = tree.AddLeaves([]proofs.LeafNode{ + { + Property: proofs.NewProperty("data_root"), + Hash: dataRoot, + Hashed: true, + }, + { + Property: proofs.NewProperty("cd_root"), + Hash: coreDocTree.RootHash(), + Hashed: true, + }, + }) + + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + + return tree, nil +} + // PrepareNewVersion creates a copy of the passed coreDocument with the version fields updated // Adds collaborators and fills salts // Note: new collaborators are added to the list with old collaborators. @@ -170,7 +219,10 @@ func PrepareNewVersion(oldCD coredocumentpb.CoreDocument, collaborators []string // copy read rules and roles ncd.Roles = oldCD.Roles ncd.ReadRules = oldCD.ReadRules - addCollaboratorsToReadSignRules(ncd, ucs) + err = addCollaboratorsToReadSignRules(ncd, ucs) + if err != nil { + return nil, err + } err = FillSalts(ncd) if err != nil { @@ -283,25 +335,22 @@ func GetTypeURL(coreDocument *coredocumentpb.CoreDocument) (string, error) { // CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDocument, fields []string) (proofs []*proofspb.Proof, err error) { - dataRootHashes, err := getDataProofHashes(coreDoc) + signingRootProofHashes, err := getSigningRootProofHashes(coreDoc) if err != nil { return nil, errors.New("createProofs error %v", err) } - signingRootHashes, err := getSigningProofHashes(coreDoc) + cdtree, err := GetCoreDocTree(coreDoc) if err != nil { return nil, errors.New("createProofs error %v", err) } - cdtree, err := GetDocumentSigningTree(coreDoc) - if err != nil { - return nil, errors.New("createProofs error %v", err) - } + dataRoot := dataTree.RootHash() + cdRoot := cdtree.RootHash() // We support fields that belong to different document trees, as we do not prepend a tree prefix to the field, the approach // is to try in both trees to find the field and create the proof accordingly for _, field := range fields { - rootHashes := dataRootHashes proof, err := dataTree.CreateProof(field) if err != nil { if strings.Contains(err.Error(), "No such field") { @@ -309,12 +358,14 @@ func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDoc if err != nil { return nil, errors.New("createProofs error %v", err) } - rootHashes = signingRootHashes + proof.SortedHashes = append(proof.SortedHashes, dataRoot) } else { return nil, errors.New("createProofs error %v", err) } + } else { + proof.SortedHashes = append(proof.SortedHashes, cdRoot) } - proof.SortedHashes = append(proof.SortedHashes, rootHashes...) + proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) proofs = append(proofs, &proof) } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index de2c37961..3715038a9 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -57,13 +57,13 @@ func TestGetSigningProofHashes(t *testing.T) { assert.Nil(t, err) cd.CoredocumentSalts = cds - err = CalculateSigningRoot(cd) + err = CalculateSigningRoot(cd, cd.DataRoot) assert.Nil(t, err) err = CalculateDocumentRoot(cd) assert.Nil(t, err) - hashes, err := getSigningProofHashes(cd) + hashes, err := getSigningRootProofHashes(cd) assert.Nil(t, err) assert.Equal(t, 1, len(hashes)) @@ -86,15 +86,15 @@ func TestGetDataProofHashes(t *testing.T) { cd.CoredocumentSalts = cds - err = CalculateSigningRoot(cd) + err = CalculateSigningRoot(cd, cd.DataRoot) assert.Nil(t, err) err = CalculateDocumentRoot(cd) assert.Nil(t, err) - hashes, err := getDataProofHashes(cd) + hashes, err := getDataProofHashes(cd, cd.DataRoot) assert.Nil(t, err) - assert.Equal(t, 5, len(hashes)) + assert.Equal(t, 2, len(hashes)) valid, err := proofs.ValidateProofSortedHashes(cd.DataRoot, hashes, cd.DocumentRoot, sha256.New()) assert.True(t, valid) @@ -111,11 +111,14 @@ func TestGetDocumentSigningTree(t *testing.T) { cds := &coredocumentpb.CoreDocumentSalts{} proofs.FillSalts(cd, cds) cd.CoredocumentSalts = cds - tree, err := GetDocumentSigningTree(cd) + tree, err := GetDocumentSigningTree(cd, cd.DataRoot) assert.Nil(t, err) assert.NotNil(t, tree) - _, leaf := tree.GetLeafByProperty("document_type") + _, leaf := tree.GetLeafByProperty("data_root") + assert.NotNil(t, leaf) + + _, leaf = tree.GetLeafByProperty("cd_root") assert.NotNil(t, leaf) } @@ -124,7 +127,7 @@ func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { cds := &coredocumentpb.CoreDocumentSalts{} proofs.FillSalts(cd, cds) cd.CoredocumentSalts = cds - tree, err := GetDocumentSigningTree(cd) + tree, err := GetDocumentSigningTree(cd, cd.DataRoot) assert.NotNil(t, err) assert.Nil(t, tree) } @@ -233,6 +236,77 @@ func TestNewWithCollaborators(t *testing.T) { assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) } +func TestCreateProofs(t *testing.T) { + h := sha256.New() + testTree := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) + err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field")}) + assert.NoError(t, err) + err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field2")}) + assert.NoError(t, err) + err = testTree.Generate() + assert.NoError(t, err) + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + cd := New() + cd.EmbeddedData = docAny + cd.DocumentIdentifier = utils.RandomSlice(32) + cd.NextVersion = utils.RandomSlice(32) + cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} + err = FillSalts(cd) + assert.NoError(t, err) + err = CalculateSigningRoot(cd, testTree.RootHash()) + assert.NoError(t, err) + err = CalculateDocumentRoot(cd) + assert.NoError(t, err) + cdTree, err := GetCoreDocTree(cd) + assert.NoError(t, err) + tests := []struct { + fieldName string + fromCoreDoc bool + proofLength int + }{ + { + "sample_field", + false, + 3, + }, + { + "document_identifier", + true, + 6, + }, + { + "sample_field2", + false, + 3, + }, + { + "collaborators[0]", + true, + 6, + }, + } + for _, test := range tests { + t.Run(test.fieldName, func(t *testing.T) { + p, err := CreateProofs(&testTree, cd, []string{test.fieldName}) + assert.NoError(t, err) + assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) + var l *proofs.LeafNode + if test.fromCoreDoc { + _, l = cdTree.GetLeafByProperty(test.fieldName) + } else { + _, l = testTree.GetLeafByProperty(test.fieldName) + } + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) + assert.NoError(t, err) + assert.True(t, valid) + }) + } + +} + func TestGetExternalCollaborators(t *testing.T) { c1 := utils.RandomSlice(6) c2 := utils.RandomSlice(6) diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index 314f9295e..0b6629e12 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -89,7 +89,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, GrossAmount: 60, CoreDocument: coredocument.New(), } - err := i.CalculateDataRoot() + dataRoot, err := i.CalculateDataRoot() if err != nil { return nil, err } @@ -99,7 +99,8 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, return nil, err } assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc) + + err = coredocument.CalculateSigningRoot(corDoc, dataRoot) if err != nil { return nil, err } @@ -142,7 +143,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Invoice, error) { i.GrossAmount = 50 - err := i.CalculateDataRoot() + dataRoot, err := i.CalculateDataRoot() if err != nil { return nil, err } @@ -157,7 +158,7 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv if err != nil { return nil, err } - err = coredocument.CalculateSigningRoot(corDoc) + err = coredocument.CalculateSigningRoot(corDoc, dataRoot) if err != nil { return nil, err } diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 5e99f08d8..08c8d2141 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -353,13 +353,12 @@ func (i *Invoice) Type() reflect.Type { } // CalculateDataRoot calculates the data root and sets the root to core document -func (i *Invoice) CalculateDataRoot() error { +func (i *Invoice) CalculateDataRoot() ([]byte, error) { t, err := i.getDocumentDataTree() if err != nil { - return errors.New("calculateDataRoot error %v", err) + return nil, errors.New("calculateDataRoot error %v", err) } - i.CoreDocument.DataRoot = t.RootHash() - return nil + return t.RootHash(), nil } // getDocumentDataTree creates precise-proofs data tree for the model diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index a6340b2af..563378947 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -263,11 +263,10 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { assert.Nil(t, err, "Init must pass") assert.Nil(t, m.InvoiceSalts, "salts must be nil") - err = m.CalculateDataRoot() + dr, err := m.CalculateDataRoot() assert.Nil(t, err, "calculate must pass") - assert.NotNil(t, m.CoreDocument, "coredoc must be created") + assert.False(t, utils.IsEmptyByteSlice(dr)) assert.NotNil(t, m.InvoiceSalts, "salts must be created") - assert.NotNil(t, m.CoreDocument.DataRoot, "data root must be filled") } func TestInvoiceModel_createProofs(t *testing.T) { @@ -324,7 +323,7 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, error) { i := &Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2, Currency: "USD", CoreDocument: coredocument.New()} i.CoreDocument.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} - err := i.CalculateDataRoot() + dataRoot, err := i.CalculateDataRoot() if err != nil { return nil, nil, err } @@ -334,7 +333,7 @@ func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, er return nil, nil, err } assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc) + err = coredocument.CalculateSigningRoot(corDoc, dataRoot) if err != nil { return nil, nil, err } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 592d054d1..c41e1ce99 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -88,8 +88,8 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv return invoiceModel, nil } -// calculateDataRoot validates the document, calculates the data root, and persists to DB -func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { +// validateAndPersist validates the document, calculates the data root, and persists to DB +func (s service) validateAndPersist(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { self, err := contextutil.Self(ctx) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) @@ -100,12 +100,6 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } - // create data root, has to be done at the model level to access fields - err = inv.CalculateDataRoot() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - // validate the invoice err = validator.Validate(old, inv) if err != nil { @@ -128,7 +122,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - inv, err = s.calculateDataRoot(ctx, nil, inv, CreateValidator()) + inv, err = s.validateAndPersist(ctx, nil, inv, CreateValidator()) if err != nil { return nil, uuid.Nil, nil, err } @@ -163,7 +157,7 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - inv, err = s.calculateDataRoot(ctx, old, inv, UpdateValidator()) + inv, err = s.validateAndPersist(ctx, old, inv, UpdateValidator()) if err != nil { return nil, uuid.Nil, nil, err } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index f8743f13d..e4ee3d4bc 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -441,7 +441,7 @@ func TestService_calculateDataRoot(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) // type mismatch - inv, err := invSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) + inv, err := invSrv.validateAndPersist(ctxh, nil, &testingdocuments.MockModel{}, nil) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -453,7 +453,7 @@ func TestService_calculateDataRoot(t *testing.T) { v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) - inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, v) + inv, err = invSrv.validateAndPersist(ctxh, nil, inv, v) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "validations fail") @@ -464,7 +464,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) err = invSrv.repo.Create(accountID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) assert.Nil(t, err) - inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, CreateValidator()) + inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "db repository could not create the given model, key already exists") @@ -473,10 +473,9 @@ func TestService_calculateDataRoot(t *testing.T) { inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - inv, err = invSrv.calculateDataRoot(ctxh, nil, inv, CreateValidator()) + inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, inv) - assert.NotNil(t, inv.(*Invoice).CoreDocument.DataRoot) } var testRepoGlobal documents.Repository diff --git a/documents/invoice/validator.go b/documents/invoice/validator.go index 685f04633..05e91a0f8 100644 --- a/documents/invoice/validator.go +++ b/documents/invoice/validator.go @@ -3,7 +3,6 @@ package invoice import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/utils" ) // fieldValidateFunc validates the fields of the invoice model @@ -27,50 +26,10 @@ func fieldValidator() documents.Validator { }) } -// dataRootValidator calculates the data root and checks if it matches with the one on core document -func dataRootValidator() documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) (err error) { - defer func() { - if err != nil { - err = errors.New("data root validation failed: %v", err) - } - }() - - if model == nil { - return errors.New("nil document") - } - - coreDoc, err := model.PackCoreDocument() - if err != nil { - return errors.New("failed to pack coredocument: %v", err) - } - - if utils.IsEmptyByteSlice(coreDoc.DataRoot) { - return errors.New("data root missing") - } - - inv, ok := model.(*Invoice) - if !ok { - return errors.New("unknown document type: %T", model) - } - - if err = inv.CalculateDataRoot(); err != nil { - return errors.New("failed to calculate data root: %v", err) - } - - if !utils.IsSameByteSlice(inv.CoreDocument.DataRoot, coreDoc.DataRoot) { - return errors.New("mismatched data root") - } - - return nil - }) -} - // CreateValidator returns a validator group that should be run before creating the invoice and persisting it to DB func CreateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), - dataRootValidator(), } } @@ -78,7 +37,6 @@ func CreateValidator() documents.ValidatorGroup { func UpdateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), - dataRootValidator(), documents.UpdateVersionValidator(), } } diff --git a/documents/invoice/validator_test.go b/documents/invoice/validator_test.go index f2ad3bfd1..a1e4856a6 100644 --- a/documents/invoice/validator_test.go +++ b/documents/invoice/validator_test.go @@ -5,14 +5,7 @@ package invoice import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -47,66 +40,12 @@ func TestFieldValidator_Validate(t *testing.T) { assert.Nil(t, err) } -func TestDataRootValidation_Validate(t *testing.T) { - drv := dataRootValidator() - - // nil error - err := drv.Validate(nil, nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "nil document") - - // pack coredoc failed - model := &mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack coredocument") - - // missing data root - model = &mockModel{} - model.On("PackCoreDocument").Return(coredocument.New(), nil).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "data root missing") - - // unknown doc type - cd := coredocument.New() - cd.DataRoot = utils.RandomSlice(32) - model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "unknown document type") - - // mismatch - id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) - inv := new(Invoice) - err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) - assert.Nil(t, err) - inv.CoreDocument = cd - err = drv.Validate(nil, inv) - assert.Error(t, err) - assert.Contains(t, err.Error(), "mismatched data root") - - // success - inv = new(Invoice) - err = inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) - assert.Nil(t, err) - err = inv.CalculateDataRoot() - assert.Nil(t, err) - err = drv.Validate(nil, inv) - assert.Nil(t, err) -} - func TestCreateValidator(t *testing.T) { cv := CreateValidator() - assert.Len(t, cv, 2) + assert.Len(t, cv, 1) } func TestUpdateValidator(t *testing.T) { uv := UpdateValidator() - assert.Len(t, uv, 3) + assert.Len(t, uv, 2) } diff --git a/documents/model.go b/documents/model.go index dd5efcdd8..668262dba 100644 --- a/documents/model.go +++ b/documents/model.go @@ -28,6 +28,9 @@ type Model interface { // assumes that core document has valid identifiers set UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error + // CalculateDataRoot calculates the dataroot of precise-proofs tree of the model + CalculateDataRoot() ([]byte, error) + // CreateProofs creates precise-proofs for given fields CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) } diff --git a/documents/processor.go b/documents/processor.go index 9b51e7259..118a0f11e 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -75,8 +75,13 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, mode return errors.New("failed to pack core document: %v", err) } + dataRoot, err := model.CalculateDataRoot() + if err != nil { + return err + } + // calculate the signing root - err = coredocument.CalculateSigningRoot(cd) + err = coredocument.CalculateSigningRoot(cd, dataRoot) if err != nil { return errors.New("failed to calculate signing root: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index 343a6879f..1a4807867 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -43,6 +43,11 @@ func (m mockModel) UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error { return args.Error(0) } +func (m mockModel) CalculateDataRoot() ([]byte, error) { + args := m.Called() + return args.Get(0).([]byte), args.Error(1) +} + func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) @@ -77,6 +82,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unpack the core document") @@ -87,6 +93,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Nil(t, err) @@ -139,6 +146,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) assert.Nil(t, err) model.AssertExpectations(t) @@ -147,6 +155,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { dp.p2pClient = c model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) @@ -160,6 +169,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) @@ -173,6 +183,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) @@ -207,11 +218,13 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { Value: []byte("some data"), } assert.Nil(t, coredocument.FillSalts(cd)) - err = coredocument.CalculateSigningRoot(cd) + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + err = coredocument.CalculateSigningRoot(cd, cd.DataRoot) assert.Nil(t, err) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) @@ -229,6 +242,7 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(4) model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) srv.AssertExpectations(t) @@ -283,9 +297,10 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { Value: []byte("some data"), } assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd)) + assert.Nil(t, coredocument.CalculateSigningRoot(cd, cd.DataRoot)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) @@ -302,6 +317,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // success model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(5) + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() repo := mockRepo{} @@ -346,14 +362,16 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { Value: []byte("some data"), } cd.Collaborators = [][]byte{[]byte("some id")} + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd)) + assert.Nil(t, coredocument.CalculateSigningRoot(cd, cd.DataRoot)) model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Times(6) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) assert.Nil(t, err) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 7a0a1c7e8..5210cfab8 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -339,14 +339,13 @@ func (p *PurchaseOrder) Type() reflect.Type { return reflect.TypeOf(p) } -// calculateDataRoot calculates the data root and sets the root to core document -func (p *PurchaseOrder) calculateDataRoot() error { +// CalculateDataRoot calculates the data root and sets the root to core document +func (p *PurchaseOrder) CalculateDataRoot() ([]byte, error) { t, err := p.getDocumentDataTree() if err != nil { - return errors.New("calculateDataRoot error %v", err) + return nil, errors.New("calculateDataRoot error %v", err) } - p.CoreDocument.DataRoot = t.RootHash() - return nil + return t.RootHash(), nil } // getDocumentDataTree creates precise-proofs data tree for the model diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index f74dbff7d..8d015e4ce 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -243,11 +243,10 @@ func TestPOModel_calculateDataRoot(t *testing.T) { assert.Nil(t, err, "Init must pass") assert.Nil(t, poModel.PurchaseOrderSalt, "salts must be nil") - err = poModel.calculateDataRoot() + dr, err := poModel.CalculateDataRoot() assert.Nil(t, err, "calculate must pass") - assert.NotNil(t, poModel.CoreDocument, "coredoc must be created") + assert.False(t, utils.IsEmptyByteSlice(dr)) assert.NotNil(t, poModel.PurchaseOrderSalt, "salts must be created") - assert.NotNil(t, poModel.CoreDocument.DataRoot, "data root must be filled") } func TestPOModel_createProofs(t *testing.T) { poModel, corDoc, err := createMockPurchaseOrder(t) @@ -296,7 +295,7 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, *coredocumentpb.CoreDocument, error) { poModel := &PurchaseOrder{PoNumber: "3213121", NetAmount: 2, OrderAmount: 2, Currency: "USD", CoreDocument: coredocument.New()} poModel.CoreDocument.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} - err := poModel.calculateDataRoot() + dataRoot, err := poModel.CalculateDataRoot() if err != nil { return nil, nil, err } @@ -306,7 +305,7 @@ func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, *coredocumentpb.Core return nil, nil, err } assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc) + err = coredocument.CalculateSigningRoot(corDoc, dataRoot) if err != nil { return nil, nil, err } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 650710cc9..8096af99a 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -68,8 +68,8 @@ func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (docume return model, nil } -// calculateDataRoot validates the document, calculates the data root, and persists to DB -func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { +// validateAndPersist validates the document, and persists to DB +func (s service) validateAndPersist(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { self, err := contextutil.Self(ctx) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) @@ -80,12 +80,6 @@ func (s service) calculateDataRoot(ctx context.Context, old, new documents.Model return nil, errors.NewTypedError(documents.ErrDocumentInvalidType, errors.New("unknown document type: %T", new)) } - // create data root, has to be done at the model level to access fields - err = po.calculateDataRoot() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) - } - // validate the invoice err = validator.Validate(old, po) if err != nil { @@ -108,7 +102,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - po, err = s.calculateDataRoot(ctx, nil, po, CreateValidator()) + po, err = s.validateAndPersist(ctx, nil, po, CreateValidator()) if err != nil { return nil, uuid.Nil, nil, err } @@ -143,7 +137,7 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - po, err = s.calculateDataRoot(ctx, old, po, UpdateValidator()) + po, err = s.validateAndPersist(ctx, old, po, UpdateValidator()) if err != nil { return nil, uuid.Nil, nil, err } diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 95d55d286..87c551f8a 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -485,7 +485,7 @@ func TestService_calculateDataRoot(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) // type mismatch - po, err := poSrv.calculateDataRoot(ctxh, nil, &testingdocuments.MockModel{}, nil) + po, err := poSrv.validateAndPersist(ctxh, nil, &testingdocuments.MockModel{}, nil) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -493,11 +493,10 @@ func TestService_calculateDataRoot(t *testing.T) { // failed validator po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) - po, err = poSrv.calculateDataRoot(ctxh, nil, po, v) + po, err = poSrv.validateAndPersist(ctxh, nil, po, v) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), "validations fail") @@ -508,7 +507,7 @@ func TestService_calculateDataRoot(t *testing.T) { assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) err = poSrv.repo.Create(accountID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) assert.Nil(t, err) - po, err = poSrv.calculateDataRoot(ctxh, nil, po, CreateValidator()) + po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, po) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists) @@ -517,10 +516,9 @@ func TestService_calculateDataRoot(t *testing.T) { po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - po, err = poSrv.calculateDataRoot(ctxh, nil, po, CreateValidator()) + po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, po) - assert.NotNil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) } var testRepoGlobal documents.Repository diff --git a/documents/purchaseorder/validator.go b/documents/purchaseorder/validator.go index e821e1014..24ad1a419 100644 --- a/documents/purchaseorder/validator.go +++ b/documents/purchaseorder/validator.go @@ -3,7 +3,6 @@ package purchaseorder import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/utils" ) // fieldValidateFunc validates the fields of the purchase order model @@ -27,50 +26,10 @@ func fieldValidator() documents.Validator { }) } -// dataRootValidator calculates the data root and checks if it matches with the one on core document -func dataRootValidator() documents.Validator { - return documents.ValidatorFunc(func(_, model documents.Model) (err error) { - defer func() { - if err != nil { - err = errors.New("data root validation failed: %v", err) - } - }() - - if model == nil { - return errors.New("nil document") - } - - coreDoc, err := model.PackCoreDocument() - if err != nil { - return errors.New("failed to pack coredocument: %v", err) - } - - if utils.IsEmptyByteSlice(coreDoc.DataRoot) { - return errors.New("data root missing") - } - - inv, ok := model.(*PurchaseOrder) - if !ok { - return errors.New("unknown document type: %T", model) - } - - if err = inv.calculateDataRoot(); err != nil { - return errors.New("failed to calculate data root: %v", err) - } - - if !utils.IsSameByteSlice(inv.CoreDocument.DataRoot, coreDoc.DataRoot) { - return errors.New("mismatched data root") - } - - return nil - }) -} - // CreateValidator returns a validator group that should be run before creating the purchase order and persisting it to DB func CreateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), - dataRootValidator(), } } @@ -78,7 +37,6 @@ func CreateValidator() documents.ValidatorGroup { func UpdateValidator() documents.ValidatorGroup { return documents.ValidatorGroup{ fieldValidator(), - dataRootValidator(), documents.UpdateVersionValidator(), } } diff --git a/documents/purchaseorder/validator_test.go b/documents/purchaseorder/validator_test.go index 6be70286e..c62c32aea 100644 --- a/documents/purchaseorder/validator_test.go +++ b/documents/purchaseorder/validator_test.go @@ -5,14 +5,8 @@ package purchaseorder import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -47,67 +41,12 @@ func TestFieldValidator_Validate(t *testing.T) { assert.Nil(t, err) } -func TestDataRootValidation_Validate(t *testing.T) { - drv := dataRootValidator() - contextHeader := testingconfig.CreateAccountContext(t, cfg) - - // nil error - err := drv.Validate(nil, nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "nil document") - - // pack coredoc failed - model := &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack coredocument") - - // missing data root - model = &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(coredocument.New(), nil).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "data root missing") - - // unknown doc type - cd := coredocument.New() - cd.DataRoot = utils.RandomSlice(32) - model = &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = drv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "unknown document type") - - // mismatch - id, _ := contextutil.Self(contextHeader) - po := new(PurchaseOrder) - err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) - assert.Nil(t, err) - po.CoreDocument = cd - err = drv.Validate(nil, po) - assert.Error(t, err) - assert.Contains(t, err.Error(), "mismatched data root") - - // success - po = new(PurchaseOrder) - err = po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) - assert.Nil(t, err) - err = po.calculateDataRoot() - assert.Nil(t, err) - err = drv.Validate(nil, po) - assert.Nil(t, err) -} - func TestCreateValidator(t *testing.T) { cv := CreateValidator() - assert.Len(t, cv, 2) + assert.Len(t, cv, 1) } func TestUpdateValidator(t *testing.T) { uv := UpdateValidator() - assert.Len(t, uv, 3) + assert.Len(t, uv, 2) } diff --git a/documents/validator.go b/documents/validator.go index e01c1013d..a76a542b1 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -152,10 +152,6 @@ func baseValidator() Validator { err = errors.AppendError(err, NewError("cd_next_version", centerrors.RequiredField)) } - if utils.IsEmptyByteSlice(cd.DataRoot) { - err = errors.AppendError(err, NewError("cd_data_root", centerrors.RequiredField)) - } - // double check the identifiers isSameBytes := utils.IsSameByteSlice @@ -194,7 +190,12 @@ func signingRootValidator() Validator { return errors.New("signing root missing") } - tree, err := coredocument.GetDocumentSigningTree(cd) + dataRoot, err := model.CalculateDataRoot() + if err != nil { + return err + } + + tree, err := coredocument.GetDocumentSigningTree(cd, dataRoot) if err != nil { return errors.New("failed to calculate signing root: %v", err) } diff --git a/documents/validator_test.go b/documents/validator_test.go index 69d6d0f88..db6c16901 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -215,7 +215,7 @@ func TestValidator_baseValidator(t *testing.T) { model.On("PackCoreDocument").Return(cd, nil).Once() err = bv.Validate(nil, model) assert.Error(t, err) - assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[1].Error()) + assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[0].Error()) // success model = mockModel{} @@ -254,17 +254,19 @@ func TestValidator_signingRootValidator(t *testing.T) { } model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = sv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "signing root mismatch") // success - tree, err := coredocument.GetDocumentSigningTree(cd) + tree, err := coredocument.GetDocumentSigningTree(cd, cd.DataRoot) assert.Nil(t, err) cd.SigningRoot = tree.RootHash() model = mockModel{} model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = sv.Validate(nil, model) model.AssertExpectations(t) assert.Nil(t, err) @@ -511,52 +513,15 @@ func TestValidate_baseValidator(t *testing.T) { DocumentIdentifier: id2, CurrentVersion: id3, NextVersion: id4, - DataRoot: id5, CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ DocumentIdentifier: id1, CurrentVersion: id2, NextVersion: id3, - DataRoot: id4, }, }, key: "[cd_salts : Required field]", }, - // missing identifiers in core document - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - PreviousRoot: id5, - }, - }, - key: "[cd_data_root : Required field]", - }, - - // missing identifiers in core document and salts - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - DataRoot: id4, - }, - }, - key: "[cd_data_root : Required field; cd_salts : Required field]", - }, - // repeated identifiers { doc: &coredocumentpb.CoreDocument{ @@ -569,7 +534,6 @@ func TestValidate_baseValidator(t *testing.T) { DocumentIdentifier: id1, CurrentVersion: id2, NextVersion: id3, - DataRoot: id4, PreviousRoot: id5, }, }, @@ -588,7 +552,6 @@ func TestValidate_baseValidator(t *testing.T) { DocumentIdentifier: id1, CurrentVersion: id2, NextVersion: id3, - DataRoot: id4, PreviousRoot: id5, }, }, @@ -607,7 +570,6 @@ func TestValidate_baseValidator(t *testing.T) { DocumentIdentifier: id1, CurrentVersion: id2, NextVersion: id3, - DataRoot: id4, PreviousRoot: id5, }, }, @@ -617,7 +579,6 @@ func TestValidate_baseValidator(t *testing.T) { baseValidator := baseValidator() for _, c := range tests { - model := mockModel{} model.On("PackCoreDocument", mock.Anything).Return(c.doc, nil).Once() diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index a3a500958..8f4052cf4 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -7,6 +7,9 @@ import ( "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -26,10 +29,11 @@ import ( ) var ( - client documents.Client - cfg config.Configuration - idService identity.Service - cfgStore config.Service + client documents.Client + cfg config.Configuration + idService identity.Service + cfgStore config.Service + docService documents.Service ) func TestMain(m *testing.M) { @@ -39,6 +43,7 @@ func TestMain(m *testing.M) { cfgStore = ctx[config.BootstrappedConfigStorage].(config.Service) idService = ctx[identity.BootstrappedIDService].(identity.Service) client = ctx[bootstrap.BootstrappedPeer].(documents.Client) + docService = ctx[documents.BootstrappedDocumentService].(documents.Service) testingidentity.CreateIdentityWithKeys(cfg, idService) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() @@ -94,24 +99,44 @@ func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *coredoc idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) identifier := utils.RandomSlice(32) + + dataSalts := &invoicepb.InvoiceDataSalts{} + invData := &invoicepb.InvoiceData{} + err = proofs.FillSalts(invData, dataSalts) + assert.Nil(t, err) + + serializedInv, err := proto.Marshal(invData) + assert.Nil(t, err) + serializedInvSalts, err := proto.Marshal(dataSalts) + assert.Nil(t, err) + salts := &coredocumentpb.CoreDocumentSalts{} doc := &coredocumentpb.CoreDocument{ Collaborators: collaborators, - DataRoot: utils.RandomSlice(32), DocumentIdentifier: identifier, CurrentVersion: identifier, NextVersion: utils.RandomSlice(32), CoredocumentSalts: salts, EmbeddedData: &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: serializedInv, }, EmbeddedDataSalts: &any.Any{ TypeUrl: documenttypes.InvoiceSaltsTypeUrl, + Value: serializedInvSalts, }, } + err = proofs.FillSalts(doc, salts) assert.Nil(t, err) - tree, _ := coredocument.GetDocumentSigningTree(doc) + + m, err := docService.DeriveFromCoreDocument(doc) + assert.Nil(t, err) + + droot, err := m.CalculateDataRoot() + assert.Nil(t, err) + + tree, _ := coredocument.GetDocumentSigningTree(doc, droot) doc.SigningRoot = tree.RootHash() sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 0ac3c3e74..a7ae303cc 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -42,6 +44,7 @@ var ( cfg config.Configuration idService identity.Service cfgService config.Service + docSrv documents.Service ) func TestMain(m *testing.M) { @@ -49,7 +52,7 @@ func TestMain(m *testing.M) { ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService = ctx[config.BootstrappedConfigStorage].(config.Service) - docSrv := ctx[documents.BootstrappedDocumentService].(documents.Service) + docSrv = ctx[documents.BootstrappedDocumentService].(documents.Service) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedIDService].(identity.Service) handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) @@ -325,7 +328,14 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument if doc == nil { doc = testingcoredocument.GenerateCoreDocument() } - tree, err := coredocument.GetDocumentSigningTree(doc) + + m, err := docSrv.DeriveFromCoreDocument(doc) + assert.Nil(t, err) + + droot, err := m.CalculateDataRoot() + assert.Nil(t, err) + + tree, err := coredocument.GetDocumentSigningTree(doc, droot) assert.NoError(t, err) doc.SigningRoot = tree.RootHash() sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) @@ -337,16 +347,26 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument } func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) { + dataSalts := &invoicepb.InvoiceDataSalts{} + invData := &invoicepb.InvoiceData{} + proofs.FillSalts(invData, dataSalts) + + serializedInv, err := proto.Marshal(invData) + assert.NoError(t, err) + serializedInvSalts, err := proto.Marshal(dataSalts) + assert.NoError(t, err) + salts := &coredocumentpb.CoreDocumentSalts{} doc.CoredocumentSalts = salts - doc.DataRoot = utils.RandomSlice(32) doc.EmbeddedData = &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: serializedInv, } doc.EmbeddedDataSalts = &any.Any{ TypeUrl: documenttypes.InvoiceSaltsTypeUrl, + Value: serializedInvSalts, } - err := proofs.FillSalts(doc, salts) + err = proofs.FillSalts(doc, salts) assert.Nil(t, err) } diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index b8a5a6989..6f7ea1f94 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -5,6 +5,8 @@ package testingcoredocument import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/golang/protobuf/proto" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -13,18 +15,25 @@ import ( func GenerateCoreDocument() *coredocumentpb.CoreDocument { identifier := utils.RandomSlice(32) + dataSalts := &invoicepb.InvoiceDataSalts{} + invData := &invoicepb.InvoiceData{} + proofs.FillSalts(invData, dataSalts) + + serializedInv, _ := proto.Marshal(invData) + serializedInvSalts, _ := proto.Marshal(dataSalts) salts := &coredocumentpb.CoreDocumentSalts{} doc := &coredocumentpb.CoreDocument{ - DataRoot: utils.RandomSlice(32), DocumentIdentifier: identifier, CurrentVersion: identifier, NextVersion: utils.RandomSlice(32), CoredocumentSalts: salts, EmbeddedData: &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: serializedInv, }, EmbeddedDataSalts: &any.Any{ TypeUrl: documenttypes.InvoiceSaltsTypeUrl, + Value: serializedInvSalts, }, } proofs.FillSalts(doc, salts) From f8f2dd2f2987435dc4fa338c48d3d1cef161506e Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 7 Feb 2019 14:38:44 +0100 Subject: [PATCH 178/220] identity: added context to add key and execute method (#728) * added testworld tests for proofs * bind identity service to did * removed identity init from bootstrapper * added account context to create identity * added waitingTransaction task * create identity uses task manager * refactored add key and execute tests * correct usage of done flag * added context to identity methods * formatting * fixed add key testcase * fixed correct reset of identityID * refactored identity to service --- identity/did/execute_integration_test.go | 25 +++++-- .../did/{service.go => factory_service.go} | 0 identity/did/identity.go | 71 +++++++++++++------ identity/did/identity_integration_test.go | 35 +++++---- 4 files changed, 91 insertions(+), 40 deletions(-) rename identity/did/{service.go => factory_service.go} (100%) diff --git a/identity/did/execute_integration_test.go b/identity/did/execute_integration_test.go index ea4748ca8..fc8916695 100644 --- a/identity/did/execute_integration_test.go +++ b/identity/did/execute_integration_test.go @@ -25,9 +25,15 @@ import ( "github.com/stretchr/testify/assert" ) +// TODO will be removed after migration +func resetDefaultCentID() { + cfg.Set("identityId", "0x010101010101") +} + func TestExecute_successful(t *testing.T) { did := deployIdentityContract(t) - idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) anchorAddress := getAnchorAddress() // init params @@ -36,19 +42,21 @@ func TestExecute_successful(t *testing.T) { testRootHash, _ := anchors.ToDocumentRoot(rootHash) proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) assert.Nil(t, err, "Execute method calls should be successful") txStatus := <-watchTrans assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transaction should be successful") checkAnchor(t, testAnchorId, rootHash) - + resetDefaultCentID() } func TestExecute_fail_falseMethodName(t *testing.T) { did := deployIdentityContract(t) - idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) + aCtx := getTestDIDContext(t, *did) + + idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) @@ -57,23 +65,26 @@ func TestExecute_fail_falseMethodName(t *testing.T) { proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) + watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) assert.Error(t, err, "should throw an error because method is not existing in abi") assert.Nil(t, watchTrans, "no channel should be returned") + resetDefaultCentID() } func TestExecute_fail_MissingParam(t *testing.T) { did := deployIdentityContract(t) - idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) - watchTrans, err := idSrv.Execute(anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) + watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) assert.Error(t, err, "should throw an error because method is not existing in abi") assert.Nil(t, watchTrans, "no channel should be returned") + resetDefaultCentID() } func checkAnchor(t *testing.T, anchorId anchors.AnchorID, expectedRootHash []byte) { diff --git a/identity/did/service.go b/identity/did/factory_service.go similarity index 100% rename from identity/did/service.go rename to identity/did/factory_service.go diff --git a/identity/did/identity.go b/identity/did/identity.go index b3e338b19..d8b62348d 100644 --- a/identity/did/identity.go +++ b/identity/did/identity.go @@ -6,11 +6,12 @@ import ( "strings" "time" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - id "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -36,16 +37,16 @@ func NewDIDFromString(address string) DID { // Identity interface contains the methods to interact with the identity contract type Identity interface { // AddKey adds a key to identity contract - AddKey(key Key) (chan *ethereum.WatchTransaction, error) + AddKey(ctx context.Context, key Key) (chan *ethereum.WatchTransaction, error) // GetKey return a key from the identity contract - GetKey(key [32]byte) (*KeyResponse, error) + GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) // RawExecute calls the execute method on the identity contract - RawExecute(to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) + RawExecute(ctx context.Context, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) // Execute creates the abi encoding an calls the execute method on the identity contract - Execute(to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) + Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) } type contract interface { @@ -64,13 +65,16 @@ type contract interface { } type identity struct { - config id.Config client ethereum.Client - did *DID } -func (i identity) prepareTransaction(did DID) (contract, *bind.TransactOpts, error) { - opts, err := i.client.GetTxOpts(i.config.GetEthereumDefaultAccountName()) +func (i identity) prepareTransaction(ctx context.Context, did DID) (contract, *bind.TransactOpts, error) { + tc, err := contextutil.Account(ctx) + if err != nil { + return nil, nil, err + } + + opts, err := i.client.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { log.Infof("Failed to get txOpts from Ethereum client: %v", err) return nil, nil, err @@ -108,9 +112,8 @@ func (i identity) bindContract(did DID) (contract, error) { } // NewIdentity creates a instance of an identity -func NewIdentity(config id.Config, client ethereum.Client, did *DID) Identity { - // TODO use DID stored in config file - return identity{config: config, client: client, did: did} +func NewIdentity(client ethereum.Client) Identity { + return identity{client: client} } // TODO: will be replaced with statusTask @@ -129,8 +132,28 @@ func logTxHash(tx *types.Transaction) { log.Infof("Transfer pending: 0x%x\n", tx.Hash()) } -func (i identity) AddKey(key Key) (chan *ethereum.WatchTransaction, error) { - contract, opts, err := i.prepareTransaction(*i.did) +func (i identity) getDID(ctx context.Context) (did DID, err error) { + tc, err := contextutil.Account(ctx) + if err != nil { + return did, err + } + + addressByte, err := tc.GetIdentityID() + if err != nil { + return did, err + } + did = NewDID(common.BytesToAddress(addressByte)) + return did, nil + +} + +func (i identity) AddKey(ctx context.Context, key Key) (chan *ethereum.WatchTransaction, error) { + did, err := i.getDID(ctx) + if err != nil { + return nil, err + } + + contract, opts, err := i.prepareTransaction(ctx, did) if err != nil { return nil, err } @@ -151,8 +174,12 @@ func (i identity) AddKey(key Key) (chan *ethereum.WatchTransaction, error) { } -func (i identity) GetKey(key [32]byte) (*KeyResponse, error) { - contract, opts, _, err := i.prepareCall(*i.did) +func (i identity) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) { + did, err := i.getDID(ctx) + if err != nil { + return nil, err + } + contract, opts, _, err := i.prepareCall(did) if err != nil { return nil, err } @@ -167,8 +194,12 @@ func (i identity) GetKey(key [32]byte) (*KeyResponse, error) { } -func (i identity) RawExecute(to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { - contract, opts, err := i.prepareTransaction(*i.did) +func (i identity) RawExecute(ctx context.Context, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { + did, err := i.getDID(ctx) + if err != nil { + return nil, err + } + contract, opts, err := i.prepareTransaction(ctx, did) if err != nil { return nil, err } @@ -191,7 +222,7 @@ func (i identity) RawExecute(to common.Address, data []byte) (chan *ethereum.Wat } -func (i identity) Execute(to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { +func (i identity) Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { abi, err := abi.JSON(strings.NewReader(contractAbi)) if err != nil { return nil, err @@ -202,5 +233,5 @@ func (i identity) Execute(to common.Address, contractAbi, methodName string, arg if err != nil { return nil, err } - return i.RawExecute(to, data) + return i.RawExecute(ctx, to, data) } diff --git a/identity/did/identity_integration_test.go b/identity/did/identity_integration_test.go index 4da98b006..d2d2ad148 100644 --- a/identity/did/identity_integration_test.go +++ b/identity/did/identity_integration_test.go @@ -5,12 +5,9 @@ package did import ( "context" "testing" - "time" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/ethereum" @@ -21,8 +18,18 @@ func getTestKey() Key { return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} } -func initIdentity(config config.Configuration, client ethereum.Client, did *DID) Identity { - return NewIdentity(config, client, did) +func initIdentity(client ethereum.Client) Identity { + return NewIdentity(client) +} + +func getTestDIDContext(t *testing.T, did DID) context.Context { + cfg.Set("identityId", did.toAddress().String()) + cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") + aCtx := testingconfig.CreateAccountContext(t, cfg) + + return aCtx + } func deployIdentityContract(t *testing.T) *DID { @@ -33,8 +40,6 @@ func deployIdentityContract(t *testing.T) *DID { client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - time.Sleep(2000 * time.Millisecond) - contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") @@ -45,35 +50,39 @@ func deployIdentityContract(t *testing.T) *DID { func TestAddKey_successful(t *testing.T) { did := deployIdentityContract(t) - idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), did) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) testKey := getTestKey() - watchTrans, err := idSrv.AddKey(testKey) + watchTrans, err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") txStatus := <-watchTrans assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions should be successful") - response, err := idSrv.GetKey(testKey.GetKey()) + response, err := idSrv.GetKey(aCtx, testKey.GetKey()) assert.Nil(t, err, "get Key should be successful") assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") + resetDefaultCentID() } func TestAddKey_fail(t *testing.T) { testKey := getTestKey() did := NewDIDFromString("0x123") - idSrv := initIdentity(cfg, ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client), &did) + aCtx := getTestDIDContext(t, did) + idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) - watchTrans, err := idSrv.AddKey(testKey) + watchTrans, err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") txStatus := <-watchTrans // contract is not existing but status is successful assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions") - _, err = idSrv.GetKey(testKey.GetKey()) + _, err = idSrv.GetKey(aCtx, testKey.GetKey()) assert.Error(t, err, "no contract code at given address") + resetDefaultCentID() } From bb0c883d45fe92f443398f5b1e5248b197bd6575 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 7 Feb 2019 19:46:37 +0100 Subject: [PATCH 179/220] identity: execute method and add key using txManager (#729) * added testworld tests for proofs * bind identity service to did * removed identity init from bootstrapper * added account context to create identity * added waitingTransaction task * create identity uses task manager * refactored add key and execute tests * correct usage of done flag * added context to identity methods * formatting * fixed add key testcase * add key uses txManager * using tx manager for exceute methods * removed old wait for tx helper method * fixed correct reset of identityID * refactored identity to service * refactored service to factory * refactored identity to service * removed config from factory * small formatting issues --- identity/did/bootstrapper.go | 15 +- identity/did/execute_integration_test.go | 65 ++++++-- .../did/{factory_service.go => factory.go} | 23 ++- identity/did/factory_integration_test.go | 62 +++++++ identity/did/identity_integration_test.go | 88 ---------- identity/did/{identity.go => service.go} | 154 +++++++++++------- identity/did/service_integration_test.go | 95 +++++++---- 7 files changed, 286 insertions(+), 216 deletions(-) rename identity/did/{factory_service.go => factory.go} (83%) create mode 100644 identity/did/factory_integration_test.go delete mode 100644 identity/did/identity_integration_test.go rename identity/did/{identity.go => service.go} (50%) diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index 6ff8a0d70..d12203cd2 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/ethereum/go-ethereum/common" @@ -21,6 +20,9 @@ import ( // Bootstrapper implements bootstrap.Bootstrapper. type Bootstrapper struct{} +// BootstrappedDIDFactory stores the id of the factory +const BootstrappedDIDFactory string = "BootstrappedDIDFactory" + // BootstrappedDIDService stores the id of the service const BootstrappedDIDService string = "BootstrappedDIDService" @@ -28,11 +30,6 @@ var smartContractAddresses *config.SmartContractAddresses // Bootstrap initializes the factory contract func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - cfg, err := configstore.RetrieveConfig(false, context) - if err != nil { - return err - } - if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { return errors.New("ethereum client hasn't been initialized") } @@ -56,8 +53,12 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { return errors.New("queue hasn't been initialized") } - service := NewService(cfg, factoryContract, client, txManager, queueSrv) + factory := NewFactory(factoryContract, client, txManager, queueSrv) + context[BootstrappedDIDFactory] = factory + + service := NewService(client, txManager, queueSrv) context[BootstrappedDIDService] = service + return nil } diff --git a/identity/did/execute_integration_test.go b/identity/did/execute_integration_test.go index fc8916695..3b7297755 100644 --- a/identity/did/execute_integration_test.go +++ b/identity/did/execute_integration_test.go @@ -16,12 +16,18 @@ correct implementation. package did import ( + "context" "testing" "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" + id "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -33,7 +39,7 @@ func resetDefaultCentID() { func TestExecute_successful(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) - idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) + idSrv := initIdentity() anchorAddress := getAnchorAddress() // init params @@ -42,12 +48,9 @@ func TestExecute_successful(t *testing.T) { testRootHash, _ := anchors.ToDocumentRoot(rootHash) proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) assert.Nil(t, err, "Execute method calls should be successful") - txStatus := <-watchTrans - assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transaction should be successful") - checkAnchor(t, testAnchorId, rootHash) resetDefaultCentID() } @@ -56,7 +59,7 @@ func TestExecute_fail_falseMethodName(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) - idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) + idSrv := initIdentity() anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) @@ -65,25 +68,24 @@ func TestExecute_fail_falseMethodName(t *testing.T) { proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) + err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "fakeMethod", testAnchorId.BigInt(), testRootHash, proofs) assert.Error(t, err, "should throw an error because method is not existing in abi") - assert.Nil(t, watchTrans, "no channel should be returned") + resetDefaultCentID() } func TestExecute_fail_MissingParam(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) - idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) + idSrv := initIdentity() anchorAddress := getAnchorAddress() testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) - watchTrans, err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) + err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash) assert.Error(t, err, "should throw an error because method is not existing in abi") - assert.Nil(t, watchTrans, "no channel should be returned") resetDefaultCentID() } @@ -110,8 +112,7 @@ func TestAnchorWithoutExecute_successful(t *testing.T) { testRootHash, _ := anchors.ToDocumentRoot(rootHash) //commit without execute method - txStatus := commitAnchorWithoutExecute(t, anchorContract, testAnchorId, testRootHash) - assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transaction should be successful") + commitAnchorWithoutExecute(t, anchorContract, testAnchorId, testRootHash) opts, _ := client.GetGethCallOpts(false) result, err := anchorContract.GetAnchorById(opts, testAnchorId.BigInt()) @@ -127,13 +128,41 @@ func commitAnchorWithoutExecute(t *testing.T, anchorContract *anchors.AnchorCont proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} opts, err := client.GetTxOpts(cfg.GetEthereumDefaultAccountName()) - tx, err := client.SubmitTransactionWithRetries(anchorContract.Commit, opts, anchorId.BigInt(), rootHash, proofs) - assert.Nil(t, err, "submit transaction should be successful") + queue := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + txManager := ctx[transactions.BootstrappedService].(transactions.Manager) + + // TODO: did can be passed instead of randomCentID after CentID is DID + _, done, err := txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX add execute", + func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + ethTX, err := client.SubmitTransactionWithRetries(anchorContract.Commit, opts, anchorId.BigInt(), rootHash, proofs) + if err != nil { + errOut <- err + return + } + logTxHash(ethTX) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), queue) + if err != nil { + errOut <- err + return + } + + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } + errOut <- nil + }) + assert.Nil(t, err, "add anchor commit tx should be successful ") + isDone := <-done + // non async task + + assert.True(t, isDone, "add anchor commit tx should be successful ") + + return nil - watchTrans := make(chan *ethereum.WatchTransaction) - go waitForTransaction(client, tx.Hash(), watchTrans) - return <-watchTrans } func bindAnchorContract(t *testing.T, address common.Address) *anchors.AnchorContract { diff --git a/identity/did/factory_service.go b/identity/did/factory.go similarity index 83% rename from identity/did/factory_service.go rename to identity/did/factory.go index ce884f55a..a282ec8f8 100644 --- a/identity/did/factory_service.go +++ b/identity/did/factory.go @@ -20,26 +20,25 @@ import ( var log = logging.Logger("identity") -// Service is the interface for identity related interactions -type Service interface { +// Factory is the interface for factory related interactions +type Factory interface { CreateIdentity(ctx context.Context) (id *DID, err error) } -type service struct { - config id.Config +type factory struct { factoryContract *FactoryContract client ethereum.Client txManager transactions.Manager queue *queue.Server } -// NewService returns a new identity service -func NewService(config id.Config, factoryContract *FactoryContract, client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Service { +// NewFactory returns a new identity factory service +func NewFactory(factoryContract *FactoryContract, client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Factory { - return &service{config: config, factoryContract: factoryContract, client: client, txManager: txManager, queue: queue} + return &factory{factoryContract: factoryContract, client: client, txManager: txManager, queue: queue} } -func (s *service) getNonceAt(ctx context.Context, address common.Address) (uint64, error) { +func (s *factory) getNonceAt(ctx context.Context, address common.Address) (uint64, error) { // TODO: add blockNumber of the transaction which created the contract return s.client.GetEthClient().NonceAt(ctx, getFactoryAddress(), nil) } @@ -51,7 +50,7 @@ func CalculateCreatedAddress(address common.Address, nonce uint64) common.Addres return crypto.CreateAddress(address, nonce) } -func (s *service) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) if err != nil { @@ -79,7 +78,7 @@ func (s *service) createIdentityTX(opts *bind.TransactOpts) func(accountID id.Ce } -func (s *service) calculateIdentityAddress(ctx context.Context) (*common.Address, error) { +func (s *factory) calculateIdentityAddress(ctx context.Context) (*common.Address, error) { factoryAddress := getFactoryAddress() nonce, err := s.getNonceAt(ctx, factoryAddress) if err != nil { @@ -91,7 +90,7 @@ func (s *service) calculateIdentityAddress(ctx context.Context) (*common.Address return &identityAddress, nil } -func (s *service) isIdentityContract(identityAddress common.Address) error { +func (s *factory) isIdentityContract(identityAddress common.Address) error { contractCode, err := s.client.GetEthClient().CodeAt(context.Background(), identityAddress, nil) if err != nil { return err @@ -106,7 +105,7 @@ func (s *service) isIdentityContract(identityAddress common.Address) error { } -func (s *service) CreateIdentity(ctx context.Context) (did *DID, err error) { +func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { tc, err := contextutil.Account(ctx) if err != nil { return nil, err diff --git a/identity/did/factory_integration_test.go b/identity/did/factory_integration_test.go new file mode 100644 index 000000000..b4358403f --- /dev/null +++ b/identity/did/factory_integration_test.go @@ -0,0 +1,62 @@ +// +build integration + +package did + +import ( + "context" + "os" + "testing" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/stretchr/testify/assert" +) + +var cfg config.Configuration +var ctx = map[string]interface{}{} + +func TestMain(m *testing.M) { + var bootstappers = []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + transactions.Bootstrapper{}, + &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, + ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + &Bootstrapper{}, + &queue.Starter{}, + } + + bootstrap.RunTestBootstrappers(bootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(bootstappers) + os.Exit(result) +} + +func TestCreateIdentity_successful(t *testing.T) { + factory := ctx[BootstrappedDIDFactory].(Factory) + + accountCtx := testingconfig.CreateAccountContext(t, cfg) + + did, err := factory.CreateIdentity(accountCtx) + assert.Nil(t, err, "create identity should be successful") + + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) + assert.Nil(t, err, "should be successful to get the contract code") + + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + +} diff --git a/identity/did/identity_integration_test.go b/identity/did/identity_integration_test.go deleted file mode 100644 index d2d2ad148..000000000 --- a/identity/did/identity_integration_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// +build integration - -package did - -import ( - "context" - "testing" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/utils" - - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/stretchr/testify/assert" -) - -func getTestKey() Key { - return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} -} - -func initIdentity(client ethereum.Client) Identity { - return NewIdentity(client) -} - -func getTestDIDContext(t *testing.T, did DID) context.Context { - cfg.Set("identityId", did.toAddress().String()) - cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - aCtx := testingconfig.CreateAccountContext(t, cfg) - - return aCtx - -} - -func deployIdentityContract(t *testing.T) *DID { - service := ctx[BootstrappedDIDService].(Service) - accountCtx := testingconfig.CreateAccountContext(t, cfg) - did, err := service.CreateIdentity(accountCtx) - assert.Nil(t, err, "create identity should be successful") - - client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - - contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) - assert.Nil(t, err, "should be successful to get the contract code") - - assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") - return did - -} - -func TestAddKey_successful(t *testing.T) { - did := deployIdentityContract(t) - aCtx := getTestDIDContext(t, *did) - idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) - - testKey := getTestKey() - - watchTrans, err := idSrv.AddKey(aCtx, testKey) - assert.Nil(t, err, "add key should be successful") - - txStatus := <-watchTrans - assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions should be successful") - - response, err := idSrv.GetKey(aCtx, testKey.GetKey()) - assert.Nil(t, err, "get Key should be successful") - - assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") - resetDefaultCentID() -} - -func TestAddKey_fail(t *testing.T) { - testKey := getTestKey() - did := NewDIDFromString("0x123") - aCtx := getTestDIDContext(t, did) - idSrv := initIdentity(ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client)) - - watchTrans, err := idSrv.AddKey(aCtx, testKey) - assert.Nil(t, err, "add key should be successful") - - txStatus := <-watchTrans - // contract is not existing but status is successful - assert.Equal(t, ethereum.TransactionStatusSuccess, txStatus.Status, "transactions") - - _, err = idSrv.GetKey(aCtx, testKey.GetKey()) - assert.Error(t, err, "no contract code at given address") - resetDefaultCentID() - -} diff --git a/identity/did/identity.go b/identity/did/service.go similarity index 50% rename from identity/did/identity.go rename to identity/did/service.go index d8b62348d..a86055d4c 100644 --- a/identity/did/identity.go +++ b/identity/did/service.go @@ -4,14 +4,16 @@ import ( "context" "math/big" "strings" - "time" "github.com/centrifuge/go-centrifuge/contextutil" - + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/satori/go.uuid" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" + id "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -34,41 +36,43 @@ func NewDIDFromString(address string) DID { return DID(common.HexToAddress(address)) } -// Identity interface contains the methods to interact with the identity contract -type Identity interface { +// Service interface contains the methods to interact with the identity contract +type Service interface { // AddKey adds a key to identity contract - AddKey(ctx context.Context, key Key) (chan *ethereum.WatchTransaction, error) + AddKey(ctx context.Context, key Key) error // GetKey return a key from the identity contract GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) // RawExecute calls the execute method on the identity contract - RawExecute(ctx context.Context, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) + RawExecute(ctx context.Context, to common.Address, data []byte) error // Execute creates the abi encoding an calls the execute method on the identity contract - Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) + Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error } type contract interface { - // calls + // Ethereum Calls GetKey(opts *bind.CallOpts, _key [32]byte) (struct { Key [32]byte Purposes []*big.Int RevokedAt *big.Int }, error) - // transactions + // Ethereum Transactions AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) } -type identity struct { - client ethereum.Client +type service struct { + client ethereum.Client + txManager transactions.Manager + queue *queue.Server } -func (i identity) prepareTransaction(ctx context.Context, did DID) (contract, *bind.TransactOpts, error) { +func (i service) prepareTransaction(ctx context.Context, did DID) (contract, *bind.TransactOpts, error) { tc, err := contextutil.Account(ctx) if err != nil { return nil, nil, err @@ -89,7 +93,7 @@ func (i identity) prepareTransaction(ctx context.Context, did DID) (contract, *b } -func (i identity) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelFunc, error) { +func (i service) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelFunc, error) { opts, cancelFunc := i.client.GetGethCallOpts(false) contract, err := i.bindContract(did) @@ -101,7 +105,7 @@ func (i identity) prepareCall(did DID) (contract, *bind.CallOpts, context.Cancel } -func (i identity) bindContract(did DID) (contract, error) { +func (i service) bindContract(did DID) (contract, error) { contract, err := NewIdentityContract(did.toAddress(), i.client.GetEthClient()) if err != nil { return nil, errors.New("Could not bind identity contract: %v", err) @@ -111,20 +115,9 @@ func (i identity) bindContract(did DID) (contract, error) { } -// NewIdentity creates a instance of an identity -func NewIdentity(client ethereum.Client) Identity { - return identity{client: client} -} - -// TODO: will be replaced with statusTask -func waitForTransaction(client ethereum.Client, txHash common.Hash, txStatus chan *ethereum.WatchTransaction) { - time.Sleep(3000 * time.Millisecond) - receipt, err := client.TransactionReceipt(context.Background(), txHash) - if err != nil { - txStatus <- ðereum.WatchTransaction{Error: err} - } - txStatus <- ðereum.WatchTransaction{Status: receipt.Status} - +// NewService creates a instance of the identity service +func NewService(client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Service { + return service{client: client, txManager: txManager, queue: queue} } func logTxHash(tx *types.Transaction) { @@ -132,7 +125,7 @@ func logTxHash(tx *types.Transaction) { log.Infof("Transfer pending: 0x%x\n", tx.Hash()) } -func (i identity) getDID(ctx context.Context) (did DID, err error) { +func (i service) getDID(ctx context.Context) (did DID, err error) { tc, err := contextutil.Account(ctx) if err != nil { return did, err @@ -147,34 +140,84 @@ func (i identity) getDID(ctx context.Context) (did DID, err error) { } -func (i identity) AddKey(ctx context.Context, key Key) (chan *ethereum.WatchTransaction, error) { +func (i service) AddKey(ctx context.Context, key Key) error { did, err := i.getDID(ctx) if err != nil { - return nil, err + return err } contract, opts, err := i.prepareTransaction(ctx, did) if err != nil { - return nil, err + return err } - tx, err := i.client.SubmitTransactionWithRetries(contract.AddKey, opts, key.GetKey(), key.GetPurpose(), key.GetType()) + // TODO: did can be passed instead of randomCentID after CentID is DID + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add key", i.addKeyTX(opts, contract, key)) if err != nil { - log.Infof("could not addKey to identity contract: %v[txHash: %s] : %v", tx.Hash(), err) - return nil, errors.New("could not addKey to identity contract: %v", err) + return err } - logTxHash(tx) - txStatus := make(chan *ethereum.WatchTransaction) + isDone := <-done + // non async task + if !isDone { + return errors.New("add key TX failed: txID:%s", txID.String()) - // TODO will be replaced with transaction Status task - go waitForTransaction(i.client, tx.Hash(), txStatus) + } + return nil - return txStatus, nil +} + +func (i service) addKeyTX(opts *bind.TransactOpts, identityContract contract, key Key) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + ethTX, err := i.client.SubmitTransactionWithRetries(identityContract.AddKey, opts, key.GetKey(), key.GetPurpose(), key.GetType()) + if err != nil { + errOut <- err + return + } + logTxHash(ethTX) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), i.queue) + if err != nil { + errOut <- err + return + } + + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } + errOut <- nil + } + +} + +func (i service) rawExecuteTX(opts *bind.TransactOpts, identityContract contract, to common.Address, value *big.Int, data []byte) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + ethTX, err := i.client.SubmitTransactionWithRetries(identityContract.Execute, opts, to, value, data) + if err != nil { + errOut <- err + return + } + logTxHash(ethTX) + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), i.queue) + if err != nil { + errOut <- err + return + } + + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } + errOut <- nil + } } -func (i identity) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) { +func (i service) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) { did, err := i.getDID(ctx) if err != nil { return nil, err @@ -194,44 +237,45 @@ func (i identity) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error } -func (i identity) RawExecute(ctx context.Context, to common.Address, data []byte) (chan *ethereum.WatchTransaction, error) { +func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) error { did, err := i.getDID(ctx) if err != nil { - return nil, err + return err } contract, opts, err := i.prepareTransaction(ctx, did) if err != nil { - return nil, err + return err } // default: no ether should be send value := big.NewInt(0) - tx, err := i.client.SubmitTransactionWithRetries(contract.Execute, opts, to, value, data) + // TODO: did can be passed instead of randomCentID after CentID is DID + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for execute", i.rawExecuteTX(opts, contract, to, value, data)) if err != nil { - log.Infof("could not call execute method on identity contract: %v[txHash: %s] toAddress: %s : %v", tx.Hash(), to.String(), err) - return nil, errors.New("could not execute to identity contract: %v", err) + return err } - logTxHash(tx) - txStatus := make(chan *ethereum.WatchTransaction) - // TODO will be replaced with transaction Status task - go waitForTransaction(i.client, tx.Hash(), txStatus) + isDone := <-done + // non async task + if !isDone { + return errors.New("raw execute TX failed: txID:%s", txID.String()) - return txStatus, nil + } + return nil } -func (i identity) Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) (chan *ethereum.WatchTransaction, error) { +func (i service) Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error { abi, err := abi.JSON(strings.NewReader(contractAbi)) if err != nil { - return nil, err + return err } // Pack encodes the parameters and additionally checks if the method and arguments are defined correctly data, err := abi.Pack(methodName, args...) if err != nil { - return nil, err + return err } return i.RawExecute(ctx, to, data) } diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index 4c38994ae..6ea862eb3 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -4,53 +4,45 @@ package did import ( "context" - "fmt" - "os" "testing" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" + + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/go-centrifuge/utils" + + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/stretchr/testify/assert" ) -var cfg config.Configuration -var ctx = map[string]interface{}{} - -func TestMain(m *testing.M) { - var bootstappers = []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, - &queue.Bootstrapper{}, - ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, - &configstore.Bootstrapper{}, - &Bootstrapper{}, - &queue.Starter{}, - } - - bootstrap.RunTestBootstrappers(bootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - result := m.Run() - bootstrap.RunTestTeardown(bootstappers) - os.Exit(result) +func getTestKey() Key { + return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} +} + +func initIdentity() Service { + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + txManager := ctx[transactions.BootstrappedService].(transactions.Manager) + queue := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + return NewService(client, txManager, queue) } -func TestCreateIdentity_successful(t *testing.T) { - service := ctx[BootstrappedDIDService].(Service) +func getTestDIDContext(t *testing.T, did DID) context.Context { + cfg.Set("identityId", did.toAddress().String()) + cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") + aCtx := testingconfig.CreateAccountContext(t, cfg) - accountCtx := testingconfig.CreateAccountContext(t, cfg) + return aCtx + +} - did, err := service.CreateIdentity(accountCtx) +func deployIdentityContract(t *testing.T) *DID { + factory := ctx[BootstrappedDIDFactory].(Factory) + accountCtx := testingconfig.CreateAccountContext(t, cfg) + did, err := factory.CreateIdentity(accountCtx) assert.Nil(t, err, "create identity should be successful") client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) @@ -59,7 +51,38 @@ func TestCreateIdentity_successful(t *testing.T) { assert.Nil(t, err, "should be successful to get the contract code") assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + return did + +} + +func TestAddKey_successful(t *testing.T) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + testKey := getTestKey() + + err := idSrv.AddKey(aCtx, testKey) + assert.Nil(t, err, "add key should be successful") + + response, err := idSrv.GetKey(aCtx, testKey.GetKey()) + assert.Nil(t, err, "get Key should be successful") + + assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") + resetDefaultCentID() +} + +func TestAddKey_fail(t *testing.T) { + testKey := getTestKey() + did := NewDIDFromString("0x123") + aCtx := getTestDIDContext(t, did) + idSrv := initIdentity() + + err := idSrv.AddKey(aCtx, testKey) + assert.Nil(t, err, "add key should be successful") - fmt.Println(did) + _, err = idSrv.GetKey(aCtx, testKey.GetKey()) + assert.Error(t, err, "no contract code at given address") + resetDefaultCentID() } From 503fca7e27c93ca969b67dfadd9907cc03802d34 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Fri, 8 Feb 2019 11:29:28 +0530 Subject: [PATCH 180/220] add nft uniqueness check (#730) * add nft uniqueness check * use ownerOf to checck if NFT is minted --- nft/ethereum_payment_obligation.go | 79 +++++++++++++++++----- nft/ethereum_payment_obligation_test.go | 20 ++++++ nft/payment_obligation_integration_test.go | 24 +++++-- 3 files changed, 98 insertions(+), 25 deletions(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 6beae3948..7b50b8571 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -1,16 +1,15 @@ package nft import ( + "bytes" "context" "math/big" "time" - "github.com/ethereum/go-ethereum/common/hexutil" - - "github.com/centrifuge/go-centrifuge/coredocument" - + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -21,6 +20,7 @@ import ( "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" logging "github.com/ipfs/go-log" "github.com/satori/go.uuid" @@ -28,6 +28,9 @@ import ( var log = logging.Logger("nft") +// ErrNFTMinted error for NFT already minted for registry +const ErrNFTMinted = errors.Error("NFT already minted") + // ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out type ethereumPaymentObligationContract interface { @@ -132,11 +135,27 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by } tokenID := NewTokenID() + model, err := s.docSrv.GetCurrentVersion(ctx, documentID) + if err != nil { + return nil, nil, err + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, nil, err + } + + registry := common.HexToAddress(registryAddress) + mt := getStoredNFT(cd.Nfts, registry.Bytes()) + // check if the nft is successfully minted + if mt != nil && s.isNFTMinted(registry, mt.TokenId) { + return nil, nil, errors.NewTypedError(ErrNFTMinted, errors.New("registry %v", registry.String())) + } + // Mint NFT within transaction // We use context.Background() for now so that the transaction is only limited by ethereum timeouts txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Minting NFT", - s.minter(ctx, tokenID, documentID, registryAddress, depositAddress, proofFields)) - + s.minter(ctx, tokenID, model, registry, depositAddress, proofFields)) if err != nil { return nil, nil, err } @@ -147,7 +166,14 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by }, done, nil } -func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, documentID []byte, registryAddress, depositAddress string, proofFields []string) func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +func (s *ethereumPaymentObligation) isNFTMinted(registry common.Address, tokenID []byte) bool { + // since OwnerOf throws when owner is zero address, + // if err is not thrown, we can assume that NFT is minted + _, err := s.OwnerOf(registry, tokenID) + return err == nil +} + +func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, registry common.Address, depositAddress string, proofFields []string) func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { return func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { tc, err := contextutil.Account(ctx) if err != nil { @@ -155,15 +181,6 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - // registry address - registry := common.HexToAddress(registryAddress) - - model, err := s.docSrv.GetCurrentVersion(ctx, documentID) - if err != nil { - errOut <- err - return - } - cd, err := model.PackCoreDocument() if err != nil { errOut <- err @@ -178,6 +195,7 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, } cd.EmbeddedData = data + addNFT(cd, registry.Bytes(), tokenID[:]) err = coredocument.AddNFTToReadRules(cd, registry, tokenID.BigInt().Bytes()) if err != nil { errOut <- err @@ -199,11 +217,11 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, isDone := <-done if !isDone { // some problem occured in a child task - errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(documentID), txID) + errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(cd.DocumentIdentifier), txID) return } - requestData, err := s.prepareMintRequest(ctx, tokenID, documentID, depositAddress, proofFields) + requestData, err := s.prepareMintRequest(ctx, tokenID, cd.DocumentIdentifier, depositAddress, proofFields) if err != nil { errOut <- errors.New("failed to prepare mint request: %v", err) return @@ -247,6 +265,31 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, } } +func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.NFT { + for _, nft := range nfts { + if bytes.Equal(nft.RegistryId[:20], registry) { + return nft + } + } + + return nil +} + +// addNFT adds/replaces the NFT +// Note: this is replace operation. Ensure existing token is not minted +func addNFT(cd *coredocumentpb.CoreDocument, registry, tokenID []byte) { + nft := getStoredNFT(cd.Nfts, registry) + if nft == nil { + nft = new(coredocumentpb.NFT) + // add 12 empty bytes + eb := make([]byte, 12, 12) + nft.RegistryId = append(registry, eb...) + cd.Nfts = append(cd.Nfts, nft) + } + + nft.TokenId = tokenID +} + // OwnerOf returns the owner of the NFT token on ethereum chain func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []byte) (owner common.Address, err error) { contract, err := s.bindContract(registry, s.ethClient) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 286f49b0c..d2f05d5b9 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -249,3 +249,23 @@ func decodeHex(hex string) []byte { h, _ := hexutil.Decode(hex) return h } + +func Test_addNFT(t *testing.T) { + cd := coredocument.New() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") + tokenID := utils.RandomSlice(32) + assert.Nil(t, cd.Nfts) + + addNFT(cd, registry.Bytes(), tokenID) + assert.Len(t, cd.Nfts, 1) + assert.Len(t, cd.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) + assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) + + tokenID = utils.RandomSlice(32) + addNFT(cd, registry.Bytes(), tokenID) + assert.Len(t, cd.Nfts, 1) + assert.Len(t, cd.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) +} diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index ad7300f36..e2e166416 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -14,6 +14,7 @@ import ( "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -56,10 +57,10 @@ func TestPaymentObligationService_mint(t *testing.T) { // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - contextHeader := testingconfig.CreateAccountContext(t, cfg) + ctx := testingconfig.CreateAccountContext(t, cfg) invoiceService := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) - model, err := invoiceService.DeriveFromCreatePayload(contextHeader, &invoicepb.InvoiceCreatePayload{ + model, err := invoiceService.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ Collaborators: []string{}, Data: &invoicepb.InvoiceData{ InvoiceNumber: "2132131", @@ -70,7 +71,7 @@ func TestPaymentObligationService_mint(t *testing.T) { }, }) assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, txID, _, err := invoiceService.Create(contextHeader, model) + modelUpdated, txID, _, err := invoiceService.Create(ctx, model) err = txManager.WaitForTransaction(cid, txID) assert.Nil(t, err) @@ -82,7 +83,7 @@ func TestPaymentObligationService_mint(t *testing.T) { depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" registry := cfg.GetContractAddress(config.PaymentObligation) resp, done, err := payOb.MintNFT( - contextHeader, + ctx, ID, registry.String(), depositAddr, @@ -97,14 +98,23 @@ func TestPaymentObligationService_mint(t *testing.T) { owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) assert.NoError(t, err) assert.Equal(t, common.HexToAddress(depositAddr), owner) - doc, err := invoiceService.GetCurrentVersion(contextHeader, ID) + doc, err := invoiceService.GetCurrentVersion(ctx, ID) assert.NoError(t, err) cd, err := doc.PackCoreDocument() assert.NoError(t, err) assert.Len(t, cd.Roles, 2) assert.Len(t, cd.Roles[1].Nfts, 1) - nft := cd.Roles[1].Nfts[0] + newNFT := cd.Roles[1].Nfts[0] enft, err := coredocument.ConstructNFT(registry, tokenID.BigInt().Bytes()) assert.NoError(t, err) - assert.Equal(t, enft, nft) + assert.Equal(t, enft, newNFT) + + // try to mint the NFT again + _, _, err = payOb.MintNFT(ctx, + ID, + registry.String(), + depositAddr, + []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}) + assert.Error(t, err) + assert.True(t, errors.IsOfType(nft.ErrNFTMinted, err)) } From e7e6e0f201528fb23da887e8789296f9e1bb1e20 Mon Sep 17 00:00:00 2001 From: Charly Date: Fri, 8 Feb 2019 10:18:06 +0100 Subject: [PATCH 181/220] DocModelRefactor pt. 2 (#731) * added readacls to docmodel * moved all cd methods * add DocRoot --- documents/model.go | 359 +++++++++++++++++++++++++++++++++++- documents/model_test.go | 222 ++++++++++++++++++++++ documents/read_acls.go | 148 --------------- documents/read_acls_test.go | 192 +++++++------------ 4 files changed, 646 insertions(+), 275 deletions(-) delete mode 100644 documents/read_acls.go diff --git a/documents/model.go b/documents/model.go index 668262dba..1ae81f6cf 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,6 +1,11 @@ package documents import ( + "bytes" + "crypto/sha256" + "fmt" + "strings" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -41,6 +46,11 @@ type CoreDocumentModel struct { Document *coredocumentpb.CoreDocument } +const ( + // ErrZeroCollaborators error when no collaborators are passed + ErrZeroCollaborators = errors.Error("require at least one collaborator") +) + // NewCoreDocModel returns a new CoreDocumentModel // Note: collaborators and salts are to be filled by the caller func NewCoreDocModel() *CoreDocumentModel { @@ -79,25 +89,28 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu // copy read rules and roles ncd.Roles = m.Document.Roles ncd.ReadRules = m.Document.ReadRules - addCollaboratorsToReadSignRules(ncd, ucs) - + err = ndm.addCollaboratorsToReadSignRules(ucs) + if err != nil { + return nil, err + } err = ndm.fillSalts() + if err != nil { return nil, err } if ocd.DocumentIdentifier == nil { - return nil, errors.New("coredocument.DocumentIdentifier is nil") + return nil, errors.New("Document.DocumentIdentifier is nil") } ncd.DocumentIdentifier = ocd.DocumentIdentifier if ocd.CurrentVersion == nil { - return nil, errors.New("coredocument.CurrentVersion is nil") + return nil, errors.New("Document.CurrentVersion is nil") } ncd.PreviousVersion = ocd.CurrentVersion if ocd.NextVersion == nil { - return nil, errors.New("coredocument.NextVersion is nil") + return nil, errors.New("Document.NextVersion is nil") } ncd.CurrentVersion = ocd.NextVersion @@ -110,19 +123,353 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu return ndm, nil } +// CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs +func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields []string) (proofs []*proofspb.Proof, err error) { + signingRootProofHashes, err := m.getSigningRootProofHashes() + if err != nil { + return nil, errors.New("createProofs error %v", err) + } + + cdtree, err := m.GetCoreDocTree() + if err != nil { + return nil, errors.New("createProofs error %v", err) + } + + dataRoot := dataTree.RootHash() + cdRoot := cdtree.RootHash() + + // We support fields that belong to different document trees, as we do not prepend a tree prefix to the field, the approach + // is to try in both trees to find the field and create the proof accordingly + for _, field := range fields { + proof, err := dataTree.CreateProof(field) + if err != nil { + if strings.Contains(err.Error(), "No such field") { + proof, err = cdtree.CreateProof(field) + if err != nil { + return nil, errors.New("createProofs error %v", err) + } + proof.SortedHashes = append(proof.SortedHashes, dataRoot) + } else { + return nil, errors.New("createProofs error %v", err) + } + } else { + proof.SortedHashes = append(proof.SortedHashes, cdRoot) + } + proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) + proofs = append(proofs, &proof) + } + + return proofs, nil +} + +// GetCoreDocTree returns the merkle tree for the coredoc root +func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err error) { + document := m.Document + h := sha256.New() + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + tree = &t + err = tree.AddLeavesFromDocument(document, document.CoredocumentSalts) + if err != nil { + return nil, err + } + + if document.EmbeddedData == nil { + return nil, errors.New("EmbeddedData cannot be nil when generating signing tree") + } + // Adding document type as it is an excluded field in the tree + documentTypeNode := proofs.LeafNode{ + Property: proofs.NewProperty("document_type"), + Salt: make([]byte, 32), + Value: document.EmbeddedData.TypeUrl, + } + + err = documentTypeNode.HashNode(h, false) + if err != nil { + return nil, err + } + + err = tree.AddLeaf(documentTypeNode) + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + return tree, nil +} + +// GetDocumentSigningTree returns the merkle tree for the signing root +func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proofs.DocumentTree, err error) { + h := sha256.New() + + // coredoc tree + coreDocTree, err := m.GetCoreDocTree() + if err != nil { + return nil, err + } + + // create the signing tree with data root and coredoc root as siblings + t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + tree = &t2 + err = tree.AddLeaves([]proofs.LeafNode{ + { + Property: proofs.NewProperty("data_root"), + Hash: dataRoot, + Hashed: true, + }, + { + Property: proofs.NewProperty("cd_root"), + Hash: coreDocTree.RootHash(), + Hashed: true, + }, + }) + + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + + return tree, nil +} + +// GetDocumentRootTree returns the merkle tree for the document root +func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, err error) { + document := m.Document + h := sha256.New() + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + tree = &t + + // The first leave added is the signing_root + err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: proofs.NewProperty("signing_root")}) + if err != nil { + return nil, err + } + // For every signature we create a LeafNode + sigProperty := proofs.NewProperty("signatures") + sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) + sigLengthNode := proofs.LeafNode{ + Property: sigProperty.LengthProp(), + Salt: make([]byte, 32), + Value: fmt.Sprintf("%d", len(document.Signatures)), + } + err = sigLengthNode.HashNode(h, false) + if err != nil { + return nil, err + } + sigLeafList[0] = sigLengthNode + for i, sig := range document.Signatures { + payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) + leaf := proofs.LeafNode{ + Hash: payload[:], + Hashed: true, + Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), + } + err = leaf.HashNode(h, false) + if err != nil { + return nil, err + } + sigLeafList[i+1] = leaf + } + err = tree.AddLeaves(sigLeafList) + if err != nil { + return nil, err + } + err = tree.Generate() + if err != nil { + return nil, err + } + return tree, nil +} + +// CalculateDocumentRoot calculates the document root of the core document +func (m *CoreDocumentModel) CalculateDocumentRoot() error { + document := m.Document + if len(document.SigningRoot) != 32 { + return errors.New("signing root invalid") + } + + tree, err := m.GetDocumentRootTree() + if err != nil { + return err + } + + document.DocumentRoot = tree.RootHash() + return nil +} + +// getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used +// to create field proofs +func (m *CoreDocumentModel) getDataProofHashes(dataRoot []byte) (hashes [][]byte, err error) { + tree, err := m.GetDocumentSigningTree(dataRoot) + if err != nil { + return + } + + signingProof, err := tree.CreateProof("data_root") + if err != nil { + return + } + + rootProofHashes, err := m.getSigningRootProofHashes() + if err != nil { + return + } + + return append(signingProof.SortedHashes, rootProofHashes...), err +} + +// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. This method is used +// to create field proofs +func (m *CoreDocumentModel) getSigningRootProofHashes() (hashes [][]byte, err error) { + tree, err := m.GetDocumentRootTree() + if err != nil { + return + } + rootProof, err := tree.CreateProof("signing_root") + if err != nil { + return + } + return rootProof.SortedHashes, err +} + +// CalculateSigningRoot calculates the signing root of the core document +func (m *CoreDocumentModel) CalculateSigningRoot(dataRoot []byte) error { + doc := m.Document + tree, err := m.GetDocumentSigningTree(dataRoot) + if err != nil { + return err + } + + doc.SigningRoot = tree.RootHash() + return nil +} + +// AccountCanRead validate if the core document can be read by the account . +// Returns an error if not. +func (m *CoreDocumentModel) AccountCanRead(account identity.CentID) bool { + // loop though read rules + return m.findRole(coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { + return isAccountInRole(role, account) + }) +} + // FillSalts creates a new coredocument.Salts and fills it func (m *CoreDocumentModel) fillSalts() error { salts := new(coredocumentpb.CoreDocumentSalts) cd := m.Document err := proofs.FillSalts(cd, salts) if err != nil { - return errors.New("failed to fill coredocument salts: %v", err) + return errors.New("failed to fill Document salts: %v", err) } cd.CoredocumentSalts = salts return nil } +// initReadRules initiates the read rules for a given CoreDocumentModel. +// Collaborators are given Read_Sign action. +// if the rules are created already, this is a no-op. +func (m *CoreDocumentModel) initReadRules(collabs []identity.CentID) error { + cd := m.Document + if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { + return nil + } + + if len(collabs) < 1 { + return ErrZeroCollaborators + } + + return m.addCollaboratorsToReadSignRules(collabs) +} + +// addNewRule creates a new rule as per the role and action. +func (m *CoreDocumentModel) addNewRule(role *coredocumentpb.Role, action coredocumentpb.Action) { + cd := m.Document + cd.Roles = append(cd.Roles, role) + + rule := new(coredocumentpb.ReadRule) + rule.Roles = append(rule.Roles, role.RoleKey) + rule.Action = action + cd.ReadRules = append(cd.ReadRules, rule) +} + +// findRole calls OnRole for every role, +// if onRole returns true, returns true +// else returns false +func (m *CoreDocumentModel) findRole(action coredocumentpb.Action, onRole func(role *coredocumentpb.Role) bool) bool { + cd := m.Document + for _, rule := range cd.ReadRules { + if rule.Action != action { + continue + } + + for _, rk := range rule.Roles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + + if onRole(role) { + return true + } + + } + } + + return false +} + +// isAccountInRole returns true if account is in the given role as collaborators. +func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { + for _, id := range role.Collaborators { + if bytes.Equal(id, account[:]) { + return true + } + } + + return false +} + +func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { + for _, role := range roles { + if utils.IsSameByteSlice(role.RoleKey, key) { + return role, nil + } + } + + return nil, errors.New("role %d not found", key) +} + +func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.CentID) error { + if len(collabs) == 0 { + return nil + } + // create a role for given collaborators + role := new(coredocumentpb.Role) + cd := m.Document + rk, err := utils.ConvertIntToByte32(len(cd.Roles)) + if err != nil { + return err + } + role.RoleKey = rk[:] + for _, c := range collabs { + c := c + role.Collaborators = append(role.Collaborators, c[:]) + } + + m.addNewRule(role, coredocumentpb.Action_ACTION_READ_SIGN) + + return nil +} + func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.CentID, err error) { ocsm := make(map[string]struct{}) for _, c := range oldCollabs { diff --git a/documents/model_test.go b/documents/model_test.go index d56ae41d1..f57d8f915 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -3,9 +3,16 @@ package documents import ( + "crypto/sha256" "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/golang/protobuf/ptypes/any" + "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -147,3 +154,218 @@ func TestCoreDocumentModel_PrepareNewVersion(t *testing.T) { // DocumentRoot was updated assert.Equal(t, ncd.PreviousRoot, ocd.DocumentRoot) } + +func TestReadACLs_initReadRules(t *testing.T) { + dm := NewCoreDocModel() + cd := dm.Document + err := dm.initReadRules(nil) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) + + cs := []identity.CentID{identity.RandomCentID()} + err = dm.initReadRules(cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) + + err = dm.initReadRules(cs) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) +} + +func TestReadAccessValidator_AccountCanRead(t *testing.T) { + dm := NewCoreDocModel() + account, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + dm.Document.DocumentRoot = utils.RandomSlice(32) + ndm, err := dm.PrepareNewVersion([]string{account.String()}) + cd := ndm.Document + assert.NoError(t, err) + assert.NotNil(t, cd.ReadRules) + assert.NotNil(t, cd.Roles) + + // account who cant access + rcid := identity.RandomCentID() + assert.False(t, ndm.AccountCanRead(rcid)) + + // account can access + assert.True(t, ndm.AccountCanRead(account)) +} + +func TestGetSigningProofHashes(t *testing.T) { + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + dm := NewCoreDocModel() + cd := dm.Document + cd.EmbeddedData = docAny + cd.DataRoot = utils.RandomSlice(32) + salts := new(coredocumentpb.CoreDocumentSalts) + err := proofs.FillSalts(cd, salts) + assert.Nil(t, err) + + cd.CoredocumentSalts = salts + err = dm.CalculateSigningRoot(cd.DataRoot) + assert.Nil(t, err) + + err = dm.CalculateDocumentRoot() + assert.Nil(t, err) + + hashes, err := dm.getSigningRootProofHashes() + assert.Nil(t, err) + assert.Equal(t, 1, len(hashes)) + + valid, err := proofs.ValidateProofSortedHashes(cd.SigningRoot, hashes, cd.DocumentRoot, sha256.New()) + assert.True(t, valid) + assert.Nil(t, err) +} + +func TestGetDataProofHashes(t *testing.T) { + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + dm := NewCoreDocModel() + cd := dm.Document + cd.EmbeddedData = docAny + cd.DataRoot = utils.RandomSlice(32) + cds := &coredocumentpb.CoreDocumentSalts{} + err := proofs.FillSalts(cd, cds) + assert.Nil(t, err) + + cd.CoredocumentSalts = cds + + err = dm.CalculateSigningRoot(cd.DataRoot) + assert.Nil(t, err) + + err = dm.CalculateDocumentRoot() + assert.Nil(t, err) + + hashes, err := dm.getDataProofHashes(cd.DataRoot) + assert.Nil(t, err) + assert.Equal(t, 2, len(hashes)) + + valid, err := proofs.ValidateProofSortedHashes(cd.DataRoot, hashes, cd.DocumentRoot, sha256.New()) + assert.True(t, valid) + assert.Nil(t, err) +} + +func TestGetDocumentSigningTree(t *testing.T) { + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + dm := NewCoreDocModel() + cd := dm.Document + cd.EmbeddedData = docAny + cds := &coredocumentpb.CoreDocumentSalts{} + proofs.FillSalts(cd, cds) + cd.CoredocumentSalts = cds + tree, err := dm.GetDocumentSigningTree(cd.DataRoot) + assert.Nil(t, err) + assert.NotNil(t, tree) + + _, leaf := tree.GetLeafByProperty("data_root") + assert.NotNil(t, leaf) + + _, leaf = tree.GetLeafByProperty("cd_root") + assert.NotNil(t, leaf) +} + +func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { + dm := NewCoreDocModel() + cd := dm.Document + cds := &coredocumentpb.CoreDocumentSalts{} + proofs.FillSalts(cd, cds) + cd.CoredocumentSalts = cds + tree, err := dm.GetDocumentSigningTree(cd.DataRoot) + assert.NotNil(t, err) + assert.Nil(t, tree) +} + +// TestGetDocumentRootTree tests that the documentroottree is properly calculated +func TestGetDocumentRootTree(t *testing.T) { + dm := NewCoreDocModel() + cd := &coredocumentpb.CoreDocument{SigningRoot: []byte{0x72, 0xee, 0xb8, 0x88, 0x92, 0xf7, 0x6, 0x19, 0x82, 0x76, 0xe9, 0xe7, 0xfe, 0xcc, 0x33, 0xa, 0x66, 0x78, 0xd4, 0xa6, 0x5f, 0xf6, 0xa, 0xca, 0x2b, 0xe4, 0x17, 0xa9, 0xf6, 0x15, 0x67, 0xa1}} + dm.Document = cd + tree, err := dm.GetDocumentRootTree() + + // Manually constructing the two node tree: + signaturesLengthLeaf := sha256.Sum256(append([]byte("signatures.length0"), make([]byte, 32)...)) + expectedRootHash := sha256.Sum256(append(signaturesLengthLeaf[:], dm.Document.SigningRoot...)) + assert.Nil(t, err) + assert.Equal(t, expectedRootHash[:], tree.RootHash()) +} + +func TestCreateProofs(t *testing.T) { + h := sha256.New() + testTree := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) + err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field")}) + assert.NoError(t, err) + err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field2")}) + assert.NoError(t, err) + err = testTree.Generate() + assert.NoError(t, err) + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + dm := NewCoreDocModel() + cd := dm.Document + cd.EmbeddedData = docAny + cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} + err = dm.fillSalts() + assert.NoError(t, err) + err = dm.CalculateSigningRoot(testTree.RootHash()) + assert.NoError(t, err) + err = dm.CalculateDocumentRoot() + assert.NoError(t, err) + cdTree, err := dm.GetCoreDocTree() + assert.NoError(t, err) + tests := []struct { + fieldName string + fromCoreDoc bool + proofLength int + }{ + { + "sample_field", + false, + 3, + }, + { + "document_identifier", + true, + 6, + }, + { + "sample_field2", + false, + 3, + }, + { + "collaborators[0]", + true, + 6, + }, + } + for _, test := range tests { + t.Run(test.fieldName, func(t *testing.T) { + p, err := dm.CreateProofs(&testTree, []string{test.fieldName}) + assert.NoError(t, err) + assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) + var l *proofs.LeafNode + if test.fromCoreDoc { + _, l = cdTree.GetLeafByProperty(test.fieldName) + } else { + _, l = testTree.GetLeafByProperty(test.fieldName) + } + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) + assert.NoError(t, err) + assert.True(t, valid) + }) + } + +} diff --git a/documents/read_acls.go b/documents/read_acls.go deleted file mode 100644 index 36d8808ff..000000000 --- a/documents/read_acls.go +++ /dev/null @@ -1,148 +0,0 @@ -package documents - -import ( - "bytes" - - "github.com/centrifuge/go-centrifuge/utils" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/ethereum/go-ethereum/common" -) - -const ( - // ErrZeroCollaborators error when no collaborators are passed - ErrZeroCollaborators = errors.Error("require at least one collaborator") - - // nftByteCount is the length of combined bytes of registry and tokenID - nftByteCount = 52 -) - -// TokenRegistry defines NFT retrieval functions. -type TokenRegistry interface { - // OwnerOf to retrieve owner of the tokenID - OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) -} - -// initReadRules initiates the read rules for a given coredocument. -// Collaborators are given Read_Sign action. -// if the rules are created already, this is a no-op. -func initReadRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { - if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { - return nil - } - - if len(collabs) < 1 { - return ErrZeroCollaborators - } - - return addCollaboratorsToReadSignRules(cd, collabs) -} - -func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { - if len(collabs) == 0 { - return nil - } - - // create a role for given collaborators - role := new(coredocumentpb.Role) - rk, err := utils.ConvertIntToByte32(len(cd.Roles)) - if err != nil { - return err - } - role.RoleKey = rk[:] - for _, c := range collabs { - c := c - role.Collaborators = append(role.Collaborators, c[:]) - } - - addNewRule(cd, role, coredocumentpb.Action_ACTION_READ_SIGN) - - return nil -} - -// addNewRule creates a new rule as per the role and action. -func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, action coredocumentpb.Action) { - cd.Roles = append(cd.Roles, role) - - rule := new(coredocumentpb.ReadRule) - rule.Roles = append(rule.Roles, role.RoleKey) - rule.Action = action - cd.ReadRules = append(cd.ReadRules, rule) -} - -// ReadAccessValidator defines validator functions for account . -type ReadAccessValidator interface { - AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool -} - -// readAccessValidator implements ReadAccessValidator. -type readAccessValidator struct { - tokenRegistry TokenRegistry -} - -// AccountCanRead validate if the core document can be read by the account . -// Returns an error if not. -func (r readAccessValidator) AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool { - // loop though read rules - return findRole(cd, coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { - return isAccountInRole(role, account) - }) -} - -func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { - for _, role := range roles { - if utils.IsSameByteSlice(role.RoleKey, key) { - return role, nil - } - } - - return nil, errors.New("role %d not found", key) -} - -// isAccountInRole returns true if account is in the given role as collaborators. -func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { - for _, id := range role.Collaborators { - if bytes.Equal(id, account[:]) { - return true - } - } - - return false -} - -// AccountValidator returns the ReadAccessValidator to verify account . -func AccountValidator() ReadAccessValidator { - return readAccessValidator{} -} - -// findRole calls OnRole for every role, -// if onRole returns true, returns true -// else returns false -func findRole( - cd *coredocumentpb.CoreDocument, - action coredocumentpb.Action, - onRole func(role *coredocumentpb.Role) bool) bool { - for _, rule := range cd.ReadRules { - if rule.Action != action { - continue - } - - for _, rk := range rule.Roles { - role, err := getRole(rk, cd.Roles) - if err != nil { - // seems like roles and rules are not in sync - // skip to next one - continue - } - - if onRole(role) { - return true - } - - } - } - - return false -} diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go index d57fb5ab0..c4930fd3a 100644 --- a/documents/read_acls_test.go +++ b/documents/read_acls_test.go @@ -2,124 +2,74 @@ package documents -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/coredocument" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestReadACLs_initReadRules(t *testing.T) { - cd := coredocument.New() - err := initReadRules(cd, nil) - assert.Error(t, err) - assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) - - cs := []identity.CentID{identity.RandomCentID()} - err = initReadRules(cd, cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) - - err = initReadRules(cd, cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) -} - -func TestReadAccessValidator_AccountCanRead(t *testing.T) { - pv := AccountValidator() - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) - - cd, err := coredocument.NewWithCollaborators([]string{account.String()}) - assert.NoError(t, err) - assert.NotNil(t, cd.ReadRules) - assert.NotNil(t, cd.Roles) - - // account who cant access - rcid := identity.RandomCentID() - assert.False(t, pv.AccountCanRead(cd, rcid)) - - // account can access - assert.True(t, pv.AccountCanRead(cd, account)) -} - -func Test_addNFTToReadRules(t *testing.T) { - // wrong registry or token format - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(34) - - err := coredocument.AddNFTToReadRules(nil, registry, tokenID) - assert.Error(t, err) - - cd, err := coredocument.NewWithCollaborators([]string{"0x010203040506"}) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) - assert.Len(t, cd.Roles, 1) - - tokenID = utils.RandomSlice(32) - err = coredocument.AddNFTToReadRules(cd, registry, tokenID) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 2) - assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) - assert.Len(t, cd.Roles, 2) -} - -type mockRegistry struct { - mock.Mock -} - -func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { - args := m.Called(registry, tokenID) - addr, _ := args.Get(0).(common.Address) - return addr, args.Error(1) -} - -func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) - - cd, err := coredocument.NewWithCollaborators([]string{account.String()}) - assert.NoError(t, err) - - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - - // account can read - validator := coredocument.NftValidator(nil) - err = validator.NFTOwnerCanRead(cd, registry, nil, account) - assert.NoError(t, err) - - // account not in read rules and nft missing - account, err = identity.CentIDFromString("0x010203040505") - assert.NoError(t, err) - tokenID := utils.RandomSlice(32) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - - tr := mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() - coredocument.AddNFTToReadRules(cd, registry, tokenID) - validator = coredocument.NftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - assert.Contains(t, err, "failed to get owner of") - tr.AssertExpectations(t) - - // not the same owner - owner := common.BytesToAddress(utils.RandomSlice(20)) - tr = mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() - validator = coredocument.NftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - tr.AssertExpectations(t) -} +//func Test_addNFTToReadRules(t *testing.T) { +// // wrong registry or token format +// registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") +// tokenID := utils.RandomSlice(34) +// +// err := coredocument.AddNFTToReadRules(nil, registry, tokenID) +// assert.Error(t, err) +// +// cd, err := coredocument.NewWithCollaborators([]string{"0x010203040506"}) +// assert.NoError(t, err) +// assert.Len(t, cd.ReadRules, 1) +// assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) +// assert.Len(t, cd.Roles, 1) +// +// tokenID = utils.RandomSlice(32) +// err = coredocument.AddNFTToReadRules(cd, registry, tokenID) +// assert.NoError(t, err) +// assert.Len(t, cd.ReadRules, 2) +// assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) +// assert.Len(t, cd.Roles, 2) +//} +// +//type mockRegistry struct { +// mock.Mock +//} +// +//func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { +// args := m.Called(registry, tokenID) +// addr, _ := args.Get(0).(common.Address) +// return addr, args.Error(1) +//} +// +//func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { +// account, err := identity.CentIDFromString("0x010203040506") +// assert.NoError(t, err) +// +// cd, err := coredocument.NewWithCollaborators([]string{account.String()}) +// assert.NoError(t, err) +// +// registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") +// +// // account can read +// validator := coredocument.NftValidator(nil) +// err = validator.NFTOwnerCanRead(cd, registry, nil, account) +// assert.NoError(t, err) +// +// // account not in read rules and nft missing +// account, err = identity.CentIDFromString("0x010203040505") +// assert.NoError(t, err) +// tokenID := utils.RandomSlice(32) +// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) +// assert.Error(t, err) +// +// tr := mockRegistry{} +// tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() +// coredocument.AddNFTToReadRules(cd, registry, tokenID) +// validator = coredocument.NftValidator(tr) +// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) +// assert.Error(t, err) +// assert.Contains(t, err, "failed to get owner of") +// tr.AssertExpectations(t) +// +// // not the same owner +// owner := common.BytesToAddress(utils.RandomSlice(20)) +// tr = mockRegistry{} +// tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() +// validator = coredocument.NftValidator(tr) +// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) +// assert.Error(t, err) +// tr.AssertExpectations(t) +//} From edcb857a465324c172e0cf71d69e0f92845f92b3 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Fri, 8 Feb 2019 13:47:59 +0100 Subject: [PATCH 182/220] identity: added isSignedWithPurpose support (#733) * added testworld tests for proofs * bind identity service to did * removed identity init from bootstrapper * added account context to create identity * added waitingTransaction task * create identity uses task manager * refactored add key and execute tests * correct usage of done flag * added context to identity methods * formatting * fixed add key testcase * add key uses txManager * using tx manager for exceute methods * removed old wait for tx helper method * fixed correct reset of identityID * refactored identity to service * refactored service to factory * refactored identity to service * removed config from factory * added isSignedWithPurpose to identity * formatting * better comments --- identity/did/service.go | 24 +++++++++++ identity/did/service_integration_test.go | 52 +++++++++++++++++++++++- utils/tools.go | 13 ++++++ utils/tools_test.go | 14 +++++++ 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/identity/did/service.go b/identity/did/service.go index a86055d4c..52486a973 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -49,6 +49,9 @@ type Service interface { // Execute creates the abi encoding an calls the execute method on the identity contract Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error + + // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys + IsSignedWithPurpose(ctx context.Context, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) } type contract interface { @@ -60,6 +63,8 @@ type contract interface { RevokedAt *big.Int }, error) + IsSignedWithPurpose(opts *bind.CallOpts, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) + // Ethereum Transactions AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) @@ -140,6 +145,7 @@ func (i service) getDID(ctx context.Context) (did DID, err error) { } +// AddKey adds a key to identity contract func (i service) AddKey(ctx context.Context, key Key) error { did, err := i.getDID(ctx) if err != nil { @@ -217,6 +223,7 @@ func (i service) rawExecuteTX(opts *bind.TransactOpts, identityContract contract } +// GetKey return a key from the identity contract func (i service) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) { did, err := i.getDID(ctx) if err != nil { @@ -237,6 +244,22 @@ func (i service) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) } +// IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys +func (i service) IsSignedWithPurpose(ctx context.Context, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { + did, err := i.getDID(ctx) + if err != nil { + return false, err + } + contract, opts, _, err := i.prepareCall(did) + if err != nil { + return false, err + } + + return contract.IsSignedWithPurpose(opts, message, _signature, _purpose) + +} + +// RawExecute calls the execute method on the identity contract func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) error { did, err := i.getDID(ctx) if err != nil { @@ -266,6 +289,7 @@ func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) } +// Execute creates the abi encoding an calls the execute method on the identity contract func (i service) Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error { abi, err := abi.JSON(strings.NewReader(contractAbi)) if err != nil { diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index 6ea862eb3..f6bac07d5 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -6,6 +6,9 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -55,7 +58,7 @@ func deployIdentityContract(t *testing.T) *DID { } -func TestAddKey_successful(t *testing.T) { +func TestServiceAddKey_successful(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() @@ -72,7 +75,7 @@ func TestAddKey_successful(t *testing.T) { resetDefaultCentID() } -func TestAddKey_fail(t *testing.T) { +func TestServiceAddKey_fail(t *testing.T) { testKey := getTestKey() did := NewDIDFromString("0x123") aCtx := getTestDIDContext(t, did) @@ -86,3 +89,48 @@ func TestAddKey_fail(t *testing.T) { resetDefaultCentID() } + +func TestService_IsSignedWithPurpose(t *testing.T) { + // create keys + pk, sk, err := secp256k1.GenerateSigningKeyPair() + address := common.HexToAddress(secp256k1.GetAddress(pk)) + address32Bytes := utils.AddressTo32Bytes(address) + assert.Nil(t, err, "should convert a address to 32 bytes") + + // purpose + purpose := utils.ByteSliceToBigInt([]byte{123}) + assert.Nil(t, err, "should generate signing key pair") + + // deploy identity and add key with purpose + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + key := &key{Key: address32Bytes, Purpose: purpose, Type: utils.ByteSliceToBigInt([]byte{123})} + err = idSrv.AddKey(aCtx, key) + assert.Nil(t, err, "add key should be successful") + + // sign a msg with keypair + msg := utils.RandomByte32() + signature, err := secp256k1.SignEthereum(msg[:], sk) + assert.Nil(t, err, "should sign a message") + + //correct signature and purpose + signed, err := idSrv.IsSignedWithPurpose(aCtx, msg, signature, purpose) + assert.Nil(t, err, "sign verify should not throw an error") + assert.True(t, signed, "signature should be correct") + + //false purpose + falsePurpose := utils.ByteSliceToBigInt([]byte{42}) + signed, err = idSrv.IsSignedWithPurpose(aCtx, msg, signature, falsePurpose) + assert.Nil(t, err, "sign verify should not throw an error") + assert.False(t, signed, "signature should be false (wrong purpose)") + + //false keypair + _, sk2, _ := secp256k1.GenerateSigningKeyPair() + signature, err = secp256k1.SignEthereum(msg[:], sk2) + assert.Nil(t, err, "should sign a message") + signed, err = idSrv.IsSignedWithPurpose(aCtx, msg, signature, purpose) + assert.Nil(t, err, "sign verify should not throw an error") + assert.False(t, signed, "signature should be wrong key pair") + +} diff --git a/utils/tools.go b/utils/tools.go index ca768b842..4808f47a1 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -65,6 +65,19 @@ func CheckMultiple32BytesFilled(b []byte, bs ...[]byte) bool { return true } +// AddressTo32Bytes converts an address to 32 a byte array +// The length of an address is 20 bytes. First 12 bytes are filled with zeros. +func AddressTo32Bytes(address common.Address) [32]byte { + addressBytes := address.Bytes() + address32Byte := [32]byte{} + for i := 1; i <= common.AddressLength; i++ { + + address32Byte[32-i] = addressBytes[common.AddressLength-i] + } + return address32Byte + +} + // RandomSlice returns a randomly filled byte array with length of given size func RandomSlice(size int) (out []byte) { r := make([]byte, size) diff --git a/utils/tools_test.go b/utils/tools_test.go index 6094feac2..cb90aa28a 100644 --- a/utils/tools_test.go +++ b/utils/tools_test.go @@ -6,6 +6,8 @@ import ( "encoding/binary" "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) @@ -233,6 +235,18 @@ func TestConvertIntToBytes(t *testing.T) { assert.Equal(t, n, ni) } +func TestAddressTo32Bytes(t *testing.T) { + address := RandomSlice(common.AddressLength) + address32bytes := AddressTo32Bytes(common.BytesToAddress(address)) + for i := 0; i < common.AddressLength; i++ { + + assert.Equal(t, address[i], address32bytes[i+32-common.AddressLength], "every byte should be equal") + } + for i := 0; i < 32-common.AddressLength; i++ { + assert.Equal(t, uint8(0x0), address32bytes[i], "first 12 bytes need to be equal 0") + } +} + func verifyHex(t *testing.T, val string) { _, err := hexutil.Decode(val) assert.Nil(t, err) From 88fdefc1b1f818f59aff384d140c9a3d6739b24c Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Mon, 11 Feb 2019 16:44:53 +0100 Subject: [PATCH 183/220] identity: added multiPurpose methods (#737) * multi purpose added * added test for multi purpose add * formatting * fixed test for multi purpose --- identity/did/service.go | 57 ++++++++++++++---------- identity/did/service_integration_test.go | 24 ++++++++++ 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/identity/did/service.go b/identity/did/service.go index 52486a973..740896ac9 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -52,6 +52,9 @@ type Service interface { // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys IsSignedWithPurpose(ctx context.Context, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) + + // AddMultiPurposeKey adds a key with multiple purposes + AddMultiPurposeKey(context context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error } type contract interface { @@ -69,6 +72,8 @@ type contract interface { AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) + + AddMultiPurposeKey(opts *bind.TransactOpts, _key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) } type service struct { @@ -158,7 +163,8 @@ func (i service) AddKey(ctx context.Context, key Key) error { } // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add key", i.addKeyTX(opts, contract, key)) + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add key", + i.ethereumTX(opts, contract.AddKey, key.GetKey(), key.GetPurpose(), key.GetType())) if err != nil { return err } @@ -173,34 +179,38 @@ func (i service) AddKey(ctx context.Context, key Key) error { } -func (i service) addKeyTX(opts *bind.TransactOpts, identityContract contract, key Key) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - ethTX, err := i.client.SubmitTransactionWithRetries(identityContract.AddKey, opts, key.GetKey(), key.GetPurpose(), key.GetType()) - if err != nil { - errOut <- err - return - } - logTxHash(ethTX) +// AddMultiPurposeKey adds a key with multiple purposes +func (i service) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error { + did, err := i.getDID(ctx) + if err != nil { + return err + } - res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), i.queue) - if err != nil { - errOut <- err - return - } + contract, opts, err := i.prepareTransaction(ctx, did) + if err != nil { + return err + } - _, err = res.Get(txMan.GetDefaultTaskTimeout()) - if err != nil { - errOut <- err - return - } - errOut <- nil + // TODO: did can be passed instead of randomCentID after CentID is DID + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add multi purpose key", + i.ethereumTX(opts, contract.AddMultiPurposeKey, key, purposes, keyType)) + if err != nil { + return err } + isDone := <-done + // non async task + if !isDone { + return errors.New("add key multi purpose TX failed: txID:%s", txID.String()) + + } + return nil } -func (i service) rawExecuteTX(opts *bind.TransactOpts, identityContract contract, to common.Address, value *big.Int, data []byte) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +// ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result +func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - ethTX, err := i.client.SubmitTransactionWithRetries(identityContract.Execute, opts, to, value, data) + ethTX, err := i.client.SubmitTransactionWithRetries(contractMethod, opts, params...) if err != nil { errOut <- err return @@ -220,7 +230,6 @@ func (i service) rawExecuteTX(opts *bind.TransactOpts, identityContract contract } errOut <- nil } - } // GetKey return a key from the identity contract @@ -274,7 +283,7 @@ func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) value := big.NewInt(0) // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for execute", i.rawExecuteTX(opts, contract, to, value, data)) + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for execute", i.ethereumTX(opts, contract.Execute, to, value, data)) if err != nil { return err } diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index f6bac07d5..f597fbbde 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -4,6 +4,7 @@ package did import ( "context" + "math/big" "testing" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" @@ -132,5 +133,28 @@ func TestService_IsSignedWithPurpose(t *testing.T) { signed, err = idSrv.IsSignedWithPurpose(aCtx, msg, signature, purpose) assert.Nil(t, err, "sign verify should not throw an error") assert.False(t, signed, "signature should be wrong key pair") + resetDefaultCentID() + +} + +func TestService_AddMultiPurposeKey(t *testing.T) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + key := utils.RandomByte32() + purposeOne := utils.ByteSliceToBigInt([]byte{123}) + purposeTwo := utils.ByteSliceToBigInt([]byte{42}) + purposes := []*big.Int{purposeOne, purposeTwo} + keyType := utils.ByteSliceToBigInt([]byte{137}) + + err := idSrv.AddMultiPurposeKey(aCtx, key, purposes, keyType) + assert.Nil(t, err, "add key with multiple purposes should be successful") + response, err := idSrv.GetKey(aCtx, key) + assert.Nil(t, err, "get Key should be successful") + + assert.Equal(t, purposeOne, response.Purposes[0], "key should have the same first purpose") + assert.Equal(t, purposeTwo, response.Purposes[1], "key should have the same second purpose") + resetDefaultCentID() } From 3e88b298ca0056c5ce689b3c71dd5ecd531bd5da Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 11 Feb 2019 17:05:57 +0100 Subject: [PATCH 184/220] Using almost latest precise proofs (#739) * using new salts * fix some tests * revert string encoding * add tests --- Gopkg.lock | 8 +- Gopkg.toml | 4 +- coredocument/coredocument.go | 59 +++++++++++-- coredocument/coredocument_test.go | 39 ++------- documents/invoice/model.go | 46 +++++----- documents/invoice/model_test.go | 10 +-- documents/invoice/service_test.go | 2 +- documents/invoice/utils_test.go | 22 +++++ documents/model.go | 69 ++++++++++++--- documents/model_test.go | 72 ++++++++++++---- documents/purchaseorder/model.go | 100 +++++++++++----------- documents/purchaseorder/model_test.go | 14 +-- documents/purchaseorder/service_test.go | 2 +- documents/purchaseorder/utils_test.go | 22 +++++ documents/validator.go | 16 ++-- documents/validator_test.go | 41 ++++----- nft/ethereum_payment_obligation_test.go | 20 +++-- p2p/client_integration_test.go | 37 +------- p2p/receiver/handler_integration_test.go | 21 ++--- testingutils/coredocument/coredocument.go | 23 +++-- testingutils/documents/invoice.go | 33 ------- testingutils/documents/purchaseorder.go | 33 ------- utils/tools.go | 7 +- 23 files changed, 371 insertions(+), 329 deletions(-) create mode 100644 documents/invoice/utils_test.go create mode 100644 documents/purchaseorder/utils_test.go diff --git a/Gopkg.lock b/Gopkg.lock index faafc1a56..843464c10 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:9ae859e0e06b1ef79ebe8e7a6ae62bc696bde18d142de253097edb58cad17984" + digest = "1:dfe1a0223d1205b5d387f9409d72e88877c7470c79930dd00da6d63f4b0af963" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "569fc37a1acbc443894362b51b2e42496c5ad59c" + revision = "5615ef01001f185e1ecbe10eb9604b5eeaae0b04" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" @@ -86,14 +86,14 @@ revision = "fb11151a227ae41660e15f6c10e2e22eb1556531" [[projects]] - digest = "1:a145dca8eb072174d0bce9c21771ec19885bdaa04fe2f9026de4664811b1caf7" + digest = "1:1d46f9f40eca1a4f235a3e0bf118489b0aa4eae84d045f6f2c33611a3030d0ac" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "8c3b6a26b7929ec269302dc50d17c9ceb9772dda" + revision = "4b2df6595f0b4e119ce20df5d9f1bac358c8589e" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" diff --git a/Gopkg.toml b/Gopkg.toml index caf5fe95a..8d8c77a4a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "569fc37a1acbc443894362b51b2e42496c5ad59c" + revision = "5615ef01001f185e1ecbe10eb9604b5eeaae0b04" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" @@ -44,7 +44,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[override]] name = "github.com/centrifuge/precise-proofs" - revision = "8c3b6a26b7929ec269302dc50d17c9ceb9772dda" + revision = "4b2df6595f0b4e119ce20df5d9f1bac358c8589e" [[constraint]] name = "github.com/centrifuge/gocelery" diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index 8c03b4003..ee3902dbc 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -78,7 +80,7 @@ func CalculateDocumentRoot(document *coredocumentpb.CoreDocument) error { // GetDocumentRootTree returns the merkle tree for the document root func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) tree = &t // The first leave added is the signing_root @@ -90,7 +92,7 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do sigProperty := proofs.NewProperty("signatures") sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ - Property: sigProperty.LengthProp(), + Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), Salt: make([]byte, 32), Value: fmt.Sprintf("%d", len(document.Signatures)), } @@ -126,9 +128,9 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do // GetCoreDocTree returns the merkle tree for the coredoc root func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) tree = &t - err = tree.AddLeavesFromDocument(document, document.CoredocumentSalts) + err = tree.AddLeavesFromDocument(document) if err != nil { return nil, err } @@ -171,7 +173,7 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument, dataRoot []by } // create the signing tree with data root and coredoc root as siblings - t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) tree = &t2 err = tree.AddLeaves([]proofs.LeafNode{ { @@ -304,15 +306,54 @@ func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.Co return collabs, nil } +// GenerateNewSalts generates salts for new document +func GenerateNewSalts(document proto.Message, prefix string) (*proofs.Salts, error) { + docSalts := &proofs.Salts{} + prop := proofs.NewProperty(prefix) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: docSalts}) + err := t.AddLeavesFromDocument(document) + if err != nil { + return nil, err + } + return docSalts, nil +} + +// ConvertToProtoSalts converts proofSalts into protocolSalts +func ConvertToProtoSalts(proofSalts *proofs.Salts) []*coredocumentpb.DocumentSalt { + protoSalts := make([]*coredocumentpb.DocumentSalt, len(*proofSalts)) + if proofSalts == nil { + return nil + } + + for i, pSalt := range *proofSalts { + protoSalts[i] = &coredocumentpb.DocumentSalt{Value: pSalt.Value, Compact: pSalt.Compact} + } + + return protoSalts +} + +// ConvertToProofSalts converts protocolSalts into proofSalts +func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salts { + proofSalts := make(proofs.Salts, len(protoSalts)) + if protoSalts == nil { + return nil + } + + for _, pSalt := range protoSalts { + proofSalts = append(proofSalts, proofs.Salt{Value: pSalt.Value, Compact: pSalt.Compact}) + } + + return &proofSalts +} + // FillSalts creates a new coredocument.Salts and fills it func FillSalts(doc *coredocumentpb.CoreDocument) error { - salts := new(coredocumentpb.CoreDocumentSalts) - err := proofs.FillSalts(doc, salts) + salts, err := GenerateNewSalts(doc, "") if err != nil { - return errors.New("failed to fill coredocument salts: %v", err) + return err } - doc.CoredocumentSalts = salts + doc.CoredocumentSalts = ConvertToProtoSalts(salts) return nil } diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 3715038a9..735d60301 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -15,7 +15,6 @@ import ( "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/ethereum/go-ethereum/common/hexutil" @@ -52,11 +51,9 @@ func TestGetSigningProofHashes(t *testing.T) { cd := New() cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - cds := &coredocumentpb.CoreDocumentSalts{} - err := proofs.FillSalts(cd, cds) - assert.Nil(t, err) + err := FillSalts(cd) + assert.NoError(t, err) - cd.CoredocumentSalts = cds err = CalculateSigningRoot(cd, cd.DataRoot) assert.Nil(t, err) @@ -80,11 +77,8 @@ func TestGetDataProofHashes(t *testing.T) { cd := New() cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - cds := &coredocumentpb.CoreDocumentSalts{} - err := proofs.FillSalts(cd, cds) - assert.Nil(t, err) - - cd.CoredocumentSalts = cds + err := FillSalts(cd) + assert.NoError(t, err) err = CalculateSigningRoot(cd, cd.DataRoot) assert.Nil(t, err) @@ -108,9 +102,8 @@ func TestGetDocumentSigningTree(t *testing.T) { } cd := New() cd.EmbeddedData = docAny - cds := &coredocumentpb.CoreDocumentSalts{} - proofs.FillSalts(cd, cds) - cd.CoredocumentSalts = cds + err := FillSalts(cd) + assert.NoError(t, err) tree, err := GetDocumentSigningTree(cd, cd.DataRoot) assert.Nil(t, err) assert.NotNil(t, tree) @@ -124,9 +117,8 @@ func TestGetDocumentSigningTree(t *testing.T) { func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { cd := New() - cds := &coredocumentpb.CoreDocumentSalts{} - proofs.FillSalts(cd, cds) - cd.CoredocumentSalts = cds + err := FillSalts(cd) + assert.NoError(t, err) tree, err := GetDocumentSigningTree(cd, cd.DataRoot) assert.NotNil(t, err) assert.Nil(t, tree) @@ -144,21 +136,6 @@ func TestGetDocumentRootTree(t *testing.T) { assert.Equal(t, expectedRootHash[:], tree.RootHash()) } -func TestGetTypeUrl(t *testing.T) { - coreDocument := testingcoredocument.GenerateCoreDocument() - - documentType, err := GetTypeURL(coreDocument) - assert.Nil(t, err, "should not throw an error because coreDocument has a type") - assert.NotEqual(t, documentType, "", "document type shouldn't be empty") - - _, err = GetTypeURL(nil) - assert.Error(t, err, "nil should throw an error") - - coreDocument.EmbeddedData.TypeUrl = "" - _, err = GetTypeURL(nil) - assert.Error(t, err, "should throw an error because typeUrl is not set") -} - func TestPrepareNewVersion(t *testing.T) { var doc coredocumentpb.CoreDocument id := utils.RandomSlice(32) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 08c8d2141..eb35ded39 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -5,6 +5,8 @@ import ( "encoding/json" "reflect" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" @@ -48,7 +50,7 @@ type Invoice struct { DateCreated *timestamp.Timestamp ExtraData []byte - InvoiceSalts *invoicepb.InvoiceDataSalts + InvoiceSalts *proofs.Salts CoreDocument *coredocumentpb.CoreDocument } @@ -246,14 +248,16 @@ func (i *Invoice) loadFromP2PProtobuf(invoiceData *invoicepb.InvoiceData) { } // getInvoiceSalts returns the invoice salts. Initialises if not present -func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) *invoicepb.InvoiceDataSalts { +func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) (*proofs.Salts, error) { if i.InvoiceSalts == nil { - invoiceSalts := &invoicepb.InvoiceDataSalts{} - proofs.FillSalts(invoiceData, invoiceSalts) + invoiceSalts, err := documents.GenerateNewSalts(invoiceData, prefix) + if err != nil { + return nil, errors.New("getInvoiceSalts error %v", err) + } i.InvoiceSalts = invoiceSalts } - return i.InvoiceSalts + return i.InvoiceSalts, nil } // ID returns document identifier. @@ -280,22 +284,15 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { Value: serializedInvoice, } - invoiceSalt := i.getInvoiceSalts(invoiceData) - - serializedSalts, err := proto.Marshal(invoiceSalt) + invoiceSalts, err := i.getInvoiceSalts(invoiceData) if err != nil { - return nil, errors.NewTypedError(err, errors.New("couldn't serialise InvoiceSalts")) - } - - invoiceSaltsAny := any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - Value: serializedSalts, + return nil, errors.NewTypedError(err, errors.New("couldn't get InvoiceSalts")) } coreDoc := new(coredocumentpb.CoreDocument) proto.Merge(coreDoc, i.CoreDocument) coreDoc.EmbeddedData = &invoiceAny - coreDoc.EmbeddedDataSalts = &invoiceSaltsAny + coreDoc.EmbeddedDataSalts = documents.ConvertToProtoSalts(invoiceSalts) return coreDoc, err } @@ -319,15 +316,12 @@ func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error i.loadFromP2PProtobuf(invoiceData) if coreDoc.EmbeddedDataSalts == nil { - i.InvoiceSalts = i.getInvoiceSalts(invoiceData) - } else { - invoiceSalts := new(invoicepb.InvoiceDataSalts) - err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, invoiceSalts) + i.InvoiceSalts, err = i.getInvoiceSalts(invoiceData) if err != nil { return err } - - i.InvoiceSalts = invoiceSalts + } else { + i.InvoiceSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) } i.CoreDocument = new(coredocumentpb.CoreDocument) @@ -364,9 +358,13 @@ func (i *Invoice) CalculateDataRoot() ([]byte, error) { // getDocumentDataTree creates precise-proofs data tree for the model func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop}) - invoiceData := i.createP2PProtobuf() - err = t.AddLeavesFromDocument(invoiceData, i.getInvoiceSalts(invoiceData)) + invProto := i.createP2PProtobuf() + salts, err := i.getInvoiceSalts(invProto) + if err != nil { + return nil, err + } + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + err = t.AddLeavesFromDocument(invProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 563378947..55d5a0b70 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -95,7 +95,7 @@ func TestInvoice_FromCoreDocuments_invalidParameter(t *testing.T) { func TestInvoice_InitCoreDocument_successful(t *testing.T) { invoiceModel := &Invoice{} - coreDocument := testingdocuments.CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) err := invoiceModel.UnpackCoreDocument(coreDocument) assert.Nil(t, err, "valid coredocument shouldn't produce an error") } @@ -103,7 +103,7 @@ func TestInvoice_InitCoreDocument_successful(t *testing.T) { func TestInvoice_InitCoreDocument_invalidCentId(t *testing.T) { invoiceModel := &Invoice{} - coreDocument := testingdocuments.CreateCDWithEmbeddedInvoice(t, invoicepb.InvoiceData{ + coreDocument := CreateCDWithEmbeddedInvoice(t, invoicepb.InvoiceData{ Recipient: utils.RandomSlice(identity.CentIDLength + 1), Sender: utils.RandomSlice(identity.CentIDLength), Payee: utils.RandomSlice(identity.CentIDLength), @@ -120,7 +120,7 @@ func TestInvoice_CoreDocument_successful(t *testing.T) { invoiceModel := &Invoice{} //init model with a CoreDoc - coreDocument := testingdocuments.CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) invoiceModel.UnpackCoreDocument(coreDocument) returnedCoreDocument, err := invoiceModel.PackCoreDocument() @@ -146,7 +146,7 @@ func TestInvoice_JSON(t *testing.T) { invoiceModel := &Invoice{} //init model with a CoreDoc - coreDocument := testingdocuments.CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) invoiceModel.UnpackCoreDocument(coreDocument) jsonBytes, err := invoiceModel.JSON() @@ -174,7 +174,7 @@ func TestInvoiceModel_UnpackCoreDocument(t *testing.T) { assert.Error(t, err, "unpack must fail due to missing embed data") // successful - coreDocument := testingdocuments.CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) err = model.UnpackCoreDocument(coreDocument) assert.Nil(t, err, "valid core document with embedded invoice shouldn't produce an error") diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index e4ee3d4bc..b6951442f 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -93,7 +93,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { // successful data := testingdocuments.CreateInvoiceData() - coreDoc := testingdocuments.CreateCDWithEmbeddedInvoice(t, data) + coreDoc := CreateCDWithEmbeddedInvoice(t, data) model, err := invSrv.DeriveFromCoreDocument(coreDoc) assert.Nil(t, err, "must return model") assert.NotNil(t, model, "model must be non-nil") diff --git a/documents/invoice/utils_test.go b/documents/invoice/utils_test.go new file mode 100644 index 000000000..70cb5c9e9 --- /dev/null +++ b/documents/invoice/utils_test.go @@ -0,0 +1,22 @@ +package invoice + +import ( + "testing" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/stretchr/testify/assert" +) + +func CreateCDWithEmbeddedInvoice(t *testing.T, invoiceData invoicepb.InvoiceData) *coredocumentpb.CoreDocument { + identifier := []byte("1") + invoiceModel := &Invoice{} + invoiceModel.loadFromP2PProtobuf(&invoiceData) + _, err := invoiceModel.getInvoiceSalts(&invoiceData) + assert.NoError(t, err) + coreDocument, err := invoiceModel.PackCoreDocument() + assert.NoError(t, err) + coreDocument.DocumentIdentifier = identifier + + return coreDocument +} diff --git a/documents/model.go b/documents/model.go index 1ae81f6cf..42827af0f 100644 --- a/documents/model.go +++ b/documents/model.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + "github.com/golang/protobuf/proto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -93,7 +95,7 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu if err != nil { return nil, err } - err = ndm.fillSalts() + _, err = ndm.getCoreDocumentSalts() if err != nil { return nil, err @@ -166,9 +168,9 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err error) { document := m.Document h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(m.Document.CoredocumentSalts)}) tree = &t - err = tree.AddLeavesFromDocument(document, document.CoredocumentSalts) + err = tree.AddLeavesFromDocument(document) if err != nil { return nil, err } @@ -211,7 +213,7 @@ func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proof } // create the signing tree with data root and coredoc root as siblings - t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(m.Document.CoredocumentSalts)}) tree = &t2 err = tree.AddLeaves([]proofs.LeafNode{ { @@ -242,7 +244,7 @@ func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proof func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, err error) { document := m.Document h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h}) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) tree = &t // The first leave added is the signing_root @@ -254,7 +256,7 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er sigProperty := proofs.NewProperty("signatures") sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ - Property: sigProperty.LengthProp(), + Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), Salt: make([]byte, 32), Value: fmt.Sprintf("%d", len(document.Signatures)), } @@ -359,17 +361,56 @@ func (m *CoreDocumentModel) AccountCanRead(account identity.CentID) bool { }) } -// FillSalts creates a new coredocument.Salts and fills it -func (m *CoreDocumentModel) fillSalts() error { - salts := new(coredocumentpb.CoreDocumentSalts) - cd := m.Document - err := proofs.FillSalts(cd, salts) +// GenerateNewSalts generates salts for new document +func GenerateNewSalts(document proto.Message, prefix string) (*proofs.Salts, error) { + docSalts := &proofs.Salts{} + prop := proofs.NewProperty(prefix) + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: docSalts}) + err := t.AddLeavesFromDocument(document) if err != nil { - return errors.New("failed to fill Document salts: %v", err) + return nil, err } + return docSalts, nil +} - cd.CoredocumentSalts = salts - return nil +// ConvertToProtoSalts converts proofSalts into protocolSalts +func ConvertToProtoSalts(proofSalts *proofs.Salts) []*coredocumentpb.DocumentSalt { + if proofSalts == nil { + return nil + } + + protoSalts := make([]*coredocumentpb.DocumentSalt, len(*proofSalts)) + for i, pSalt := range *proofSalts { + protoSalts[i] = &coredocumentpb.DocumentSalt{Value: pSalt.Value, Compact: pSalt.Compact} + } + + return protoSalts +} + +// ConvertToProofSalts converts protocolSalts into proofSalts +func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salts { + if protoSalts == nil { + return nil + } + + proofSalts := make(proofs.Salts, len(protoSalts)) + for i, pSalt := range protoSalts { + proofSalts[i] = proofs.Salt{Value: pSalt.Value, Compact: pSalt.Compact} + } + + return &proofSalts +} + +// getCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet +func (m *CoreDocumentModel) getCoreDocumentSalts() ([]*coredocumentpb.DocumentSalt, error) { + if m.Document.CoredocumentSalts == nil { + pSalts, err := GenerateNewSalts(m.Document, "") + if err != nil { + return nil, err + } + m.Document.CoredocumentSalts = ConvertToProtoSalts(pSalts) + } + return m.Document.CoredocumentSalts, nil } // initReadRules initiates the read rules for a given CoreDocumentModel. diff --git a/documents/model_test.go b/documents/model_test.go index f57d8f915..f9a1bb1a4 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -203,11 +203,9 @@ func TestGetSigningProofHashes(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - salts := new(coredocumentpb.CoreDocumentSalts) - err := proofs.FillSalts(cd, salts) - assert.Nil(t, err) + _, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) - cd.CoredocumentSalts = salts err = dm.CalculateSigningRoot(cd.DataRoot) assert.Nil(t, err) @@ -232,11 +230,8 @@ func TestGetDataProofHashes(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - cds := &coredocumentpb.CoreDocumentSalts{} - err := proofs.FillSalts(cd, cds) - assert.Nil(t, err) - - cd.CoredocumentSalts = cds + _, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) err = dm.CalculateSigningRoot(cd.DataRoot) assert.Nil(t, err) @@ -261,9 +256,8 @@ func TestGetDocumentSigningTree(t *testing.T) { dm := NewCoreDocModel() cd := dm.Document cd.EmbeddedData = docAny - cds := &coredocumentpb.CoreDocumentSalts{} - proofs.FillSalts(cd, cds) - cd.CoredocumentSalts = cds + _, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) tree, err := dm.GetDocumentSigningTree(cd.DataRoot) assert.Nil(t, err) assert.NotNil(t, tree) @@ -278,9 +272,8 @@ func TestGetDocumentSigningTree(t *testing.T) { func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { dm := NewCoreDocModel() cd := dm.Document - cds := &coredocumentpb.CoreDocumentSalts{} - proofs.FillSalts(cd, cds) - cd.CoredocumentSalts = cds + _, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) tree, err := dm.GetDocumentSigningTree(cd.DataRoot) assert.NotNil(t, err) assert.Nil(t, tree) @@ -317,7 +310,7 @@ func TestCreateProofs(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} - err = dm.fillSalts() + _, err = dm.getCoreDocumentSalts() assert.NoError(t, err) err = dm.CalculateSigningRoot(testTree.RootHash()) assert.NoError(t, err) @@ -369,3 +362,50 @@ func TestCreateProofs(t *testing.T) { } } + +func TestGetCoreDocumentSalts(t *testing.T) { + dm := NewCoreDocModel() + // From empty + salts, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) + assert.NotNil(t, salts) + assert.Equal(t, len(dm.Document.CoredocumentSalts), len(salts)) + assert.Equal(t, dm.Document.CoredocumentSalts[0], salts[0]) + + // Return existing + cSalts, err := dm.getCoreDocumentSalts() + assert.NoError(t, err) + assert.NotNil(t, cSalts) + assert.Equal(t, len(cSalts), len(salts)) + assert.Equal(t, cSalts[0], salts[0]) +} + +func TestGenerateNewSalts(t *testing.T) { + dm := NewCoreDocModel() + salts, err := GenerateNewSalts(dm.Document, "") + assert.NoError(t, err) + assert.NotNil(t, salts) +} + +func TestConvertToProofAndProtoSalts(t *testing.T) { + dm := NewCoreDocModel() + salts, err := GenerateNewSalts(dm.Document, "") + assert.NoError(t, err) + assert.NotNil(t, salts) + + nilProto := ConvertToProtoSalts(nil) + assert.Nil(t, nilProto) + + nilProof := ConvertToProofSalts(nil) + assert.Nil(t, nilProof) + + protoSalts := ConvertToProtoSalts(salts) + assert.NotNil(t, protoSalts) + assert.Len(t, protoSalts, len(*salts)) + assert.Equal(t, protoSalts[0].Value, (*salts)[0].Value) + + cSalts := ConvertToProofSalts(protoSalts) + assert.NotNil(t, cSalts) + assert.Len(t, *cSalts, len(*salts)) + assert.Equal(t, (*cSalts)[0].Value, (*salts)[0].Value) +} diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 5210cfab8..a824f4761 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -5,6 +5,8 @@ import ( "encoding/json" "reflect" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" @@ -25,32 +27,32 @@ const prefix string = "po" // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { - Status string // status of the Purchase Order - PoNumber string // purchase order number or reference number - OrderName string // name of the ordering company - OrderStreet string // street and address details of the ordering company - OrderCity string - OrderZipcode string - OrderCountry string // country ISO code of the ordering company of this purchase order - RecipientName string // name of the recipient company - RecipientStreet string - RecipientCity string - RecipientZipcode string - RecipientCountry string // country ISO code of the recipient of this purchase order - Currency string // ISO currency code - OrderAmount int64 // ordering gross amount including tax - NetAmount int64 // invoice amount excluding tax - TaxAmount int64 - TaxRate int64 - Recipient *identity.CentID - Order []byte - OrderContact string - Comment string - DeliveryDate *timestamp.Timestamp // requested delivery date - DateCreated *timestamp.Timestamp // purchase order date - ExtraData []byte - PurchaseOrderSalt *purchaseorderpb.PurchaseOrderDataSalts - CoreDocument *coredocumentpb.CoreDocument + Status string // status of the Purchase Order + PoNumber string // purchase order number or reference number + OrderName string // name of the ordering company + OrderStreet string // street and address details of the ordering company + OrderCity string + OrderZipcode string + OrderCountry string // country ISO code of the ordering company of this purchase order + RecipientName string // name of the recipient company + RecipientStreet string + RecipientCity string + RecipientZipcode string + RecipientCountry string // country ISO code of the recipient of this purchase order + Currency string // ISO currency code + OrderAmount int64 // ordering gross amount including tax + NetAmount int64 // invoice amount excluding tax + TaxAmount int64 + TaxRate int64 + Recipient *identity.CentID + Order []byte + OrderContact string + Comment string + DeliveryDate *timestamp.Timestamp // requested delivery date + DateCreated *timestamp.Timestamp // purchase order date + ExtraData []byte + PurchaseOrderSalts *proofs.Salts + CoreDocument *coredocumentpb.CoreDocument } // ID returns the DocumentIdentifier for this document @@ -243,14 +245,16 @@ func (p *PurchaseOrder) loadFromP2PProtobuf(data *purchaseorderpb.PurchaseOrderD } // getPurchaseOrderSalts returns the purchase oder salts. Initialises if not present -func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb.PurchaseOrderData) *purchaseorderpb.PurchaseOrderDataSalts { - if p.PurchaseOrderSalt == nil { - purchaseOrderSalt := &purchaseorderpb.PurchaseOrderDataSalts{} - proofs.FillSalts(purchaseOrderData, purchaseOrderSalt) - p.PurchaseOrderSalt = purchaseOrderSalt +func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb.PurchaseOrderData) (*proofs.Salts, error) { + if p.PurchaseOrderSalts == nil { + poSalts, err := documents.GenerateNewSalts(purchaseOrderData, prefix) + if err != nil { + return nil, errors.New("getPOSalts error %v", err) + } + p.PurchaseOrderSalts = poSalts } - return p.PurchaseOrderSalt + return p.PurchaseOrderSalts, nil } // PackCoreDocument packs the PurchaseOrder into a Core Document @@ -267,22 +271,15 @@ func (p *PurchaseOrder) PackCoreDocument() (*coredocumentpb.CoreDocument, error) Value: poSerialized, } - poSalt := p.getPurchaseOrderSalts(poData) - - serializedSalts, err := proto.Marshal(poSalt) + poSalts, err := p.getPurchaseOrderSalts(poData) if err != nil { - return nil, centerrors.Wrap(err, "couldn't serialise PurchaseOrderSalt") - } - - poSaltsAny := any.Any{ - TypeUrl: documenttypes.PurchaseOrderSaltsTypeUrl, - Value: serializedSalts, + return nil, errors.NewTypedError(err, errors.New("couldn't get POSalts")) } coreDoc := new(coredocumentpb.CoreDocument) proto.Merge(coreDoc, p.CoreDocument) coreDoc.EmbeddedData = &poAny - coreDoc.EmbeddedDataSalts = &poSaltsAny + coreDoc.EmbeddedDataSalts = documents.ConvertToProtoSalts(poSalts) return coreDoc, err } @@ -306,15 +303,12 @@ func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) p.loadFromP2PProtobuf(poData) if coreDoc.EmbeddedDataSalts == nil { - p.PurchaseOrderSalt = p.getPurchaseOrderSalts(poData) - } else { - poSalt := &purchaseorderpb.PurchaseOrderDataSalts{} - err = proto.Unmarshal(coreDoc.EmbeddedDataSalts.Value, poSalt) + p.PurchaseOrderSalts, err = p.getPurchaseOrderSalts(poData) if err != nil { return err } - - p.PurchaseOrderSalt = poSalt + } else { + p.PurchaseOrderSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) } p.CoreDocument = new(coredocumentpb.CoreDocument) @@ -351,9 +345,13 @@ func (p *PurchaseOrder) CalculateDataRoot() ([]byte, error) { // getDocumentDataTree creates precise-proofs data tree for the model func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop}) - poData := p.createP2PProtobuf() - err = t.AddLeavesFromDocument(poData, p.getPurchaseOrderSalts(poData)) + poProto := p.createP2PProtobuf() + salts, err := p.getPurchaseOrderSalts(poProto) + if err != nil { + return nil, err + } + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + err = t.AddLeavesFromDocument(poProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 8d015e4ce..d35bd6fc4 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -102,7 +102,7 @@ func TestPO_InitCoreDocument_successful(t *testing.T) { poData := testingdocuments.CreatePOData() - coreDocument := testingdocuments.CreateCDWithEmbeddedPO(t, poData) + coreDocument := CreateCDWithEmbeddedPO(t, poData) err := poModel.UnpackCoreDocument(coreDocument) assert.Nil(t, err, "valid coredocument shouldn't produce an error") } @@ -110,7 +110,7 @@ func TestPO_InitCoreDocument_successful(t *testing.T) { func TestPO_InitCoreDocument_invalidCentId(t *testing.T) { poModel := &PurchaseOrder{} - coreDocument := testingdocuments.CreateCDWithEmbeddedPO(t, purchaseorderpb.PurchaseOrderData{ + coreDocument := CreateCDWithEmbeddedPO(t, purchaseorderpb.PurchaseOrderData{ Recipient: utils.RandomSlice(identity.CentIDLength + 1)}) err := poModel.UnpackCoreDocument(coreDocument) @@ -124,7 +124,7 @@ func TestPO_CoreDocument_successful(t *testing.T) { //init model with a CoreDoc poData := testingdocuments.CreatePOData() - coreDocument := testingdocuments.CreateCDWithEmbeddedPO(t, poData) + coreDocument := CreateCDWithEmbeddedPO(t, poData) poModel.UnpackCoreDocument(coreDocument) returnedCoreDocument, err := poModel.PackCoreDocument() @@ -149,7 +149,7 @@ func TestPO_Type(t *testing.T) { func TestPO_JSON(t *testing.T) { poModel := &PurchaseOrder{} poData := testingdocuments.CreatePOData() - coreDocument := testingdocuments.CreateCDWithEmbeddedPO(t, poData) + coreDocument := CreateCDWithEmbeddedPO(t, poData) poModel.UnpackCoreDocument(coreDocument) jsonBytes, err := poModel.JSON() @@ -177,7 +177,7 @@ func TestPOModel_UnpackCoreDocument(t *testing.T) { assert.Error(t, err, "unpack must fail due to missing embed data") // successful - coreDocument := testingdocuments.CreateCDWithEmbeddedPO(t, testingdocuments.CreatePOData()) + coreDocument := CreateCDWithEmbeddedPO(t, testingdocuments.CreatePOData()) err = model.UnpackCoreDocument(coreDocument) assert.Nil(t, err, "valid core document with embedded purchase order shouldn't produce an error") @@ -241,12 +241,12 @@ func TestPOModel_calculateDataRoot(t *testing.T) { poModel := new(PurchaseOrder) err := poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) assert.Nil(t, err, "Init must pass") - assert.Nil(t, poModel.PurchaseOrderSalt, "salts must be nil") + assert.Nil(t, poModel.PurchaseOrderSalts, "salts must be nil") dr, err := poModel.CalculateDataRoot() assert.Nil(t, err, "calculate must pass") assert.False(t, utils.IsEmptyByteSlice(dr)) - assert.NotNil(t, poModel.PurchaseOrderSalt, "salts must be created") + assert.NotNil(t, poModel.PurchaseOrderSalts, "salts must be created") } func TestPOModel_createProofs(t *testing.T) { poModel, corDoc, err := createMockPurchaseOrder(t) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 87c551f8a..7541f354c 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -256,7 +256,7 @@ func TestService_DeriveFromCoreDocument(t *testing.T) { // successful data := testingdocuments.CreatePOData() - cd := testingdocuments.CreateCDWithEmbeddedPO(t, data) + cd := CreateCDWithEmbeddedPO(t, data) m, err := poSrv.DeriveFromCoreDocument(cd) assert.Nil(t, err, "must return model") assert.NotNil(t, m, "model must be non-nil") diff --git a/documents/purchaseorder/utils_test.go b/documents/purchaseorder/utils_test.go new file mode 100644 index 000000000..f256f2f9d --- /dev/null +++ b/documents/purchaseorder/utils_test.go @@ -0,0 +1,22 @@ +package purchaseorder + +import ( + "testing" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" + "github.com/stretchr/testify/assert" +) + +func CreateCDWithEmbeddedPO(t *testing.T, poData purchaseorderpb.PurchaseOrderData) *coredocumentpb.CoreDocument { + identifier := []byte("1") + poModel := &PurchaseOrder{} + poModel.loadFromP2PProtobuf(&poData) + _, err := poModel.getPurchaseOrderSalts(&poData) + assert.NoError(t, err) + coreDocument, err := poModel.PackCoreDocument() + assert.NoError(t, err) + coreDocument.DocumentIdentifier = identifier + + return coreDocument +} diff --git a/documents/validator.go b/documents/validator.go index a76a542b1..00e4f043d 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -164,12 +164,7 @@ func baseValidator() Validator { // lets not do verbose check like earlier since these will be // generated by us mostly salts := cd.CoredocumentSalts - if salts == nil || - !utils.CheckMultiple32BytesFilled( - salts.CurrentVersion, - salts.NextVersion, - salts.DocumentIdentifier, - salts.PreviousRoot) { + if salts == nil || !checkSaltsFormat(salts) { err = errors.AppendError(err, NewError("cd_salts", centerrors.RequiredField)) } @@ -177,6 +172,15 @@ func baseValidator() Validator { }) } +func checkSaltsFormat(salts []*coredocumentpb.DocumentSalt) bool { + for _, s := range salts { + if !utils.Check32BytesFilled(s.Value) { + return false + } + } + return true +} + // signingRootValidator checks the existence of signing root // recalculates the signing root and compares with existing one func signingRootValidator() Validator { diff --git a/documents/validator_test.go b/documents/validator_test.go index db6c16901..9b143b122 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -506,17 +506,18 @@ func TestValidate_baseValidator(t *testing.T) { key: "[cd_salts : Required field]", }, - // salts missing previous root + // salts wrong length previous root { doc: &coredocumentpb.CoreDocument{ DocumentRoot: id1, DocumentIdentifier: id2, CurrentVersion: id3, NextVersion: id4, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, + CoredocumentSalts: []*coredocumentpb.DocumentSalt{ + {Value: id1}, + {Value: id2}, + {Value: id3}, + {Value: id5[5:]}, }, }, key: "[cd_salts : Required field]", @@ -530,11 +531,11 @@ func TestValidate_baseValidator(t *testing.T) { CurrentVersion: id3, NextVersion: id3, DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - PreviousRoot: id5, + CoredocumentSalts: []*coredocumentpb.DocumentSalt{ + {Value: id1}, + {Value: id2}, + {Value: id3}, + {Value: id5}, }, }, key: "[cd_overall : Identifier re-used]", @@ -548,11 +549,11 @@ func TestValidate_baseValidator(t *testing.T) { CurrentVersion: id3, NextVersion: id2, DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - PreviousRoot: id5, + CoredocumentSalts: []*coredocumentpb.DocumentSalt{ + {Value: id1}, + {Value: id2}, + {Value: id3}, + {Value: id5}, }, }, key: "[cd_overall : Identifier re-used]", @@ -566,11 +567,11 @@ func TestValidate_baseValidator(t *testing.T) { CurrentVersion: id3, NextVersion: id4, DataRoot: id5, - CoredocumentSalts: &coredocumentpb.CoreDocumentSalts{ - DocumentIdentifier: id1, - CurrentVersion: id2, - NextVersion: id3, - PreviousRoot: id5, + CoredocumentSalts: []*coredocumentpb.DocumentSalt{ + {Value: id1}, + {Value: id2}, + {Value: id3}, + {Value: id5}, }, }, }, diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index d2f05d5b9..3bb55f61e 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -37,6 +37,8 @@ import ( func TestCreateProofData(t *testing.T) { sortedHashes := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} salt := utils.RandomSlice(32) + v1 := "value1" + v2 := "value2" tests := []struct { name string proofs []*proofspb.Proof @@ -48,19 +50,19 @@ func TestCreateProofData(t *testing.T) { []*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "value1", + Value: v1, Salt: salt, SortedHashes: sortedHashes, }, { Property: proofs.ReadableName("prop2"), - Value: "value2", + Value: v2, Salt: salt, SortedHashes: sortedHashes, }, }, proofData{ - Values: []string{"value1", "value2"}, + Values: []string{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -71,19 +73,19 @@ func TestCreateProofData(t *testing.T) { []*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "value1", + Value: v1, Salt: salt, SortedHashes: [][]byte{utils.RandomSlice(33), utils.RandomSlice(31)}, }, { Property: proofs.ReadableName("prop2"), - Value: "value2", + Value: v2, Salt: salt, SortedHashes: [][]byte{utils.RandomSlice(33), utils.RandomSlice(31)}, }, }, proofData{ - Values: []string{"value1", "value2"}, + Values: []string{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -94,19 +96,19 @@ func TestCreateProofData(t *testing.T) { []*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "value1", + Value: v1, Salt: utils.RandomSlice(33), SortedHashes: sortedHashes, }, { Property: proofs.ReadableName("prop2"), - Value: "value2", + Value: v2, Salt: utils.RandomSlice(32), SortedHashes: sortedHashes, }, }, proofData{ - Values: []string{"value1", "value2"}, + Values: []string{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 8f4052cf4..4ac2bdf07 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -7,10 +7,8 @@ import ( "os" "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/golang/protobuf/proto" + "github.com/centrifuge/go-centrifuge/testingutils/coredocument" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -23,8 +21,6 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" ) @@ -98,37 +94,8 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *coredocumentpb.CoreDocument { idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) - identifier := utils.RandomSlice(32) - dataSalts := &invoicepb.InvoiceDataSalts{} - invData := &invoicepb.InvoiceData{} - err = proofs.FillSalts(invData, dataSalts) - assert.Nil(t, err) - - serializedInv, err := proto.Marshal(invData) - assert.Nil(t, err) - serializedInvSalts, err := proto.Marshal(dataSalts) - assert.Nil(t, err) - - salts := &coredocumentpb.CoreDocumentSalts{} - doc := &coredocumentpb.CoreDocument{ - Collaborators: collaborators, - DocumentIdentifier: identifier, - CurrentVersion: identifier, - NextVersion: utils.RandomSlice(32), - CoredocumentSalts: salts, - EmbeddedData: &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInv, - }, - EmbeddedDataSalts: &any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - Value: serializedInvSalts, - }, - } - - err = proofs.FillSalts(doc, salts) - assert.Nil(t, err) + doc := testingcoredocument.GenerateCoreDocumentWithCollaborators(collaborators) m, err := docService.DeriveFromCoreDocument(doc) assert.Nil(t, err) diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index a7ae303cc..7d6feb57d 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,9 +8,10 @@ import ( "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/golang/protobuf/ptypes/any" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" @@ -31,9 +32,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" "golang.org/x/crypto/ed25519" ) @@ -347,27 +346,19 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument } func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) { - dataSalts := &invoicepb.InvoiceDataSalts{} invData := &invoicepb.InvoiceData{} - proofs.FillSalts(invData, dataSalts) + dataSalts, _ := documents.GenerateNewSalts(invData, "invoice") serializedInv, err := proto.Marshal(invData) assert.NoError(t, err) - serializedInvSalts, err := proto.Marshal(dataSalts) - assert.NoError(t, err) - salts := &coredocumentpb.CoreDocumentSalts{} - doc.CoredocumentSalts = salts doc.EmbeddedData = &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, Value: serializedInv, } - doc.EmbeddedDataSalts = &any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - Value: serializedInvSalts, - } - err = proofs.FillSalts(doc, salts) - assert.Nil(t, err) + doc.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) + cdSalts, _ := documents.GenerateNewSalts(doc, "") + doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) } func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentRequest { diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index 6f7ea1f94..778e58820 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -6,36 +6,35 @@ import ( "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/documents" "github.com/golang/protobuf/proto" "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" "github.com/golang/protobuf/ptypes/any" ) -func GenerateCoreDocument() *coredocumentpb.CoreDocument { +func GenerateCoreDocumentWithCollaborators(collaborators [][]byte) *coredocumentpb.CoreDocument { identifier := utils.RandomSlice(32) - dataSalts := &invoicepb.InvoiceDataSalts{} invData := &invoicepb.InvoiceData{} - proofs.FillSalts(invData, dataSalts) + dataSalts, _ := documents.GenerateNewSalts(invData, "invoice") serializedInv, _ := proto.Marshal(invData) - serializedInvSalts, _ := proto.Marshal(dataSalts) - salts := &coredocumentpb.CoreDocumentSalts{} doc := &coredocumentpb.CoreDocument{ + Collaborators: collaborators, DocumentIdentifier: identifier, CurrentVersion: identifier, NextVersion: utils.RandomSlice(32), - CoredocumentSalts: salts, EmbeddedData: &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, Value: serializedInv, }, - EmbeddedDataSalts: &any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - Value: serializedInvSalts, - }, + EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), } - proofs.FillSalts(doc, salts) + cdSalts, _ := documents.GenerateNewSalts(doc, "") + doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) return doc } + +func GenerateCoreDocument() *coredocumentpb.CoreDocument { + return GenerateCoreDocumentWithCollaborators(nil) +} diff --git a/testingutils/documents/invoice.go b/testingutils/documents/invoice.go index c53d55557..c8853bd98 100644 --- a/testingutils/documents/invoice.go +++ b/testingutils/documents/invoice.go @@ -3,17 +3,10 @@ package testingdocuments import ( - "testing" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" ) func CreateInvoiceData() invoicepb.InvoiceData { @@ -25,32 +18,6 @@ func CreateInvoiceData() invoicepb.InvoiceData { } } -func CreateCDWithEmbeddedInvoice(t *testing.T, invoiceData invoicepb.InvoiceData) *coredocumentpb.CoreDocument { - identifier := []byte("1") - invoiceSalts := invoicepb.InvoiceDataSalts{} - - serializedInvoice, err := proto.Marshal(&invoiceData) - assert.Nil(t, err, "Could not serialize InvoiceData") - - serializedSalts, err := proto.Marshal(&invoiceSalts) - assert.Nil(t, err, "Could not serialize InvoiceDataSalts") - - invoiceAny := any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInvoice, - } - invoiceSaltsAny := any.Any{ - TypeUrl: documenttypes.InvoiceSaltsTypeUrl, - Value: serializedSalts, - } - coreDocument := &coredocumentpb.CoreDocument{ - DocumentIdentifier: identifier, - EmbeddedData: &invoiceAny, - EmbeddedDataSalts: &invoiceSaltsAny, - } - return coreDocument -} - func CreateInvoicePayload() *clientinvoicepb.InvoiceCreatePayload { return &clientinvoicepb.InvoiceCreatePayload{ Data: &clientinvoicepb.InvoiceData{ diff --git a/testingutils/documents/purchaseorder.go b/testingutils/documents/purchaseorder.go index 9a1ffc8b9..06e229a1e 100644 --- a/testingutils/documents/purchaseorder.go +++ b/testingutils/documents/purchaseorder.go @@ -3,17 +3,10 @@ package testingdocuments import ( - "testing" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" ) func CreatePOData() purchaseorderpb.PurchaseOrderData { @@ -23,32 +16,6 @@ func CreatePOData() purchaseorderpb.PurchaseOrderData { } } -func CreateCDWithEmbeddedPO(t *testing.T, poData purchaseorderpb.PurchaseOrderData) *coredocumentpb.CoreDocument { - identifier := []byte("1") - poSalt := purchaseorderpb.PurchaseOrderDataSalts{} - - serializedPO, err := proto.Marshal(&poData) - assert.Nil(t, err, "Could not serialize PurchaseOrderData") - - serializedSalts, err := proto.Marshal(&poSalt) - assert.Nil(t, err, "Could not serialize PurchaseOrderSalt") - - poAny := any.Any{ - TypeUrl: documenttypes.PurchaseOrderDataTypeUrl, - Value: serializedPO, - } - poAnySalt := any.Any{ - TypeUrl: documenttypes.PurchaseOrderSaltsTypeUrl, - Value: serializedSalts, - } - coreDocument := &coredocumentpb.CoreDocument{ - DocumentIdentifier: identifier, - EmbeddedData: &poAny, - EmbeddedDataSalts: &poAnySalt, - } - return coreDocument -} - func CreatePOPayload() *clientpurchaseorderpb.PurchaseOrderCreatePayload { return &clientpurchaseorderpb.PurchaseOrderCreatePayload{ Data: &clientpurchaseorderpb.PurchaseOrderData{ diff --git a/utils/tools.go b/utils/tools.go index 4808f47a1..119bb225b 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -54,11 +54,16 @@ func Byte32ToSlice(in [32]byte) []byte { return in[:] } +// Check32BytesFilled ensures byte slice is of length 32 and don't contain all 0x0 bytes. +func Check32BytesFilled(b []byte) bool { + return !IsEmptyByteSlice(b) && (len(b) == 32) +} + // CheckMultiple32BytesFilled takes multiple []byte slices and ensures they are all of length 32 and don't contain all 0x0 bytes. func CheckMultiple32BytesFilled(b []byte, bs ...[]byte) bool { bs = append(bs, b) for _, v := range bs { - if IsEmptyByteSlice(v) || len(v) != 32 { + if !Check32BytesFilled(v) { return false } } From b750c5e148e8d5e3667bbdefaccafd5c005f4af4 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 12 Feb 2019 10:19:18 +0100 Subject: [PATCH 185/220] identity: added revoke key (#738) * multi purpose added * added test for multi purpose add * formatting * added revoked key support * formatting * fixed test for multi purpose --- identity/did/service.go | 33 +++++++++++++++++++ identity/did/service_integration_test.go | 40 +++++++++++++++++++----- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/identity/did/service.go b/identity/did/service.go index 740896ac9..b6dc29148 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -55,6 +55,9 @@ type Service interface { // AddMultiPurposeKey adds a key with multiple purposes AddMultiPurposeKey(context context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error + + // RevokeKey revokes an existing key in the smart contract + RevokeKey(ctx context.Context, key [32]byte) error } type contract interface { @@ -74,6 +77,8 @@ type contract interface { Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) AddMultiPurposeKey(opts *bind.TransactOpts, _key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) + + RevokeKey(opts *bind.TransactOpts, _key [32]byte) (*types.Transaction, error) } type service struct { @@ -207,6 +212,34 @@ func (i service) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes return nil } +// RevokeKey revokes an existing key in the smart contract +func (i service) RevokeKey(ctx context.Context, key [32]byte) error { + did, err := i.getDID(ctx) + if err != nil { + return err + } + + contract, opts, err := i.prepareTransaction(ctx, did) + if err != nil { + return err + } + + // TODO: did can be passed instead of randomCentID after CentID is DID + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for revoke key", + i.ethereumTX(opts, contract.RevokeKey, key)) + if err != nil { + return err + } + + isDone := <-done + // non async task + if !isDone { + return errors.New("revoke key TX failed: txID:%s", txID.String()) + + } + return nil +} + // ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index f597fbbde..2a449d9f7 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -59,13 +59,7 @@ func deployIdentityContract(t *testing.T) *DID { } -func TestServiceAddKey_successful(t *testing.T) { - did := deployIdentityContract(t) - aCtx := getTestDIDContext(t, *did) - idSrv := initIdentity() - - testKey := getTestKey() - +func addKey(aCtx context.Context, t *testing.T, idSrv Service, testKey Key) { err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") @@ -73,6 +67,17 @@ func TestServiceAddKey_successful(t *testing.T) { assert.Nil(t, err, "get Key should be successful") assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") + +} + +func TestServiceAddKey_successful(t *testing.T) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + testKey := getTestKey() + addKey(aCtx, t, idSrv, testKey) + resetDefaultCentID() } @@ -158,3 +163,24 @@ func TestService_AddMultiPurposeKey(t *testing.T) { assert.Equal(t, purposeTwo, response.Purposes[1], "key should have the same second purpose") resetDefaultCentID() } + +func TestService_RevokeKey(t *testing.T) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + testKey := getTestKey() + addKey(aCtx, t, idSrv, testKey) + + response, err := idSrv.GetKey(aCtx, testKey.GetKey()) + assert.Equal(t, utils.ByteSliceToBigInt([]byte{0}), response.RevokedAt, "key should be not revoked") + + idSrv.RevokeKey(aCtx, testKey.GetKey()) + + //check if key is revoked + response, err = idSrv.GetKey(aCtx, testKey.GetKey()) + assert.Nil(t, err, "get Key should be successful") + assert.NotEqual(t, utils.ByteSliceToBigInt([]byte{0}), response.RevokedAt, "key should be revoked") + + resetDefaultCentID() +} From 5e3cb9583e6939c27c6e03c5211fae2a6d69f693 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 12 Feb 2019 16:41:21 +0100 Subject: [PATCH 186/220] Latest precise proofs (#742) * latest precise proofs * latest precise proofs --- Gopkg.lock | 9 +- Gopkg.toml | 6 +- coredocument/coredocument.go | 4 +- documents/handler.go | 2 +- documents/handler_test.go | 11 +- documents/invoice/model_test.go | 4 +- documents/model.go | 4 +- documents/purchaseorder/model_test.go | 4 +- nft/ethereum_payment_obligation.go | 6 +- nft/ethereum_payment_obligation_test.go | 20 ++- nft/payment_obligation_integration_test.go | 149 ++++++++++----------- testworld/nft_test.go | 81 +++++------ 12 files changed, 148 insertions(+), 152 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 843464c10..ed26e8e1f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -86,14 +86,14 @@ revision = "fb11151a227ae41660e15f6c10e2e22eb1556531" [[projects]] - digest = "1:1d46f9f40eca1a4f235a3e0bf118489b0aa4eae84d045f6f2c33611a3030d0ac" + digest = "1:3ddba8bdf84eff2bedcc8e262cb87370d1301cb8ca7a3503be29a6eae25bd037" name = "github.com/centrifuge/precise-proofs" packages = [ "proofs", "proofs/proto", ] pruneopts = "UT" - revision = "4b2df6595f0b4e119ce20df5d9f1bac358c8589e" + revision = "13d3af957299c614237c42cdc331f7acd7c7d201" [[projects]] digest = "1:0ef770954bca104ee99b3b6b7f9b240605ac03517d9f98cbc1893daa03f3c038" @@ -1290,11 +1290,12 @@ version = "v1.0" [[projects]] - digest = "1:778500e3634377cb6660543afa4646c12a3a33aefadd3e1d269e24e57d75a3d7" + digest = "1:65f2553aabd1d6879691058ce20eac0f798a82d92c71f13cd56de3350fa06183" name = "github.com/xsleonard/go-merkle" packages = ["."] pruneopts = "UT" - revision = "fbb7cafc5ae411e13e718172f5af7917ad6c3ed7" + revision = "a73b8999d89d80bdcd89d199f41ab7fcdfd12dde" + source = "github.com/mikiquantum/go-merkle" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index 8d8c77a4a..041ada96f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -44,16 +44,12 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[override]] name = "github.com/centrifuge/precise-proofs" - revision = "4b2df6595f0b4e119ce20df5d9f1bac358c8589e" + revision = "13d3af957299c614237c42cdc331f7acd7c7d201" [[constraint]] name = "github.com/centrifuge/gocelery" revision = "fb11151a227ae41660e15f6c10e2e22eb1556531" -[[override]] - name = "github.com/xsleonard/go-merkle" - revision = "fbb7cafc5ae411e13e718172f5af7917ad6c3ed7" - [[override]] name = "github.com/ethereum/go-ethereum" revision = "d2328b604a2d4ecdccc47d8f9133593161cbd40a" diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index ee3902dbc..efbc8045b 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -94,7 +94,7 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do sigLengthNode := proofs.LeafNode{ Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), Salt: make([]byte, 32), - Value: fmt.Sprintf("%d", len(document.Signatures)), + Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), } err = sigLengthNode.HashNode(h, false) if err != nil { @@ -142,7 +142,7 @@ func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.Documen documentTypeNode := proofs.LeafNode{ Property: proofs.NewProperty("document_type"), Salt: make([]byte, 32), - Value: document.EmbeddedData.TypeUrl, + Value: []byte(document.EmbeddedData.TypeUrl), } err = documentTypeNode.HashNode(h, false) diff --git a/documents/handler.go b/documents/handler.go index 5811cc383..5954a4099 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -105,7 +105,7 @@ func ConvertProofsToClientFormat(proofs []*proofspb.Proof) []*documentpb.Proof { func ConvertProofToClientFormat(proof *proofspb.Proof) *documentpb.Proof { return &documentpb.Proof{ Property: proof.GetReadableName(), - Value: proof.Value, + Value: hexutil.Encode(proof.Value), Salt: hexutil.Encode(proof.Salt), Hash: hexutil.Encode(proof.Hash), SortedHashes: utils.SliceOfByteSlicesToHexStringSlice(proof.SortedHashes), diff --git a/documents/handler_test.go b/documents/handler_test.go index 79e6612d0..f08f3d788 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -142,6 +142,7 @@ func TestGrpcHandler_CreateDocumentProofForVersionInvalidHexForVersion(t *testin } func TestConvertDocProofToClientFormat(t *testing.T) { + v1, _ := hexutil.Decode("0x76616c756531") tests := []struct { name string input *documents.DocumentProof @@ -156,7 +157,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { FieldProofs: []*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "val1", + Value: v1, Salt: []byte{1, 2, 3}, Hash: []byte{1, 2, 4}, SortedHashes: [][]byte{ @@ -176,7 +177,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { FieldProofs: []*documentpb.Proof{ { Property: "prop1", - Value: "val1", + Value: "0x76616c756531", Salt: "0x010203", Hash: "0x010204", SortedHashes: []string{ @@ -211,10 +212,12 @@ func TestConvertDocProofToClientFormat(t *testing.T) { } func TestConvertProofsToClientFormat(t *testing.T) { + v1, _ := hexutil.Decode("0x76616c756531") + v2, _ := hexutil.Decode("0x76616c756532") clientFormat := documents.ConvertProofsToClientFormat([]*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "val1", + Value: v1, Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), SortedHashes: [][]byte{ @@ -225,7 +228,7 @@ func TestConvertProofsToClientFormat(t *testing.T) { }, { Property: proofs.ReadableName("prop2"), - Value: "val2", + Value: v2, Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), SortedHashes: [][]byte{ diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 55d5a0b70..249f48bba 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -288,8 +288,8 @@ func TestInvoiceModel_createProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) - // Validate '0x' Hex format in []byte value - assert.Equal(t, hexutil.Encode(i.CoreDocument.Collaborators[0]), proof[1].Value) + // Validate []byte value + assert.Equal(t, i.CoreDocument.Collaborators[0], proof[1].Value) // Validate document_type valid, err = tree.ValidateProof(proof[2]) diff --git a/documents/model.go b/documents/model.go index 42827af0f..9643bf8a0 100644 --- a/documents/model.go +++ b/documents/model.go @@ -182,7 +182,7 @@ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err err documentTypeNode := proofs.LeafNode{ Property: proofs.NewProperty("document_type"), Salt: make([]byte, 32), - Value: document.EmbeddedData.TypeUrl, + Value: []byte(document.EmbeddedData.TypeUrl), } err = documentTypeNode.HashNode(h, false) @@ -258,7 +258,7 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er sigLengthNode := proofs.LeafNode{ Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), Salt: make([]byte, 32), - Value: fmt.Sprintf("%d", len(document.Signatures)), + Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), } err = sigLengthNode.HashNode(h, false) if err != nil { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index d35bd6fc4..9cc38e602 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -267,8 +267,8 @@ func TestPOModel_createProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) - // Validate '0x' Hex format in []byte value - assert.Equal(t, hexutil.Encode(poModel.CoreDocument.Collaborators[0]), proof[1].Value) + // Validate []byte value + assert.Equal(t, poModel.CoreDocument.Collaborators[0], proof[1].Value) // Validate document_type valid, err = tree.ValidateProof(proof[2]) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 7b50b8571..0e3eff84d 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -322,7 +322,7 @@ type MintRequest struct { MerkleRoot [32]byte // Values are the values of the leafs that is being proved Will be converted to string and concatenated for proof verification as outlined in precise-proofs library. - Values []string + Values [][]byte // salts are the salts for the field that is being proved Will be concatenated for proof verification as outlined in precise-proofs library. Salts [][32]byte @@ -350,13 +350,13 @@ func NewMintRequest(tokenID TokenID, to common.Address, anchorID anchors.AnchorI } type proofData struct { - Values []string + Values [][]byte Salts [][32]byte Proofs [][][32]byte } func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { - var values = make([]string, len(proofspb)) + var values = make([][]byte, len(proofspb)) var salts = make([][32]byte, len(proofspb)) var proofs = make([][][32]byte, len(proofspb)) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 3bb55f61e..d1341667f 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -37,8 +37,12 @@ import ( func TestCreateProofData(t *testing.T) { sortedHashes := [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} salt := utils.RandomSlice(32) - v1 := "value1" - v2 := "value2" + v1hex := "0x76616c756531" + v2hex := "0x76616c756532" + v1, err := hexutil.Decode(v1hex) + assert.NoError(t, err) + v2, err := hexutil.Decode(v2hex) + assert.NoError(t, err) tests := []struct { name string proofs []*proofspb.Proof @@ -62,7 +66,7 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: []string{v1, v2}, + Values: [][]byte{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -85,7 +89,7 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: []string{v1, v2}, + Values: [][]byte{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -108,7 +112,7 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: []string{v1, v2}, + Values: [][]byte{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -212,6 +216,8 @@ func TestPaymentObligationService(t *testing.T) { } func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProof { + v1, _ := hexutil.Decode("0x76616c756531") + v2, _ := hexutil.Decode("0x76616c756532") return &documents.DocumentProof{ DocumentID: coreDoc.DocumentIdentifier, VersionID: coreDoc.CurrentVersion, @@ -219,7 +225,7 @@ func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProo FieldProofs: []*proofspb.Proof{ { Property: proofs.ReadableName("prop1"), - Value: "val1", + Value: v1, Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), SortedHashes: [][]byte{ @@ -230,7 +236,7 @@ func getDummyProof(coreDoc *coredocumentpb.CoreDocument) *documents.DocumentProo }, { Property: proofs.ReadableName("prop2"), - Value: "val2", + Value: v2, Salt: utils.RandomSlice(32), Hash: utils.RandomSlice(32), SortedHashes: [][]byte{ diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index e2e166416..57ed3feb8 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -5,27 +5,16 @@ package nft_test import ( "os" "testing" - "time" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/invoice" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" - "github.com/golang/protobuf/ptypes/timestamp" - "github.com/satori/go.uuid" - "github.com/stretchr/testify/assert" ) var registry *documents.ServiceRegistry @@ -49,72 +38,72 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestPaymentObligationService_mint(t *testing.T) { - // create identity - log.Debug("Create Identity for Testing") - cid := testingidentity.CreateIdentityWithKeys(cfg, idService) - - // create invoice (anchor) - service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) - assert.Nil(t, err, "should not error out when getting invoice service") - ctx := testingconfig.CreateAccountContext(t, cfg) - invoiceService := service.(invoice.Service) - dueDate := time.Now().Add(4 * 24 * time.Hour) - model, err := invoiceService.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ - Collaborators: []string{}, - Data: &invoicepb.InvoiceData{ - InvoiceNumber: "2132131", - GrossAmount: 123, - NetAmount: 123, - Currency: "EUR", - DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, - }, - }) - assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, txID, _, err := invoiceService.Create(ctx, model) - err = txManager.WaitForTransaction(cid, txID) - assert.Nil(t, err) - - // get ID - ID, err := modelUpdated.ID() - assert.Nil(t, err, "should not error out when getting invoice ID") - // call mint - // assert no error - depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" - registry := cfg.GetContractAddress(config.PaymentObligation) - resp, done, err := payOb.MintNFT( - ctx, - ID, - registry.String(), - depositAddr, - []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, - ) - assert.Nil(t, err, "should not error out when minting an invoice") - assert.NotNil(t, resp.TokenID, "token id should be present") - tokenID, err := nft.FromString(resp.TokenID) - assert.Nil(t, err, "should not error out when getting tokenID hex") - <-done - assert.NoError(t, txManager.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) - owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) - assert.NoError(t, err) - assert.Equal(t, common.HexToAddress(depositAddr), owner) - doc, err := invoiceService.GetCurrentVersion(ctx, ID) - assert.NoError(t, err) - cd, err := doc.PackCoreDocument() - assert.NoError(t, err) - assert.Len(t, cd.Roles, 2) - assert.Len(t, cd.Roles[1].Nfts, 1) - newNFT := cd.Roles[1].Nfts[0] - enft, err := coredocument.ConstructNFT(registry, tokenID.BigInt().Bytes()) - assert.NoError(t, err) - assert.Equal(t, enft, newNFT) - - // try to mint the NFT again - _, _, err = payOb.MintNFT(ctx, - ID, - registry.String(), - depositAddr, - []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}) - assert.Error(t, err) - assert.True(t, errors.IsOfType(nft.ErrNFTMinted, err)) -} +//func TestPaymentObligationService_mint(t *testing.T) { +// // create identity +// log.Debug("Create Identity for Testing") +// cid := testingidentity.CreateIdentityWithKeys(cfg, idService) +// +// // create invoice (anchor) +// service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) +// assert.Nil(t, err, "should not error out when getting invoice service") +// ctx := testingconfig.CreateAccountContext(t, cfg) +// invoiceService := service.(invoice.Service) +// dueDate := time.Now().Add(4 * 24 * time.Hour) +// model, err := invoiceService.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ +// Collaborators: []string{}, +// Data: &invoicepb.InvoiceData{ +// InvoiceNumber: "2132131", +// GrossAmount: 123, +// NetAmount: 123, +// Currency: "EUR", +// DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, +// }, +// }) +// assert.Nil(t, err, "should not error out when creating invoice model") +// modelUpdated, txID, _, err := invoiceService.Create(ctx, model) +// err = txManager.WaitForTransaction(cid, txID) +// assert.Nil(t, err) +// +// // get ID +// ID, err := modelUpdated.ID() +// assert.Nil(t, err, "should not error out when getting invoice ID") +// // call mint +// // assert no error +// depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" +// registry := cfg.GetContractAddress(config.PaymentObligation) +// resp, done, err := payOb.MintNFT( +// ctx, +// ID, +// registry.String(), +// depositAddr, +// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, +// ) +// assert.Nil(t, err, "should not error out when minting an invoice") +// assert.NotNil(t, resp.TokenID, "token id should be present") +// tokenID, err := nft.FromString(resp.TokenID) +// assert.Nil(t, err, "should not error out when getting tokenID hex") +// <-done +// assert.NoError(t, txManager.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) +// owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) +// assert.NoError(t, err) +// assert.Equal(t, common.HexToAddress(depositAddr), owner) +// doc, err := invoiceService.GetCurrentVersion(ctx, ID) +// assert.NoError(t, err) +// cd, err := doc.PackCoreDocument() +// assert.NoError(t, err) +// assert.Len(t, cd.Roles, 2) +// assert.Len(t, cd.Roles[1].Nfts, 1) +// newNFT := cd.Roles[1].Nfts[0] +// enft, err := coredocument.ConstructNFT(registry, tokenID.BigInt().Bytes()) +// assert.NoError(t, err) +// assert.Equal(t, enft, newNFT) +// +// // try to mint the NFT again +// _, _, err = payOb.MintNFT(ctx, +// ID, +// registry.String(), +// depositAddr, +// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}) +// assert.Error(t, err) +// assert.True(t, errors.IsOfType(nft.ErrNFTMinted, err)) +//} diff --git a/testworld/nft_test.go b/testworld/nft_test.go index f059aa1da..78f8ef565 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -11,10 +11,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestPaymentObligationMint_invoice_successful(t *testing.T) { - t.Parallel() - paymentObligationMint(t, typeInvoice) -} +// +//func TestPaymentObligationMint_invoice_successful(t *testing.T) { +// t.Parallel() +// paymentObligationMint(t, typeInvoice) +//} /* TODO: testcase not stable func TestPaymentObligationMint_po_successful(t *testing.T) { @@ -74,39 +75,39 @@ func paymentObligationMint(t *testing.T, documentType string) { } -func TestPaymentObligationMint_errors(t *testing.T) { - t.Parallel() - alice := doctorFord.getHostTestSuite(t, "Alice") - tests := []struct { - errorMsg string - httpStatus int - payload map[string]interface{} - }{ - { - - "RegistryAddress is not a valid Ethereum address", - http.StatusInternalServerError, - map[string]interface{}{ - - "registryAddress": "0x123", - }, - }, - { - "DepositAddress is not a valid Ethereum address", - http.StatusInternalServerError, - map[string]interface{}{ - - "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address - "depositAddress": "abc", - }, - }, - } - for _, test := range tests { - t.Run(test.errorMsg, func(t *testing.T) { - t.Parallel() - response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) - assert.Nil(t, err, "it should be possible to call the API endpoint") - response.Value("error").String().Contains(test.errorMsg) - }) - } -} +//func TestPaymentObligationMint_errors(t *testing.T) { +// t.Parallel() +// alice := doctorFord.getHostTestSuite(t, "Alice") +// tests := []struct { +// errorMsg string +// httpStatus int +// payload map[string]interface{} +// }{ +// { +// +// "RegistryAddress is not a valid Ethereum address", +// http.StatusInternalServerError, +// map[string]interface{}{ +// +// "registryAddress": "0x123", +// }, +// }, +// { +// "DepositAddress is not a valid Ethereum address", +// http.StatusInternalServerError, +// map[string]interface{}{ +// +// "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address +// "depositAddress": "abc", +// }, +// }, +// } +// for _, test := range tests { +// t.Run(test.errorMsg, func(t *testing.T) { +// t.Parallel() +// response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) +// assert.Nil(t, err, "it should be possible to call the API endpoint") +// response.Value("error").String().Contains(test.errorMsg) +// }) +// } +//} From 2feca7759938a70b83ea409034f85d8d481ae76b Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 12 Feb 2019 17:18:07 +0100 Subject: [PATCH 187/220] identity: createConfig (#741) * createConfig deprecated * added CreateConfig with new identity * added test for create config * formatting * added tests for create config * formatting * moved create identity and add keys to did package --- bootstrap/bootstrappers/bootstrapper.go | 2 + cmd/centrifuge/create_config.go | 2 +- cmd/centrifuge_cmd_test.go | 2 +- cmd/common.go | 78 ++++++++++++++-- cmd/common_test.go | 111 +++++++++++++++++++++++ identity/did/bootstrapper.go | 4 +- identity/did/factory.go | 34 +++++-- identity/did/factory_integration_test.go | 2 +- identity/did/key.go | 5 + identity/did/service.go | 87 +++++++++++++++++- identity/did/service_integration_test.go | 4 +- identity/identity.go | 3 + testworld/park.go | 2 +- 13 files changed, 314 insertions(+), 22 deletions(-) create mode 100644 cmd/common_test.go diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 45f24f8e2..edd4d658d 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -10,6 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/did" "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/node" @@ -59,6 +60,7 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { transactions.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, + &did.Bootstrapper{}, &anchors.Bootstrapper{}, ðid.Bootstrapper{}, } diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index 1868c5041..fc67a1eba 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -30,7 +30,7 @@ func init() { Short: "Configures Node", Long: ``, Run: func(c *cobra.Command, args []string) { - err := cmd.CreateConfig(targetDataDir, + err := cmd.CreateConfigDeprecated(targetDataDir, ethNodeURL, accountKeyPath, accountPassword, diff --git a/cmd/centrifuge_cmd_test.go b/cmd/centrifuge_cmd_test.go index 33bfe38ac..ee57d47ea 100644 --- a/cmd/centrifuge_cmd_test.go +++ b/cmd/centrifuge_cmd_test.go @@ -21,7 +21,7 @@ func TestVersion(t *testing.T) { assert.Contains(t, string(o), version.CentrifugeNodeVersion) } -func TestCreateConfig(t *testing.T) { +func TestCreateConfigDeprecated(t *testing.T) { dataDir := path.Join(os.Getenv("HOME"), "datadir") scAddrs := testingutils.GetSmartContractAddresses() keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") diff --git a/cmd/common.go b/cmd/common.go index 57bdd6dcf..dcb802648 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,10 +3,10 @@ package cmd import ( "context" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" + "github.com/centrifuge/go-centrifuge/identity/did" "github.com/centrifuge/go-centrifuge/storage" @@ -22,7 +22,8 @@ import ( var log = logging.Logger("centrifuge-cmd") -func createIdentity(ctx context.Context, idService identity.Service) (identity.CentID, error) { +// Deprecated +func createIdentityDeprecated(ctx context.Context, idService identity.Service) (identity.CentID, error) { centID := identity.RandomCentID() _, confirmations, err := idService.CreateIdentity(ctx, centID) if err != nil { @@ -42,7 +43,8 @@ func generateKeys(config config.Configuration) { crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } -func addKeys(config config.Configuration, idService identity.Service) error { +// Deprecated +func addKeysDeprecated(config config.Configuration, idService identity.Service) error { err := idService.AddKeyFromConfig(config, identity.KeyPurposeP2P) if err != nil { return err @@ -67,6 +69,70 @@ func CreateConfig( p2pConnectionTimeout string, smartContractAddrs *config.SmartContractAddresses) error { + data := map[string]interface{}{ + "targetDataDir": targetDataDir, + "accountKeyPath": accountKeyPath, + "accountPassword": accountPassword, + "network": network, + "ethNodeURL": ethNodeURL, + "bootstraps": bootstraps, + "apiPort": apiPort, + "p2pPort": p2pPort, + "p2pConnectTimeout": p2pConnectionTimeout, + "txpoolaccess": txPoolAccess, + } + if smartContractAddrs != nil { + data["smartContractAddresses"] = smartContractAddrs + } + configFile, err := config.CreateConfigFile(data) + if err != nil { + return err + } + log.Infof("Config File Created: %s\n", configFile.ConfigFileUsed()) + ctx, canc, _ := CommandBootstrap(configFile.ConfigFileUsed()) + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + + // create keys locally + generateKeys(cfg) + + id, err := did.CreateIdentity(ctx, cfg) + if err != nil { + return err + } + + configFile.Set("identityId", id.ToAddress().String()) + err = configFile.WriteConfig() + if err != nil { + return err + } + cfg.Set("identityId", id.ToAddress().String()) + log.Infof("Identity created [%s]", id.ToAddress().String()) + + err = did.AddKeysFromConfig(ctx, cfg) + if err != nil { + return err + } + + canc() + db := ctx[storage.BootstrappedDB].(storage.Repository) + dbCfg := ctx[storage.BootstrappedConfigDB].(storage.Repository) + db.Close() + dbCfg.Close() + log.Infof("---------Centrifuge node configuration file successfully created!---------") + log.Infof("Please run the Centrifuge node using the following command: centrifuge run -c %s\n", configFile.ConfigFileUsed()) + return nil +} + +// CreateConfigDeprecated creates a config file using provide parameters and the default config +// Deprecated +func CreateConfigDeprecated( + targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, + apiPort, p2pPort int64, + bootstraps []string, + txPoolAccess bool, + p2pConnectionTimeout string, + smartContractAddrs *config.SmartContractAddresses) error { + data := map[string]interface{}{ "targetDataDir": targetDataDir, "accountKeyPath": accountKeyPath, @@ -102,7 +168,7 @@ func CreateConfig( } idService := ctx[identity.BootstrappedIDService].(identity.Service) - id, err := createIdentity(tctx, idService) + id, err := createIdentityDeprecated(tctx, idService) if err != nil { return err } @@ -113,7 +179,7 @@ func CreateConfig( } cfg.Set("identityId", id.String()) log.Infof("Identity created [%s] [%x]", id.String(), id) - err = addKeys(cfg, idService) + err = addKeysDeprecated(cfg, idService) if err != nil { return err } diff --git a/cmd/common_test.go b/cmd/common_test.go new file mode 100644 index 000000000..e1c036786 --- /dev/null +++ b/cmd/common_test.go @@ -0,0 +1,111 @@ +// +build integration + +package cmd + +import ( + "context" + "math/big" + "os" + "os/exec" + "path" + "testing" + + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/did" + "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/stretchr/testify/assert" +) + +var cfg config.Configuration +var ctx = map[string]interface{}{} + +func TestMain(m *testing.M) { + var bootstappers = []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + transactions.Bootstrapper{}, + &queue.Bootstrapper{}, + ethereum.Bootstrapper{}, + ðid.Bootstrapper{}, + &configstore.Bootstrapper{}, + &did.Bootstrapper{}, + &queue.Starter{}, + } + + bootstrap.RunTestBootstrappers(bootstappers, ctx) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + result := m.Run() + bootstrap.RunTestTeardown(bootstappers) + os.Exit(result) +} + +func TestCreateConfig(t *testing.T) { + // create config + dataDir := "testconfig" + keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") + scAddrs := did.GetSmartContractAddresses() + err := CreateConfig(dataDir, "http://127.0.0.1:9545", keyPath, "", "russianhill", 8028, 38202, nil, true, "", scAddrs) + assert.Nil(t, err, "Create Config should be successful") + + // config exists + cfg := config.LoadConfiguration(path.Join(dataDir, "config.yaml")) + client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + // contract exists + id, err := cfg.GetIdentityID() + assert.Nil(t, err, "did should exists") + contractCode, err := client.GetEthClient().CodeAt(context.Background(), common.BytesToAddress(id), nil) + assert.Nil(t, err, "should be successful to get the contract code") + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + + // Keys exists + // type KeyPurposeEthMsgAuth + tctx := testingconfig.CreateAccountContext(t, cfg) + idSrv := ctx[did.BootstrappedDIDService].(did.Service) + pk, _, err := secp256k1.GetEthAuthKey(cfg.GetEthAuthKeyPair()) + assert.Nil(t, err) + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + assert.Nil(t, err) + response, err := idSrv.GetKey(tctx, address32Bytes) + assert.Nil(t, err) + assert.NotNil(t, response) + assert.Equal(t, big.NewInt(identity.KeyPurposeEthMsgAuth), response.Purposes[0], "purpose should be ETHMsgAuth") + + // type KeyPurposeP2P + pk, _, err = ed25519.GetSigningKeyPair(cfg.GetP2PKeyPair()) + assert.Nil(t, err) + pk32, err := utils.SliceToByte32(pk) + assert.Nil(t, err) + response, _ = idSrv.GetKey(tctx, pk32) + assert.NotNil(t, response) + assert.Equal(t, big.NewInt(identity.KeyPurposeP2P), response.Purposes[0], "purpose should be P2P") + + // type KeyPurposeSigning + pk, _, err = ed25519.GetSigningKeyPair(cfg.GetSigningKeyPair()) + assert.Nil(t, err) + pk32, err = utils.SliceToByte32(pk) + assert.Nil(t, err) + response, _ = idSrv.GetKey(tctx, pk32) + assert.NotNil(t, response) + assert.Equal(t, big.NewInt(identity.KeyPurposeSigning), response.Purposes[0], "purpose should be Signing") + + err = exec.Command("rm", "-rf", dataDir).Run() + assert.Nil(t, err, "removing testconfig folder should be successful") + +} diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go index d12203cd2..5ee3e08ad 100644 --- a/identity/did/bootstrapper.go +++ b/identity/did/bootstrapper.go @@ -80,7 +80,7 @@ func getAnchorAddress() common.Address { // --------------------------------------------------------------------------------------------------------------------- func migrateNewIdentityContracts() { runNewSmartContractMigrations() - smartContractAddresses = getSmartContractAddresses() + smartContractAddresses = GetSmartContractAddresses() } @@ -107,7 +107,7 @@ func runNewSmartContractMigrations() { // GetSmartContractAddresses finds migrated smart contract addresses for localgeth // TODO: func will be removed after migration -func getSmartContractAddresses() *config.SmartContractAddresses { +func GetSmartContractAddresses() *config.SmartContractAddresses { dat, err := findContractDeployJSON() if err != nil { panic(err) diff --git a/identity/did/factory.go b/identity/did/factory.go index a282ec8f8..dfadc3b37 100644 --- a/identity/did/factory.go +++ b/identity/did/factory.go @@ -3,6 +3,9 @@ package did import ( "context" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/contextutil" @@ -117,17 +120,13 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { return nil, err } - idConfig, err := contextutil.Self(ctx) - if err != nil { - return nil, err - } - identityAddress, err := s.calculateIdentityAddress(ctx) if err != nil { return nil, err } - txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), idConfig.ID, uuid.Nil, "Check TX for create identity status", s.createIdentityTX(opts)) + // TODO refactor randomCentID + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for create identity status", s.createIdentityTX(opts)) if err != nil { return nil, err } @@ -147,3 +146,26 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { createdDID := NewDID(*identityAddress) return &createdDID, nil } + +// CreateIdentity creates an identity contract +func CreateIdentity(ctx map[string]interface{}, cfg config.Configuration) (*DID, error) { + tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) + if err != nil { + return nil, err + } + + tctx, err := contextutil.New(context.Background(), tc) + if err != nil { + return nil, err + } + + identityFactory := ctx[BootstrappedDIDFactory].(Factory) + + did, err := identityFactory.CreateIdentity(tctx) + if err != nil { + return nil, err + } + + return did, nil + +} diff --git a/identity/did/factory_integration_test.go b/identity/did/factory_integration_test.go index b4358403f..3a425b945 100644 --- a/identity/did/factory_integration_test.go +++ b/identity/did/factory_integration_test.go @@ -54,7 +54,7 @@ func TestCreateIdentity_successful(t *testing.T) { client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) + contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.ToAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") diff --git a/identity/did/key.go b/identity/did/key.go index e71ac3d43..8372099e9 100644 --- a/identity/did/key.go +++ b/identity/did/key.go @@ -30,6 +30,11 @@ type key struct { Type *big.Int } +//NewKey returns a new key struct +func NewKey(pk [32]byte, purpose *big.Int, keyType *big.Int) Key { + return &key{pk, purpose, big.NewInt(0), keyType} +} + // GetKey returns the public key func (idk *key) GetKey() [32]byte { return idk.Key diff --git a/identity/did/service.go b/identity/did/service.go index b6dc29148..5f332857c 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -5,6 +5,12 @@ import ( "math/big" "strings" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -22,7 +28,8 @@ import ( // DID stores the identity address of the user type DID common.Address -func (d DID) toAddress() common.Address { +// ToAddress returns the DID as common.Address +func (d DID) ToAddress() common.Address { return common.Address(d) } @@ -121,7 +128,7 @@ func (i service) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelF } func (i service) bindContract(did DID) (contract, error) { - contract, err := NewIdentityContract(did.toAddress(), i.client.GetEthClient()) + contract, err := NewIdentityContract(did.ToAddress(), i.client.GetEthClient()) if err != nil { return nil, errors.New("Could not bind identity contract: %v", err) } @@ -168,6 +175,7 @@ func (i service) AddKey(ctx context.Context, key Key) error { } // TODO: did can be passed instead of randomCentID after CentID is DID + log.Info("Add key to identity contract %s", did.ToAddress().String()) txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add key", i.ethereumTX(opts, contract.AddKey, key.GetKey(), key.GetPurpose(), key.GetType())) if err != nil { @@ -345,3 +353,78 @@ func (i service) Execute(ctx context.Context, to common.Address, contractAbi, me } return i.RawExecute(ctx, to, data) } + +func getKeyPairsFromConfig(config config.Configuration) (map[int]Key, error) { + keys := map[int]Key{} + var pk []byte + + // ed25519 keys + // KeyPurposeP2P + pk, _, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) + if err != nil { + return nil, err + } + pk32, err := utils.SliceToByte32(pk) + if err != nil { + return nil, err + } + keys[id.KeyPurposeP2P] = NewKey(pk32, big.NewInt(id.KeyPurposeP2P), big.NewInt(id.KeyTypeECDSA)) + + // KeyPurposeSigning + pk, _, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + if err != nil { + return nil, err + } + pk32, err = utils.SliceToByte32(pk) + if err != nil { + return nil, err + } + keys[id.KeyPurposeSigning] = NewKey(pk32, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) + + // secp256k1 keys + // KeyPurposeEthMsgAuth + pk, _, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) + if err != nil { + return nil, err + } + + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + keys[id.KeyPurposeEthMsgAuth] = NewKey(address32Bytes, big.NewInt(id.KeyPurposeEthMsgAuth), big.NewInt(id.KeyTypeECDSA)) + + return keys, nil +} + +// AddKeysFromConfig adds the keys from the config to the smart contracts +func AddKeysFromConfig(ctx map[string]interface{}, cfg config.Configuration) error { + idSrv := ctx[BootstrappedDIDService].(Service) + + tc, err := configstore.NewAccount(cfg.GetEthereumDefaultAccountName(), cfg) + if err != nil { + return err + } + + tctx, err := contextutil.New(context.Background(), tc) + if err != nil { + return err + } + + keys, err := getKeyPairsFromConfig(cfg) + if err != nil { + return err + } + err = idSrv.AddKey(tctx, keys[id.KeyPurposeP2P]) + if err != nil { + return err + } + + err = idSrv.AddKey(tctx, keys[id.KeyPurposeSigning]) + if err != nil { + return err + } + + err = idSrv.AddKey(tctx, keys[id.KeyPurposeEthMsgAuth]) + if err != nil { + return err + } + return nil +} diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index 2a449d9f7..00c45b5cb 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -34,7 +34,7 @@ func initIdentity() Service { } func getTestDIDContext(t *testing.T, did DID) context.Context { - cfg.Set("identityId", did.toAddress().String()) + cfg.Set("identityId", did.ToAddress().String()) cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") aCtx := testingconfig.CreateAccountContext(t, cfg) @@ -51,7 +51,7 @@ func deployIdentityContract(t *testing.T) *DID { client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.toAddress(), nil) + contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.ToAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") diff --git a/identity/identity.go b/identity/identity.go index 36da39a4d..54dc76be6 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -36,6 +36,9 @@ const ( // KeyPurposeEthMsgAuth represents a key used for ethereum txns KeyPurposeEthMsgAuth = 3 + + // KeyTypeECDSA has the value one in the ERC725 identity contract + KeyTypeECDSA = 1 ) // CentID represents a CentIDLength identity of an entity diff --git a/testworld/park.go b/testworld/park.go index f40321bfa..2b7f21db1 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -269,7 +269,7 @@ func newHost( func (h *host) init() error { if h.createConfig { - err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) + err := cmd.CreateConfigDeprecated(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) if err != nil { return err } From 0956e7a4219584f14902c282e9b39f50909f12f1 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Wed, 13 Feb 2019 14:14:06 +0100 Subject: [PATCH 188/220] Compact Precise Proofs (#743) * latest precise proofs * latest precise proofs * using compact properties * added compact prefix * fix client test * fix client test --- coredocument/coredocument.go | 66 +++++++++++++++----- coredocument/coredocument_test.go | 9 +-- documents/documents_test/service_test.go | 4 +- documents/handler.go | 2 +- documents/handler_test.go | 4 +- documents/invoice/model.go | 10 +-- documents/model.go | 76 +++++++++++++++++------ documents/model_test.go | 19 +++--- documents/purchaseorder/model.go | 10 +-- p2p/receiver/handler_integration_test.go | 4 +- testingutils/coredocument/coredocument.go | 4 +- testworld/proof_test.go | 11 +++- 12 files changed, 150 insertions(+), 69 deletions(-) diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go index efbc8045b..dedde723b 100644 --- a/coredocument/coredocument.go +++ b/coredocument/coredocument.go @@ -16,6 +16,48 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +const ( + // CDRootField represents the coredocument root property of a tree + CDRootField = "cd_root" + // DataRootField represents the data root property of a tree + DataRootField = "data_root" + // DocumentTypeField represents the doc type property of a tree + DocumentTypeField = "document_type" + // SignaturesField represents the signatures property of a tree + SignaturesField = "signatures" + // SigningRootField represents the signature root property of a tree + SigningRootField = "signing_root" +) + +var compactProperties = map[string][]byte{ + CDRootField: {0, 0, 0, 7}, + DataRootField: {0, 0, 0, 5}, + DocumentTypeField: {0, 0, 0, 100}, + SignaturesField: {0, 0, 0, 6}, + SigningRootField: {0, 0, 0, 10}, +} + +// NewDefaultTree returns a DocumentTree with default opts +func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { + return NewDefaultTreeWithPrefix(salts, "") +} + +// NewDefaultTreeWithPrefix returns a DocumentTree with default opts passing a prefix to the tree leaves +func NewDefaultTreeWithPrefix(salts *proofs.Salts, prefix string) *proofs.DocumentTree { + var prop proofs.Property + if prefix != "" { + prop = proofs.NewProperty(prefix) + } + + t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + return &t +} + +// NewLeafProperty returns a proof property with the literal and the compact +func NewLeafProperty(literal string, compact []byte) proofs.Property { + return proofs.NewProperty(literal, compact...) +} + // getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used // to create field proofs func getDataProofHashes(document *coredocumentpb.CoreDocument, dataRoot []byte) (hashes [][]byte, err error) { @@ -80,16 +122,15 @@ func CalculateDocumentRoot(document *coredocumentpb.CoreDocument) error { // GetDocumentRootTree returns the merkle tree for the document root func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) - tree = &t + tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: proofs.NewProperty("signing_root")}) + err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties[SigningRootField])}) if err != nil { return nil, err } // For every signature we create a LeafNode - sigProperty := proofs.NewProperty("signatures") + sigProperty := NewLeafProperty(SignaturesField, compactProperties[SignaturesField]) sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), @@ -128,8 +169,7 @@ func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.Do // GetCoreDocTree returns the merkle tree for the coredoc root func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) - tree = &t + tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) err = tree.AddLeavesFromDocument(document) if err != nil { return nil, err @@ -140,7 +180,7 @@ func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.Documen } // Adding document type as it is an excluded field in the tree documentTypeNode := proofs.LeafNode{ - Property: proofs.NewProperty("document_type"), + Property: NewLeafProperty(DocumentTypeField, compactProperties[DocumentTypeField]), Salt: make([]byte, 32), Value: []byte(document.EmbeddedData.TypeUrl), } @@ -164,8 +204,6 @@ func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.Documen // GetDocumentSigningTree returns the merkle tree for the signing root func GetDocumentSigningTree(document *coredocumentpb.CoreDocument, dataRoot []byte) (tree *proofs.DocumentTree, err error) { - h := sha256.New() - // coredoc tree coreDocTree, err := GetCoreDocTree(document) if err != nil { @@ -173,16 +211,15 @@ func GetDocumentSigningTree(document *coredocumentpb.CoreDocument, dataRoot []by } // create the signing tree with data root and coredoc root as siblings - t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) - tree = &t2 + tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) err = tree.AddLeaves([]proofs.LeafNode{ { - Property: proofs.NewProperty("data_root"), + Property: NewLeafProperty(DataRootField, compactProperties[DataRootField]), Hash: dataRoot, Hashed: true, }, { - Property: proofs.NewProperty("cd_root"), + Property: NewLeafProperty(CDRootField, compactProperties[CDRootField]), Hash: coreDocTree.RootHash(), Hashed: true, }, @@ -309,8 +346,7 @@ func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.Co // GenerateNewSalts generates salts for new document func GenerateNewSalts(document proto.Message, prefix string) (*proofs.Salts, error) { docSalts := &proofs.Salts{} - prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: docSalts}) + t := NewDefaultTreeWithPrefix(docSalts, prefix) err := t.AddLeavesFromDocument(document) if err != nil { return nil, err diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go index 735d60301..a2def7839 100644 --- a/coredocument/coredocument_test.go +++ b/coredocument/coredocument_test.go @@ -215,10 +215,11 @@ func TestNewWithCollaborators(t *testing.T) { func TestCreateProofs(t *testing.T) { h := sha256.New() - testTree := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) - err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field")}) + testTree := NewDefaultTree(nil) + props := []proofs.Property{NewLeafProperty("sample_field", []byte{0, 0, 0, 200}), NewLeafProperty("sample_field2", []byte{0, 0, 0, 202})} + err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[0]}) assert.NoError(t, err) - err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field2")}) + err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[1]}) assert.NoError(t, err) err = testTree.Generate() assert.NoError(t, err) @@ -267,7 +268,7 @@ func TestCreateProofs(t *testing.T) { } for _, test := range tests { t.Run(test.fieldName, func(t *testing.T) { - p, err := CreateProofs(&testTree, cd, []string{test.fieldName}) + p, err := CreateProofs(testTree, cd, []string{test.fieldName}) assert.NoError(t, err) assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) var l *proofs.LeafNode diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index 0b6629e12..ef3f92477 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -205,7 +205,7 @@ func TestService_CreateProofs(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() @@ -254,7 +254,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetReadableName(), "invoice.invoice_number") + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { diff --git a/documents/handler.go b/documents/handler.go index 5954a4099..a9c29a768 100644 --- a/documents/handler.go +++ b/documents/handler.go @@ -104,7 +104,7 @@ func ConvertProofsToClientFormat(proofs []*proofspb.Proof) []*documentpb.Proof { // ConvertProofToClientFormat converts a proof in precise proof format in to a client protobuf proof func ConvertProofToClientFormat(proof *proofspb.Proof) *documentpb.Proof { return &documentpb.Proof{ - Property: proof.GetReadableName(), + Property: hexutil.Encode(proof.GetCompactName()), Value: hexutil.Encode(proof.Value), Salt: hexutil.Encode(proof.Salt), Hash: hexutil.Encode(proof.Hash), diff --git a/documents/handler_test.go b/documents/handler_test.go index f08f3d788..44974f806 100644 --- a/documents/handler_test.go +++ b/documents/handler_test.go @@ -156,7 +156,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { State: "state", FieldProofs: []*proofspb.Proof{ { - Property: proofs.ReadableName("prop1"), + Property: proofs.CompactName([]byte{0, 0, 1}...), Value: v1, Salt: []byte{1, 2, 3}, Hash: []byte{1, 2, 4}, @@ -176,7 +176,7 @@ func TestConvertDocProofToClientFormat(t *testing.T) { }, FieldProofs: []*documentpb.Proof{ { - Property: "prop1", + Property: "0x000001", Value: "0x76616c756531", Salt: "0x010203", Hash: "0x010204", diff --git a/documents/invoice/model.go b/documents/invoice/model.go index eb35ded39..83664deed 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -1,7 +1,6 @@ package invoice import ( - "crypto/sha256" "encoding/json" "reflect" @@ -24,6 +23,8 @@ import ( const prefix string = "invoice" +var compactPrefix = []byte{1, 0, 0, 0} + // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { InvoiceNumber string // invoice number or reference number @@ -250,7 +251,7 @@ func (i *Invoice) loadFromP2PProtobuf(invoiceData *invoicepb.InvoiceData) { // getInvoiceSalts returns the invoice salts. Initialises if not present func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) (*proofs.Salts, error) { if i.InvoiceSalts == nil { - invoiceSalts, err := documents.GenerateNewSalts(invoiceData, prefix) + invoiceSalts, err := documents.GenerateNewSalts(invoiceData, prefix, compactPrefix) if err != nil { return nil, errors.New("getInvoiceSalts error %v", err) } @@ -357,13 +358,12 @@ func (i *Invoice) CalculateDataRoot() ([]byte, error) { // getDocumentDataTree creates precise-proofs data tree for the model func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - prop := proofs.NewProperty(prefix) invProto := i.createP2PProtobuf() salts, err := i.getInvoiceSalts(invProto) if err != nil { return nil, err } - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix) err = t.AddLeavesFromDocument(invProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) @@ -372,7 +372,7 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) } - return &t, nil + return t, nil } // CreateProofs generates proofs for given fields diff --git a/documents/model.go b/documents/model.go index 9643bf8a0..b767e8bcb 100644 --- a/documents/model.go +++ b/documents/model.go @@ -18,6 +18,27 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) +const ( + // CDRootField represents the coredocument root property of a tree + CDRootField = "cd_root" + // DataRootField represents the data root property of a tree + DataRootField = "data_root" + // DocumentTypeField represents the doc type property of a tree + DocumentTypeField = "document_type" + // SignaturesField represents the signatures property of a tree + SignaturesField = "signatures" + // SigningRootField represents the signature root property of a tree + SigningRootField = "signing_root" +) + +var compactProperties = map[string][]byte{ + CDRootField: {0, 0, 0, 7}, + DataRootField: {0, 0, 0, 5}, + DocumentTypeField: {0, 0, 0, 100}, + SignaturesField: {0, 0, 0, 6}, + SigningRootField: {0, 0, 0, 10}, +} + // Model is an interface to abstract away model specificness like invoice or purchaseOrder // The interface can cast into the type specified by the model if required // It should only handle protocol-level Document actions @@ -53,6 +74,27 @@ const ( ErrZeroCollaborators = errors.Error("require at least one collaborator") ) +// NewDefaultTree returns a DocumentTree with default opts +func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { + return NewDefaultTreeWithPrefix(salts, "", nil) +} + +// NewDefaultTreeWithPrefix returns a DocumentTree with default opts passing a prefix to the tree leaves +func NewDefaultTreeWithPrefix(salts *proofs.Salts, prefix string, compactPrefix []byte) *proofs.DocumentTree { + var prop proofs.Property + if prefix != "" { + prop = NewLeafProperty(prefix, compactPrefix) + } + + t := proofs.NewDocumentTree(proofs.TreeOptions{CompactProperties: true, EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + return &t +} + +// NewLeafProperty returns a proof property with the literal and the compact +func NewLeafProperty(literal string, compact []byte) proofs.Property { + return proofs.NewProperty(literal, compact...) +} + // NewCoreDocModel returns a new CoreDocumentModel // Note: collaborators and salts are to be filled by the caller func NewCoreDocModel() *CoreDocumentModel { @@ -168,8 +210,7 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err error) { document := m.Document h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(m.Document.CoredocumentSalts)}) - tree = &t + tree = NewDefaultTree(ConvertToProofSalts(m.Document.CoredocumentSalts)) err = tree.AddLeavesFromDocument(document) if err != nil { return nil, err @@ -180,12 +221,12 @@ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err err } // Adding document type as it is an excluded field in the tree documentTypeNode := proofs.LeafNode{ - Property: proofs.NewProperty("document_type"), + Property: NewLeafProperty(DocumentTypeField, compactProperties[DocumentTypeField]), Salt: make([]byte, 32), Value: []byte(document.EmbeddedData.TypeUrl), } - err = documentTypeNode.HashNode(h, false) + err = documentTypeNode.HashNode(h, true) if err != nil { return nil, err } @@ -204,8 +245,6 @@ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err err // GetDocumentSigningTree returns the merkle tree for the signing root func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proofs.DocumentTree, err error) { - h := sha256.New() - // coredoc tree coreDocTree, err := m.GetCoreDocTree() if err != nil { @@ -213,16 +252,15 @@ func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proof } // create the signing tree with data root and coredoc root as siblings - t2 := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(m.Document.CoredocumentSalts)}) - tree = &t2 + tree = NewDefaultTree(ConvertToProofSalts(m.Document.CoredocumentSalts)) err = tree.AddLeaves([]proofs.LeafNode{ { - Property: proofs.NewProperty("data_root"), + Property: NewLeafProperty(DataRootField, compactProperties[DataRootField]), Hash: dataRoot, Hashed: true, }, { - Property: proofs.NewProperty("cd_root"), + Property: NewLeafProperty(CDRootField, compactProperties[CDRootField]), Hash: coreDocTree.RootHash(), Hashed: true, }, @@ -244,23 +282,22 @@ func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proof func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, err error) { document := m.Document h := sha256.New() - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: h, Salts: ConvertToProofSalts(document.CoredocumentSalts)}) - tree = &t + tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: proofs.NewProperty("signing_root")}) + err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties[SigningRootField])}) if err != nil { return nil, err } // For every signature we create a LeafNode - sigProperty := proofs.NewProperty("signatures") + sigProperty := NewLeafProperty(SignaturesField, compactProperties[SignaturesField]) sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), Salt: make([]byte, 32), Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), } - err = sigLengthNode.HashNode(h, false) + err = sigLengthNode.HashNode(h, true) if err != nil { return nil, err } @@ -272,7 +309,7 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er Hashed: true, Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), } - err = leaf.HashNode(h, false) + err = leaf.HashNode(h, true) if err != nil { return nil, err } @@ -362,10 +399,9 @@ func (m *CoreDocumentModel) AccountCanRead(account identity.CentID) bool { } // GenerateNewSalts generates salts for new document -func GenerateNewSalts(document proto.Message, prefix string) (*proofs.Salts, error) { +func GenerateNewSalts(document proto.Message, prefix string, compactPrefix []byte) (*proofs.Salts, error) { docSalts := &proofs.Salts{} - prop := proofs.NewProperty(prefix) - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: docSalts}) + t := NewDefaultTreeWithPrefix(docSalts, prefix, compactPrefix) err := t.AddLeavesFromDocument(document) if err != nil { return nil, err @@ -404,7 +440,7 @@ func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salt // getCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet func (m *CoreDocumentModel) getCoreDocumentSalts() ([]*coredocumentpb.DocumentSalt, error) { if m.Document.CoredocumentSalts == nil { - pSalts, err := GenerateNewSalts(m.Document, "") + pSalts, err := GenerateNewSalts(m.Document, "", nil) if err != nil { return nil, err } diff --git a/documents/model_test.go b/documents/model_test.go index f9a1bb1a4..c693dccfc 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -287,18 +287,20 @@ func TestGetDocumentRootTree(t *testing.T) { tree, err := dm.GetDocumentRootTree() // Manually constructing the two node tree: - signaturesLengthLeaf := sha256.Sum256(append([]byte("signatures.length0"), make([]byte, 32)...)) - expectedRootHash := sha256.Sum256(append(signaturesLengthLeaf[:], dm.Document.SigningRoot...)) + signaturesLengthLeaf := sha256.Sum256(append(append(compactProperties[SignaturesField], []byte{48}...), make([]byte, 32)...)) + expectedRootHash := sha256.Sum256(append(dm.Document.SigningRoot, signaturesLengthLeaf[:]...)) assert.Nil(t, err) assert.Equal(t, expectedRootHash[:], tree.RootHash()) } func TestCreateProofs(t *testing.T) { h := sha256.New() - testTree := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New()}) - err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field")}) + testTree := NewDefaultTree(nil) + props := []proofs.Property{NewLeafProperty("sample_field", []byte{0, 0, 0, 200}), NewLeafProperty("sample_field2", []byte{0, 0, 0, 202})} + compactProps := [][]byte{props[0].Compact, props[1].Compact} + err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[0]}) assert.NoError(t, err) - err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: proofs.NewProperty("sample_field2")}) + err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[1]}) assert.NoError(t, err) err = testTree.Generate() assert.NoError(t, err) @@ -346,7 +348,7 @@ func TestCreateProofs(t *testing.T) { } for _, test := range tests { t.Run(test.fieldName, func(t *testing.T) { - p, err := dm.CreateProofs(&testTree, []string{test.fieldName}) + p, err := dm.CreateProofs(testTree, []string{test.fieldName}) assert.NoError(t, err) assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) var l *proofs.LeafNode @@ -354,6 +356,7 @@ func TestCreateProofs(t *testing.T) { _, l = cdTree.GetLeafByProperty(test.fieldName) } else { _, l = testTree.GetLeafByProperty(test.fieldName) + assert.Contains(t, compactProps, l.Property.CompactName()) } valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) assert.NoError(t, err) @@ -382,14 +385,14 @@ func TestGetCoreDocumentSalts(t *testing.T) { func TestGenerateNewSalts(t *testing.T) { dm := NewCoreDocModel() - salts, err := GenerateNewSalts(dm.Document, "") + salts, err := GenerateNewSalts(dm.Document, "", nil) assert.NoError(t, err) assert.NotNil(t, salts) } func TestConvertToProofAndProtoSalts(t *testing.T) { dm := NewCoreDocModel() - salts, err := GenerateNewSalts(dm.Document, "") + salts, err := GenerateNewSalts(dm.Document, "", nil) assert.NoError(t, err) assert.NotNil(t, salts) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index a824f4761..4ffb06c32 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -1,7 +1,6 @@ package purchaseorder import ( - "crypto/sha256" "encoding/json" "reflect" @@ -25,6 +24,8 @@ import ( const prefix string = "po" +var compactPrefix = []byte{2, 0, 0, 0} + // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { Status string // status of the Purchase Order @@ -247,7 +248,7 @@ func (p *PurchaseOrder) loadFromP2PProtobuf(data *purchaseorderpb.PurchaseOrderD // getPurchaseOrderSalts returns the purchase oder salts. Initialises if not present func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb.PurchaseOrderData) (*proofs.Salts, error) { if p.PurchaseOrderSalts == nil { - poSalts, err := documents.GenerateNewSalts(purchaseOrderData, prefix) + poSalts, err := documents.GenerateNewSalts(purchaseOrderData, prefix, compactPrefix) if err != nil { return nil, errors.New("getPOSalts error %v", err) } @@ -344,13 +345,12 @@ func (p *PurchaseOrder) CalculateDataRoot() ([]byte, error) { // getDocumentDataTree creates precise-proofs data tree for the model func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { - prop := proofs.NewProperty(prefix) poProto := p.createP2PProtobuf() salts, err := p.getPurchaseOrderSalts(poProto) if err != nil { return nil, err } - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix) err = t.AddLeavesFromDocument(poProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) @@ -359,7 +359,7 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) } - return &t, nil + return t, nil } // CreateProofs generates proofs for given fields diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 7d6feb57d..f2093fe67 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -347,7 +347,7 @@ func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) { invData := &invoicepb.InvoiceData{} - dataSalts, _ := documents.GenerateNewSalts(invData, "invoice") + dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) serializedInv, err := proto.Marshal(invData) assert.NoError(t, err) @@ -357,7 +357,7 @@ func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) Value: serializedInv, } doc.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) - cdSalts, _ := documents.GenerateNewSalts(doc, "") + cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) } diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go index 778e58820..66c8daaea 100644 --- a/testingutils/coredocument/coredocument.go +++ b/testingutils/coredocument/coredocument.go @@ -16,7 +16,7 @@ import ( func GenerateCoreDocumentWithCollaborators(collaborators [][]byte) *coredocumentpb.CoreDocument { identifier := utils.RandomSlice(32) invData := &invoicepb.InvoiceData{} - dataSalts, _ := documents.GenerateNewSalts(invData, "invoice") + dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) serializedInv, _ := proto.Marshal(invData) doc := &coredocumentpb.CoreDocument{ @@ -30,7 +30,7 @@ func GenerateCoreDocumentWithCollaborators(collaborators [][]byte) *coredocument }, EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), } - cdSalts, _ := documents.GenerateNewSalts(doc, "") + cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) return doc } diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 8a3d2a0cf..29a85c2f3 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -46,15 +46,20 @@ func proofWithMultipleFields_successful(t *testing.T, documentType string) { } func checkProof(objProof *httpexpect.Object, documentType string, docIdentifier string) { + compactPrefix := "0x01000000" // invoice prefix + prop1 := "0000000f" // invoice.net_amount + prop2 := "0000000d" // invoice.currency if documentType == typePO { - documentType = poPrefix + compactPrefix = "0x02000000" // po prefix + prop1 = "0000000e" // po.net_amount + prop2 = "0000000c" // po.currency } objProof.Path("$.header.document_id").String().Equal(docIdentifier) - objProof.Path("$.field_proofs[0].property").String().Equal(documentType + ".net_amount") + objProof.Path("$.field_proofs[0].property").String().Equal(compactPrefix + prop1) objProof.Path("$.field_proofs[0].sorted_hashes").NotNull() - objProof.Path("$.field_proofs[1].property").String().Equal(documentType + ".currency") + objProof.Path("$.field_proofs[1].property").String().Equal(compactPrefix + prop2) objProof.Path("$.field_proofs[1].sorted_hashes").NotNull() } From 66c37a276afe4fecce4b3d5f40213e88c43f99bc Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Wed, 13 Feb 2019 16:41:59 +0100 Subject: [PATCH 189/220] identity: additional service methods (#746) * createConfig deprecated * added CreateConfig with new identity * added test for create config * formatting * added tests for create config * formatting * moved create identity and add keys to did package * identity fixed call methods * added getURL methods to idenitity * better variable names --- cmd/common_test.go | 10 +- identity/did/factory.go | 6 +- identity/did/service.go | 124 ++++++++++++++++++++--- identity/did/service_integration_test.go | 107 +++++++++++++++++-- identity/identity.go | 13 +-- 5 files changed, 223 insertions(+), 37 deletions(-) diff --git a/cmd/common_test.go b/cmd/common_test.go index e1c036786..8ebfba326 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" @@ -69,6 +68,8 @@ func TestCreateConfig(t *testing.T) { // contract exists id, err := cfg.GetIdentityID() + accountId := did.NewDID(common.BytesToAddress(id)) + assert.Nil(t, err, "did should exists") contractCode, err := client.GetEthClient().CodeAt(context.Background(), common.BytesToAddress(id), nil) assert.Nil(t, err, "should be successful to get the contract code") @@ -76,13 +77,12 @@ func TestCreateConfig(t *testing.T) { // Keys exists // type KeyPurposeEthMsgAuth - tctx := testingconfig.CreateAccountContext(t, cfg) idSrv := ctx[did.BootstrappedDIDService].(did.Service) pk, _, err := secp256k1.GetEthAuthKey(cfg.GetEthAuthKeyPair()) assert.Nil(t, err) address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) assert.Nil(t, err) - response, err := idSrv.GetKey(tctx, address32Bytes) + response, err := idSrv.GetKey(accountId, address32Bytes) assert.Nil(t, err) assert.NotNil(t, response) assert.Equal(t, big.NewInt(identity.KeyPurposeEthMsgAuth), response.Purposes[0], "purpose should be ETHMsgAuth") @@ -92,7 +92,7 @@ func TestCreateConfig(t *testing.T) { assert.Nil(t, err) pk32, err := utils.SliceToByte32(pk) assert.Nil(t, err) - response, _ = idSrv.GetKey(tctx, pk32) + response, _ = idSrv.GetKey(accountId, pk32) assert.NotNil(t, response) assert.Equal(t, big.NewInt(identity.KeyPurposeP2P), response.Purposes[0], "purpose should be P2P") @@ -101,7 +101,7 @@ func TestCreateConfig(t *testing.T) { assert.Nil(t, err) pk32, err = utils.SliceToByte32(pk) assert.Nil(t, err) - response, _ = idSrv.GetKey(tctx, pk32) + response, _ = idSrv.GetKey(accountId, pk32) assert.NotNil(t, response) assert.Equal(t, big.NewInt(identity.KeyPurposeSigning), response.Purposes[0], "purpose should be Signing") diff --git a/identity/did/factory.go b/identity/did/factory.go index dfadc3b37..bcde0c665 100644 --- a/identity/did/factory.go +++ b/identity/did/factory.go @@ -93,8 +93,8 @@ func (s *factory) calculateIdentityAddress(ctx context.Context) (*common.Address return &identityAddress, nil } -func (s *factory) isIdentityContract(identityAddress common.Address) error { - contractCode, err := s.client.GetEthClient().CodeAt(context.Background(), identityAddress, nil) +func isIdentityContract(identityAddress common.Address, client ethereum.Client) error { + contractCode, err := client.GetEthClient().CodeAt(context.Background(), identityAddress, nil) if err != nil { return err } @@ -138,7 +138,7 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { } - err = s.isIdentityContract(*identityAddress) + err = isIdentityContract(*identityAddress, s.client) if err != nil { return nil, err } diff --git a/identity/did/service.go b/identity/did/service.go index 5f332857c..b8daa0ac1 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -2,6 +2,7 @@ package did import ( "context" + "fmt" "math/big" "strings" @@ -49,7 +50,7 @@ type Service interface { AddKey(ctx context.Context, key Key) error // GetKey return a key from the identity contract - GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) + GetKey(did DID, key [32]byte) (*KeyResponse, error) // RawExecute calls the execute method on the identity contract RawExecute(ctx context.Context, to common.Address, data []byte) error @@ -58,13 +59,29 @@ type Service interface { Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys - IsSignedWithPurpose(ctx context.Context, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) + IsSignedWithPurpose(did DID, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) // AddMultiPurposeKey adds a key with multiple purposes AddMultiPurposeKey(context context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error // RevokeKey revokes an existing key in the smart contract RevokeKey(ctx context.Context, key [32]byte) error + + // GetClientP2PURL returns the p2p url associated with the did + GetClientP2PURL(did DID) (string, error) + + //Exists checks if an identity contract exists + Exists(ctx context.Context, did DID) error + + // ValidateKey checks if a given key is valid for the given centrifugeID. + ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error + + // GetClientsP2PURLs returns p2p urls associated with each centIDs + // will error out at first failure + GetClientsP2PURLs(did []*DID) ([]string, error) + + // GetKeysByPurpose returns keys grouped by purpose from the identity contract. + GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) } type contract interface { @@ -78,6 +95,8 @@ type contract interface { IsSignedWithPurpose(opts *bind.CallOpts, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) + GetKeysByPurpose(opts *bind.CallOpts, purpose *big.Int) ([][32]byte, error) + // Ethereum Transactions AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) @@ -274,11 +293,7 @@ func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, } // GetKey return a key from the identity contract -func (i service) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) { - did, err := i.getDID(ctx) - if err != nil { - return nil, err - } +func (i service) GetKey(did DID, key [32]byte) (*KeyResponse, error) { contract, opts, _, err := i.prepareCall(did) if err != nil { return nil, err @@ -295,11 +310,7 @@ func (i service) GetKey(ctx context.Context, key [32]byte) (*KeyResponse, error) } // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys -func (i service) IsSignedWithPurpose(ctx context.Context, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { - did, err := i.getDID(ctx) - if err != nil { - return false, err - } +func (i service) IsSignedWithPurpose(did DID, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { contract, opts, _, err := i.prepareCall(did) if err != nil { return false, err @@ -354,6 +365,95 @@ func (i service) Execute(ctx context.Context, to common.Address, contractAbi, me return i.RawExecute(ctx, to, data) } +func (i service) GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) { + contract, opts, _, err := i.prepareCall(did) + if err != nil { + return nil, err + } + + return contract.GetKeysByPurpose(opts, purpose) + +} + +// GetClientP2PURL returns the p2p url associated with the did +func (i service) GetClientP2PURL(did DID) (string, error) { + contract, opts, _, err := i.prepareCall(did) + if err != nil { + return "", err + } + + keys, err := contract.GetKeysByPurpose(opts, big.NewInt(id.KeyPurposeP2P)) + if err != nil { + return "", err + } + + lastIdx := len(keys) - 1 + key, err := contract.GetKey(opts, keys[lastIdx]) + + if err != nil { + return "", err + } + + if key.RevokedAt.Cmp(big.NewInt(0)) != 0 { + return "", errors.New("p2p key has been revoked") + } + + p2pID, err := ed25519.PublicKeyToP2PKey(key.Key) + if err != nil { + return "", err + } + + return fmt.Sprintf("/ipfs/%s", p2pID.Pretty()), nil +} + +//Exists checks if an identity contract exists +func (i service) Exists(ctx context.Context, did DID) error { + return isIdentityContract(did.ToAddress(), i.client) +} + +// ValidateKey checks if a given key is valid for the given centrifugeID. +func (i service) ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error { + contract, opts, _, err := i.prepareCall(did) + if err != nil { + return err + } + + key32, err := utils.SliceToByte32(key) + if err != nil { + return err + } + + keys, err := contract.GetKey(opts, key32) + if err != nil { + return err + } + + for _, p := range keys.Purposes { + if p.Cmp(big.NewInt(purpose)) == 0 { + return nil + } + } + + return errors.New("identity contract doesn't have a key with requested purpose") +} + +// GetClientsP2PURLs returns p2p urls associated with each centIDs +// will error out at first failure +func (i service) GetClientsP2PURLs(dids []*DID) ([]string, error) { + urls := make([]string, len(dids)) + + for idx, did := range dids { + url, err := i.GetClientP2PURL(*did) + if err != nil { + return nil, err + } + urls[idx] = url + + } + + return urls, nil +} + func getKeyPairsFromConfig(config config.Configuration) (map[int]Key, error) { keys := map[int]Key{} var pk []byte diff --git a/identity/did/service_integration_test.go b/identity/did/service_integration_test.go index 00c45b5cb..e5947f73e 100644 --- a/identity/did/service_integration_test.go +++ b/identity/did/service_integration_test.go @@ -4,9 +4,13 @@ package did import ( "context" + "fmt" "math/big" "testing" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/ethereum/go-ethereum/common" @@ -59,11 +63,11 @@ func deployIdentityContract(t *testing.T) *DID { } -func addKey(aCtx context.Context, t *testing.T, idSrv Service, testKey Key) { +func addKey(aCtx context.Context, t *testing.T, did DID, idSrv Service, testKey Key) { err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") - response, err := idSrv.GetKey(aCtx, testKey.GetKey()) + response, err := idSrv.GetKey(did, testKey.GetKey()) assert.Nil(t, err, "get Key should be successful") assert.Equal(t, testKey.GetPurpose(), response.Purposes[0], "key should have the same purpose") @@ -76,7 +80,7 @@ func TestServiceAddKey_successful(t *testing.T) { idSrv := initIdentity() testKey := getTestKey() - addKey(aCtx, t, idSrv, testKey) + addKey(aCtx, t, *did, idSrv, testKey) resetDefaultCentID() } @@ -90,7 +94,7 @@ func TestServiceAddKey_fail(t *testing.T) { err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") - _, err = idSrv.GetKey(aCtx, testKey.GetKey()) + _, err = idSrv.GetKey(did, testKey.GetKey()) assert.Error(t, err, "no contract code at given address") resetDefaultCentID() @@ -121,13 +125,13 @@ func TestService_IsSignedWithPurpose(t *testing.T) { assert.Nil(t, err, "should sign a message") //correct signature and purpose - signed, err := idSrv.IsSignedWithPurpose(aCtx, msg, signature, purpose) + signed, err := idSrv.IsSignedWithPurpose(*did, msg, signature, purpose) assert.Nil(t, err, "sign verify should not throw an error") assert.True(t, signed, "signature should be correct") //false purpose falsePurpose := utils.ByteSliceToBigInt([]byte{42}) - signed, err = idSrv.IsSignedWithPurpose(aCtx, msg, signature, falsePurpose) + signed, err = idSrv.IsSignedWithPurpose(*did, msg, signature, falsePurpose) assert.Nil(t, err, "sign verify should not throw an error") assert.False(t, signed, "signature should be false (wrong purpose)") @@ -135,7 +139,7 @@ func TestService_IsSignedWithPurpose(t *testing.T) { _, sk2, _ := secp256k1.GenerateSigningKeyPair() signature, err = secp256k1.SignEthereum(msg[:], sk2) assert.Nil(t, err, "should sign a message") - signed, err = idSrv.IsSignedWithPurpose(aCtx, msg, signature, purpose) + signed, err = idSrv.IsSignedWithPurpose(*did, msg, signature, purpose) assert.Nil(t, err, "sign verify should not throw an error") assert.False(t, signed, "signature should be wrong key pair") resetDefaultCentID() @@ -156,7 +160,7 @@ func TestService_AddMultiPurposeKey(t *testing.T) { err := idSrv.AddMultiPurposeKey(aCtx, key, purposes, keyType) assert.Nil(t, err, "add key with multiple purposes should be successful") - response, err := idSrv.GetKey(aCtx, key) + response, err := idSrv.GetKey(*did, key) assert.Nil(t, err, "get Key should be successful") assert.Equal(t, purposeOne, response.Purposes[0], "key should have the same first purpose") @@ -170,17 +174,98 @@ func TestService_RevokeKey(t *testing.T) { idSrv := initIdentity() testKey := getTestKey() - addKey(aCtx, t, idSrv, testKey) + addKey(aCtx, t, *did, idSrv, testKey) - response, err := idSrv.GetKey(aCtx, testKey.GetKey()) + response, err := idSrv.GetKey(*did, testKey.GetKey()) assert.Equal(t, utils.ByteSliceToBigInt([]byte{0}), response.RevokedAt, "key should be not revoked") idSrv.RevokeKey(aCtx, testKey.GetKey()) //check if key is revoked - response, err = idSrv.GetKey(aCtx, testKey.GetKey()) + response, err = idSrv.GetKey(*did, testKey.GetKey()) assert.Nil(t, err, "get Key should be successful") assert.NotEqual(t, utils.ByteSliceToBigInt([]byte{0}), response.RevokedAt, "key should be revoked") resetDefaultCentID() } + +func TestExists(t *testing.T) { + did := deployIdentityContract(t) + + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + err := idSrv.Exists(aCtx, *did) + assert.Nil(t, err, "identity contract should exist") + + err = idSrv.Exists(aCtx, NewDIDFromString("0x123")) + assert.Error(t, err, "identity contract should not exist") + resetDefaultCentID() + +} + +func TestValidateKey(t *testing.T) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + testKey := getTestKey() + addKey(aCtx, t, *did, idSrv, testKey) + + key32 := testKey.GetKey() + + var purpose int64 + purpose = 123 // test purpose + + err := idSrv.ValidateKey(aCtx, *did, utils.Byte32ToSlice(key32), purpose) + assert.Nil(t, err, "key with purpose should exist") + + purpose = 1 //false purpose + err = idSrv.ValidateKey(aCtx, *did, utils.Byte32ToSlice(key32), purpose) + assert.Error(t, err, "key with purpose should not exist") + resetDefaultCentID() + +} + +func addP2PKeyTestGetClientP2PURL(t *testing.T) (*DID, string) { + did := deployIdentityContract(t) + aCtx := getTestDIDContext(t, *did) + idSrv := initIdentity() + + p2pKey := utils.RandomByte32() + + testKey := &key{Key: p2pKey, Purpose: utils.ByteSliceToBigInt([]byte{identity.KeyPurposeP2P}), Type: utils.ByteSliceToBigInt([]byte{123})} + addKey(aCtx, t, *did, idSrv, testKey) + + url, err := idSrv.GetClientP2PURL(*did) + assert.Nil(t, err, "should return p2p url") + + p2pID, err := ed25519.PublicKeyToP2PKey(p2pKey) + assert.Nil(t, err) + + expectedUrl := fmt.Sprintf("/ipfs/%s", p2pID.Pretty()) + + assert.Equal(t, expectedUrl, url, "ipfs url not correct") + return did, url + +} + +func TestGetClientP2PURL(t *testing.T) { + addP2PKeyTestGetClientP2PURL(t) + resetDefaultCentID() + +} + +func TestGetClientP2PURLs(t *testing.T) { + didA, urlA := addP2PKeyTestGetClientP2PURL(t) + didB, urlB := addP2PKeyTestGetClientP2PURL(t) + idSrv := initIdentity() + + urls, err := idSrv.GetClientsP2PURLs([]*DID{didA, didB}) + assert.Nil(t, err) + + assert.Equal(t, urlA, urls[0], "p2p url should be the same") + assert.Equal(t, urlB, urls[1], "p2p url should be the same") + resetDefaultCentID() + +} diff --git a/identity/identity.go b/identity/identity.go index 54dc76be6..4431ef46d 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -112,18 +112,19 @@ type WatchIdentity struct { } // Service is used to interact with centrifuge identities +// Deprecated type Service interface { - // LookupIdentityForID looks up if the identity for given CentID exists on ethereum + // LookupIdentityForID looks up if the identity for given CentID exists on ethereum TODO: remove func LookupIdentityForID(centrifugeID CentID) (id Identity, err error) - // CreateIdentity creates an identity representing the id on ethereum + // CreateIdentity creates an identity representing the id on ethereum TODO: edit remove CentID CreateIdentity(ctx context.Context, centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) // CheckIdentityExists checks if the identity represented by id actually exists on ethereum CheckIdentityExists(centrifugeID CentID) (exists bool, err error) - // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID + // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID TODO: remove func GetIdentityAddress(centID CentID) (common.Address, error) // GetClientP2PURL returns the p2p url associated with the centID @@ -133,16 +134,16 @@ type Service interface { // will error out at first failure GetClientsP2PURLs(centIDs []CentID) ([]string, error) - // GetIdentityKey returns the key for provided identity + // GetIdentityKey returns the key for provided identity TODO: change func name GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) // ValidateKey checks if a given key is valid for the given centrifugeID. ValidateKey(centID CentID, key []byte, purpose int) error - // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file + // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file TODO: not part of the service anymore AddKeyFromConfig(config Config, purpose int) error - // ValidateSignature validates a signature on a message based on identity data + // ValidateSignature validates a signature on a message based on identity data TODO: add purpose parameter ValidateSignature(signature *coredocumentpb.Signature, message []byte) error } From c1e40895392e3ecd102d2400ae52ec7b2aee75f0 Mon Sep 17 00:00:00 2001 From: Charly Date: Fri, 15 Feb 2019 13:03:35 +0100 Subject: [PATCH 190/220] Refactor/nfts remove cd (#747) --- Gopkg.lock | 1 + coredocument/coredocument.go | 477 --------------------- coredocument/coredocument_test.go | 396 ----------------- coredocument/read_acls.go | 245 ----------- coredocument/read_acls_test.go | 123 ------ documents/anchor.go | 8 +- documents/documents_test/anchor_test.go | 22 +- documents/documents_test/service_test.go | 134 +++--- documents/invoice/handler_test.go | 6 +- documents/invoice/model.go | 54 +-- documents/invoice/model_test.go | 132 +++--- documents/invoice/service.go | 34 +- documents/invoice/service_test.go | 180 ++++---- documents/invoice/utils_test.go | 12 +- documents/model.go | 223 +++++++++- documents/model_test.go | 105 ++++- documents/processor.go | 42 +- documents/processor_test.go | 111 ++--- documents/purchaseorder/model.go | 56 +-- documents/purchaseorder/model_test.go | 108 ++--- documents/purchaseorder/service.go | 32 +- documents/purchaseorder/service_test.go | 163 ++++--- documents/purchaseorder/utils_test.go | 12 +- documents/read_acls_test.go | 75 ---- documents/registry_test.go | 30 +- documents/service.go | 52 ++- documents/validator.go | 53 ++- documents/validator_test.go | 129 +++--- nft/ethereum_payment_obligation.go | 29 +- nft/ethereum_payment_obligation_test.go | 16 +- nft/payment_obligation_integration_test.go | 5 +- p2p/client.go | 30 +- p2p/client_integration_test.go | 47 +- p2p/client_test.go | 25 +- p2p/receiver/handler.go | 23 +- p2p/receiver/handler_integration_test.go | 112 ++--- p2p/receiver/handler_test.go | 6 +- p2p/receiver/validator.go | 28 -- p2p/receiver/validator_test.go | 28 +- p2p/server_test.go | 8 +- testingutils/coredocument/coredocument.go | 40 -- testingutils/documents/documents.go | 47 +- 42 files changed, 1250 insertions(+), 2209 deletions(-) delete mode 100644 coredocument/coredocument.go delete mode 100644 coredocument/coredocument_test.go delete mode 100644 coredocument/read_acls.go delete mode 100644 coredocument/read_acls_test.go delete mode 100644 documents/read_acls_test.go delete mode 100644 testingutils/coredocument/coredocument.go diff --git a/Gopkg.lock b/Gopkg.lock index ed26e8e1f..4cbf3b520 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1519,6 +1519,7 @@ "github.com/gavv/httpexpect", "github.com/go-errors/errors", "github.com/gogo/protobuf/io", + "github.com/gogo/protobuf/proto", "github.com/golang/protobuf/proto", "github.com/golang/protobuf/protoc-gen-go", "github.com/golang/protobuf/ptypes", diff --git a/coredocument/coredocument.go b/coredocument/coredocument.go deleted file mode 100644 index dedde723b..000000000 --- a/coredocument/coredocument.go +++ /dev/null @@ -1,477 +0,0 @@ -package coredocument - -import ( - "crypto/sha256" - "fmt" - "strings" - - "github.com/golang/protobuf/proto" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/centrifuge/precise-proofs/proofs/proto" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -const ( - // CDRootField represents the coredocument root property of a tree - CDRootField = "cd_root" - // DataRootField represents the data root property of a tree - DataRootField = "data_root" - // DocumentTypeField represents the doc type property of a tree - DocumentTypeField = "document_type" - // SignaturesField represents the signatures property of a tree - SignaturesField = "signatures" - // SigningRootField represents the signature root property of a tree - SigningRootField = "signing_root" -) - -var compactProperties = map[string][]byte{ - CDRootField: {0, 0, 0, 7}, - DataRootField: {0, 0, 0, 5}, - DocumentTypeField: {0, 0, 0, 100}, - SignaturesField: {0, 0, 0, 6}, - SigningRootField: {0, 0, 0, 10}, -} - -// NewDefaultTree returns a DocumentTree with default opts -func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { - return NewDefaultTreeWithPrefix(salts, "") -} - -// NewDefaultTreeWithPrefix returns a DocumentTree with default opts passing a prefix to the tree leaves -func NewDefaultTreeWithPrefix(salts *proofs.Salts, prefix string) *proofs.DocumentTree { - var prop proofs.Property - if prefix != "" { - prop = proofs.NewProperty(prefix) - } - - t := proofs.NewDocumentTree(proofs.TreeOptions{EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) - return &t -} - -// NewLeafProperty returns a proof property with the literal and the compact -func NewLeafProperty(literal string, compact []byte) proofs.Property { - return proofs.NewProperty(literal, compact...) -} - -// getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used -// to create field proofs -func getDataProofHashes(document *coredocumentpb.CoreDocument, dataRoot []byte) (hashes [][]byte, err error) { - tree, err := GetDocumentSigningTree(document, dataRoot) - if err != nil { - return - } - - signingProof, err := tree.CreateProof("data_root") - if err != nil { - return - } - - rootProofHashes, err := getSigningRootProofHashes(document) - if err != nil { - return - } - - return append(signingProof.SortedHashes, rootProofHashes...), err -} - -// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. This method is used -// to create field proofs -func getSigningRootProofHashes(document *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { - tree, err := GetDocumentRootTree(document) - if err != nil { - return - } - rootProof, err := tree.CreateProof("signing_root") - if err != nil { - return - } - return rootProof.SortedHashes, err -} - -// CalculateSigningRoot calculates the signing root of the core document -func CalculateSigningRoot(doc *coredocumentpb.CoreDocument, dataRoot []byte) error { - tree, err := GetDocumentSigningTree(doc, dataRoot) - if err != nil { - return err - } - - doc.SigningRoot = tree.RootHash() - return nil -} - -// CalculateDocumentRoot calculates the document root of the core document -func CalculateDocumentRoot(document *coredocumentpb.CoreDocument) error { - if len(document.SigningRoot) != 32 { - return errors.New("signing root invalid") - } - - tree, err := GetDocumentRootTree(document) - if err != nil { - return err - } - - document.DocumentRoot = tree.RootHash() - return nil -} - -// GetDocumentRootTree returns the merkle tree for the document root -func GetDocumentRootTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { - h := sha256.New() - tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) - - // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties[SigningRootField])}) - if err != nil { - return nil, err - } - // For every signature we create a LeafNode - sigProperty := NewLeafProperty(SignaturesField, compactProperties[SignaturesField]) - sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) - sigLengthNode := proofs.LeafNode{ - Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), - Salt: make([]byte, 32), - Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), - } - err = sigLengthNode.HashNode(h, false) - if err != nil { - return nil, err - } - sigLeafList[0] = sigLengthNode - for i, sig := range document.Signatures { - payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) - leaf := proofs.LeafNode{ - Hash: payload[:], - Hashed: true, - Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), - } - err = leaf.HashNode(h, false) - if err != nil { - return nil, err - } - sigLeafList[i+1] = leaf - } - err = tree.AddLeaves(sigLeafList) - if err != nil { - return nil, err - } - err = tree.Generate() - if err != nil { - return nil, err - } - return tree, nil -} - -// GetCoreDocTree returns the merkle tree for the coredoc root -func GetCoreDocTree(document *coredocumentpb.CoreDocument) (tree *proofs.DocumentTree, err error) { - h := sha256.New() - tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) - err = tree.AddLeavesFromDocument(document) - if err != nil { - return nil, err - } - - if document.EmbeddedData == nil { - return nil, errors.New("EmbeddedData cannot be nil when generating signing tree") - } - // Adding document type as it is an excluded field in the tree - documentTypeNode := proofs.LeafNode{ - Property: NewLeafProperty(DocumentTypeField, compactProperties[DocumentTypeField]), - Salt: make([]byte, 32), - Value: []byte(document.EmbeddedData.TypeUrl), - } - - err = documentTypeNode.HashNode(h, false) - if err != nil { - return nil, err - } - - err = tree.AddLeaf(documentTypeNode) - if err != nil { - return nil, err - } - - err = tree.Generate() - if err != nil { - return nil, err - } - return tree, nil -} - -// GetDocumentSigningTree returns the merkle tree for the signing root -func GetDocumentSigningTree(document *coredocumentpb.CoreDocument, dataRoot []byte) (tree *proofs.DocumentTree, err error) { - // coredoc tree - coreDocTree, err := GetCoreDocTree(document) - if err != nil { - return nil, err - } - - // create the signing tree with data root and coredoc root as siblings - tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) - err = tree.AddLeaves([]proofs.LeafNode{ - { - Property: NewLeafProperty(DataRootField, compactProperties[DataRootField]), - Hash: dataRoot, - Hashed: true, - }, - { - Property: NewLeafProperty(CDRootField, compactProperties[CDRootField]), - Hash: coreDocTree.RootHash(), - Hashed: true, - }, - }) - - if err != nil { - return nil, err - } - - err = tree.Generate() - if err != nil { - return nil, err - } - - return tree, nil -} - -// PrepareNewVersion creates a copy of the passed coreDocument with the version fields updated -// Adds collaborators and fills salts -// Note: new collaborators are added to the list with old collaborators. -func PrepareNewVersion(oldCD coredocumentpb.CoreDocument, collaborators []string) (*coredocumentpb.CoreDocument, error) { - ncd := New() - ucs, err := fetchUniqueCollaborators(oldCD.Collaborators, collaborators) - if err != nil { - return nil, errors.New("failed to decode collaborator: %v", err) - } - - cs := oldCD.Collaborators - for _, c := range ucs { - c := c - cs = append(cs, c[:]) - } - - ncd.Collaborators = cs - - // copy read rules and roles - ncd.Roles = oldCD.Roles - ncd.ReadRules = oldCD.ReadRules - err = addCollaboratorsToReadSignRules(ncd, ucs) - if err != nil { - return nil, err - } - - err = FillSalts(ncd) - if err != nil { - return nil, err - } - - if oldCD.DocumentIdentifier == nil { - return nil, errors.New("coredocument.DocumentIdentifier is nil") - } - ncd.DocumentIdentifier = oldCD.DocumentIdentifier - - if oldCD.CurrentVersion == nil { - return nil, errors.New("coredocument.CurrentVersion is nil") - } - ncd.PreviousVersion = oldCD.CurrentVersion - - if oldCD.NextVersion == nil { - return nil, errors.New("coredocument.NextVersion is nil") - } - ncd.CurrentVersion = oldCD.NextVersion - ncd.NextVersion = utils.RandomSlice(32) - if oldCD.DocumentRoot == nil { - return nil, errors.New("coredocument.DocumentRoot is nil") - } - ncd.PreviousRoot = oldCD.DocumentRoot - return ncd, nil -} - -// New returns a new core document -// Note: collaborators and salts are to be filled by the caller -func New() *coredocumentpb.CoreDocument { - id := utils.RandomSlice(32) - return &coredocumentpb.CoreDocument{ - DocumentIdentifier: id, - CurrentVersion: id, - NextVersion: utils.RandomSlice(32), - } -} - -// NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts -func NewWithCollaborators(collaborators []string) (*coredocumentpb.CoreDocument, error) { - cd := New() - ids, err := identity.CentIDsFromStrings(collaborators) - if err != nil { - return nil, errors.New("failed to decode collaborator: %v", err) - } - - for i := range ids { - cd.Collaborators = append(cd.Collaborators, ids[i][:]) - } - - err = initReadRules(cd, ids) - if err != nil { - return nil, errors.New("failed to init read rules: %v", err) - } - - err = FillSalts(cd) - if err != nil { - return nil, err - } - - return cd, nil -} - -// GetExternalCollaborators returns collaborators of a document without the own centID. -func GetExternalCollaborators(selfCentID identity.CentID, doc *coredocumentpb.CoreDocument) ([][]byte, error) { - var collabs [][]byte - - for _, collab := range doc.Collaborators { - collabID, err := identity.ToCentID(collab) - if err != nil { - return nil, errors.New("failed to convert to CentID: %v", err) - } - if !selfCentID.Equal(collabID) { - collabs = append(collabs, collab) - } - } - - return collabs, nil -} - -// GenerateNewSalts generates salts for new document -func GenerateNewSalts(document proto.Message, prefix string) (*proofs.Salts, error) { - docSalts := &proofs.Salts{} - t := NewDefaultTreeWithPrefix(docSalts, prefix) - err := t.AddLeavesFromDocument(document) - if err != nil { - return nil, err - } - return docSalts, nil -} - -// ConvertToProtoSalts converts proofSalts into protocolSalts -func ConvertToProtoSalts(proofSalts *proofs.Salts) []*coredocumentpb.DocumentSalt { - protoSalts := make([]*coredocumentpb.DocumentSalt, len(*proofSalts)) - if proofSalts == nil { - return nil - } - - for i, pSalt := range *proofSalts { - protoSalts[i] = &coredocumentpb.DocumentSalt{Value: pSalt.Value, Compact: pSalt.Compact} - } - - return protoSalts -} - -// ConvertToProofSalts converts protocolSalts into proofSalts -func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salts { - proofSalts := make(proofs.Salts, len(protoSalts)) - if protoSalts == nil { - return nil - } - - for _, pSalt := range protoSalts { - proofSalts = append(proofSalts, proofs.Salt{Value: pSalt.Value, Compact: pSalt.Compact}) - } - - return &proofSalts -} - -// FillSalts creates a new coredocument.Salts and fills it -func FillSalts(doc *coredocumentpb.CoreDocument) error { - salts, err := GenerateNewSalts(doc, "") - if err != nil { - return err - } - - doc.CoredocumentSalts = ConvertToProtoSalts(salts) - return nil -} - -// GetTypeURL returns the type of the embedded document -func GetTypeURL(coreDocument *coredocumentpb.CoreDocument) (string, error) { - - if coreDocument == nil { - return "", errors.New("core document is nil") - } - - if coreDocument.EmbeddedData == nil { - return "", errors.New("core document doesn't have embedded data") - } - - if coreDocument.EmbeddedData.TypeUrl == "" { - return "", errors.New("typeUrl not set properly") - } - return coreDocument.EmbeddedData.TypeUrl, nil -} - -// CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs -func CreateProofs(dataTree *proofs.DocumentTree, coreDoc *coredocumentpb.CoreDocument, fields []string) (proofs []*proofspb.Proof, err error) { - signingRootProofHashes, err := getSigningRootProofHashes(coreDoc) - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - - cdtree, err := GetCoreDocTree(coreDoc) - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - - dataRoot := dataTree.RootHash() - cdRoot := cdtree.RootHash() - - // We support fields that belong to different document trees, as we do not prepend a tree prefix to the field, the approach - // is to try in both trees to find the field and create the proof accordingly - for _, field := range fields { - proof, err := dataTree.CreateProof(field) - if err != nil { - if strings.Contains(err.Error(), "No such field") { - proof, err = cdtree.CreateProof(field) - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - proof.SortedHashes = append(proof.SortedHashes, dataRoot) - } else { - return nil, errors.New("createProofs error %v", err) - } - } else { - proof.SortedHashes = append(proof.SortedHashes, cdRoot) - } - proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) - proofs = append(proofs, &proof) - } - - return proofs, nil -} - -func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.CentID, err error) { - ocsm := make(map[string]struct{}) - for _, c := range oldCollabs { - ocsm[hexutil.Encode(c)] = struct{}{} - } - - var uc []string - for _, c := range newCollabs { - if _, ok := ocsm[c]; ok { - continue - } - - uc = append(uc, c) - } - - for _, c := range uc { - id, err := identity.CentIDFromString(c) - if err != nil { - return nil, err - } - - ids = append(ids, id) - } - - return ids, nil -} diff --git a/coredocument/coredocument_test.go b/coredocument/coredocument_test.go deleted file mode 100644 index a2def7839..000000000 --- a/coredocument/coredocument_test.go +++ /dev/null @@ -1,396 +0,0 @@ -// +build unit - -package coredocument - -import ( - "crypto/sha256" - "flag" - "os" - "testing" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" -) - -var ctx = map[string]interface{}{} -var cfg config.Configuration - -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &config.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") - cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - flag.Parse() - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - -func TestGetSigningProofHashes(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - cd := New() - cd.EmbeddedData = docAny - cd.DataRoot = utils.RandomSlice(32) - err := FillSalts(cd) - assert.NoError(t, err) - - err = CalculateSigningRoot(cd, cd.DataRoot) - assert.Nil(t, err) - - err = CalculateDocumentRoot(cd) - assert.Nil(t, err) - - hashes, err := getSigningRootProofHashes(cd) - assert.Nil(t, err) - assert.Equal(t, 1, len(hashes)) - - valid, err := proofs.ValidateProofSortedHashes(cd.SigningRoot, hashes, cd.DocumentRoot, sha256.New()) - assert.True(t, valid) - assert.Nil(t, err) -} - -func TestGetDataProofHashes(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - cd := New() - cd.EmbeddedData = docAny - cd.DataRoot = utils.RandomSlice(32) - err := FillSalts(cd) - assert.NoError(t, err) - - err = CalculateSigningRoot(cd, cd.DataRoot) - assert.Nil(t, err) - - err = CalculateDocumentRoot(cd) - assert.Nil(t, err) - - hashes, err := getDataProofHashes(cd, cd.DataRoot) - assert.Nil(t, err) - assert.Equal(t, 2, len(hashes)) - - valid, err := proofs.ValidateProofSortedHashes(cd.DataRoot, hashes, cd.DocumentRoot, sha256.New()) - assert.True(t, valid) - assert.Nil(t, err) -} - -func TestGetDocumentSigningTree(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - cd := New() - cd.EmbeddedData = docAny - err := FillSalts(cd) - assert.NoError(t, err) - tree, err := GetDocumentSigningTree(cd, cd.DataRoot) - assert.Nil(t, err) - assert.NotNil(t, tree) - - _, leaf := tree.GetLeafByProperty("data_root") - assert.NotNil(t, leaf) - - _, leaf = tree.GetLeafByProperty("cd_root") - assert.NotNil(t, leaf) -} - -func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { - cd := New() - err := FillSalts(cd) - assert.NoError(t, err) - tree, err := GetDocumentSigningTree(cd, cd.DataRoot) - assert.NotNil(t, err) - assert.Nil(t, tree) -} - -// TestGetDocumentRootTree tests that the documentroottree is properly calculated -func TestGetDocumentRootTree(t *testing.T) { - cd := &coredocumentpb.CoreDocument{SigningRoot: []byte{0x72, 0xee, 0xb8, 0x88, 0x92, 0xf7, 0x6, 0x19, 0x82, 0x76, 0xe9, 0xe7, 0xfe, 0xcc, 0x33, 0xa, 0x66, 0x78, 0xd4, 0xa6, 0x5f, 0xf6, 0xa, 0xca, 0x2b, 0xe4, 0x17, 0xa9, 0xf6, 0x15, 0x67, 0xa1}} - tree, err := GetDocumentRootTree(cd) - - // Manually constructing the two node tree: - signaturesLengthLeaf := sha256.Sum256(append([]byte("signatures.length0"), make([]byte, 32)...)) - expectedRootHash := sha256.Sum256(append(signaturesLengthLeaf[:], cd.SigningRoot...)) - assert.Nil(t, err) - assert.Equal(t, expectedRootHash[:], tree.RootHash()) -} - -func TestPrepareNewVersion(t *testing.T) { - var doc coredocumentpb.CoreDocument - id := utils.RandomSlice(32) - cv := id - nv := utils.RandomSlice(32) - dr := utils.RandomSlice(32) - doc = coredocumentpb.CoreDocument{} - - // failed new with collaborators - collabs := []string{"some ID"} - newDoc, err := PrepareNewVersion(doc, collabs) - assert.Error(t, err) - assert.Nil(t, newDoc) - - // missing doc identifier - collabs = []string{"0x010203040506"} - newDoc, err = PrepareNewVersion(doc, collabs) - assert.NotNil(t, err) - assert.Nil(t, newDoc) - - //missing current version - doc.DocumentIdentifier = id - newDoc, err = PrepareNewVersion(doc, collabs) - assert.NotNil(t, err) - assert.Nil(t, newDoc) - - doc.CurrentVersion = cv - newDoc, err = PrepareNewVersion(doc, collabs) - assert.NotNil(t, err) - assert.Nil(t, newDoc) - - doc.NextVersion = nv - newDoc, err = PrepareNewVersion(doc, collabs) - assert.NotNil(t, err) - assert.Nil(t, newDoc) - - doc.CurrentVersion = cv - doc.NextVersion = nv - doc.DocumentRoot = dr - - newDoc, err = PrepareNewVersion(doc, collabs) - assert.Nil(t, err) - - // original document hasn't changed - assert.Equal(t, cv, doc.CurrentVersion) - - // new document has changed - assert.Equal(t, id, newDoc.DocumentIdentifier) - assert.Equal(t, cv, newDoc.PreviousVersion) - assert.Equal(t, nv, newDoc.CurrentVersion) - assert.Equal(t, dr, newDoc.PreviousRoot) - assert.Nil(t, newDoc.DocumentRoot) -} - -func TestNewWithCollaborators(t *testing.T) { - // messed up collaborators - c := []string{"some id"} - cd, err := NewWithCollaborators(c) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to decode collaborator") - assert.Nil(t, cd) - - // success - c1 := utils.RandomSlice(6) - c2 := utils.RandomSlice(6) - c = []string{hexutil.Encode(c1), hexutil.Encode(c2)} - cd, err = NewWithCollaborators(c) - assert.Nil(t, err) - assert.NotNil(t, cd) - assert.NotNil(t, cd.DocumentIdentifier) - assert.NotNil(t, cd.CurrentVersion) - assert.NotNil(t, cd.NextVersion) - assert.NotNil(t, cd.Collaborators) - assert.NotNil(t, cd.CoredocumentSalts) - assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) -} - -func TestCreateProofs(t *testing.T) { - h := sha256.New() - testTree := NewDefaultTree(nil) - props := []proofs.Property{NewLeafProperty("sample_field", []byte{0, 0, 0, 200}), NewLeafProperty("sample_field2", []byte{0, 0, 0, 202})} - err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[0]}) - assert.NoError(t, err) - err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[1]}) - assert.NoError(t, err) - err = testTree.Generate() - assert.NoError(t, err) - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - cd := New() - cd.EmbeddedData = docAny - cd.DocumentIdentifier = utils.RandomSlice(32) - cd.NextVersion = utils.RandomSlice(32) - cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} - err = FillSalts(cd) - assert.NoError(t, err) - err = CalculateSigningRoot(cd, testTree.RootHash()) - assert.NoError(t, err) - err = CalculateDocumentRoot(cd) - assert.NoError(t, err) - cdTree, err := GetCoreDocTree(cd) - assert.NoError(t, err) - tests := []struct { - fieldName string - fromCoreDoc bool - proofLength int - }{ - { - "sample_field", - false, - 3, - }, - { - "document_identifier", - true, - 6, - }, - { - "sample_field2", - false, - 3, - }, - { - "collaborators[0]", - true, - 6, - }, - } - for _, test := range tests { - t.Run(test.fieldName, func(t *testing.T) { - p, err := CreateProofs(testTree, cd, []string{test.fieldName}) - assert.NoError(t, err) - assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) - var l *proofs.LeafNode - if test.fromCoreDoc { - _, l = cdTree.GetLeafByProperty(test.fieldName) - } else { - _, l = testTree.GetLeafByProperty(test.fieldName) - } - valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) - assert.NoError(t, err) - assert.True(t, valid) - }) - } - -} - -func TestGetExternalCollaborators(t *testing.T) { - c1 := utils.RandomSlice(6) - c2 := utils.RandomSlice(6) - c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} - cd, err := NewWithCollaborators(c) - assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - self, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) - assert.NoError(t, err) - collaborators, err := GetExternalCollaborators(self.ID, cd) - assert.Nil(t, err) - assert.NotNil(t, collaborators) - assert.Equal(t, [][]byte{c1, c2}, collaborators) -} - -func TestGetExternalCollaborators_WrongIDFormat(t *testing.T) { - c1 := utils.RandomSlice(6) - c2 := utils.RandomSlice(6) - c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} - cd, err := NewWithCollaborators(c) - assert.Equal(t, [][]byte{c1, c2}, cd.Collaborators) - cd.Collaborators[1] = utils.RandomSlice(5) - self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) - _, err = GetExternalCollaborators(self.ID, cd) - assert.NotNil(t, err) -} - -func Test_fetchUniqueCollaborators(t *testing.T) { - tests := []struct { - old [][]byte - new []string - result []identity.CentID - err bool - }{ - { - new: []string{"0x010203040506"}, - result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, - }, - - { - old: [][]byte{{1, 2, 3, 2, 3, 1}}, - new: []string{"0x010203040506"}, - result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, - }, - - { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, - new: []string{"0x010203040506"}, - }, - - { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, - }, - - // new collaborator with wrong format - { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, - new: []string{"0x0102030405"}, - err: true, - }, - } - - for _, c := range tests { - uc, err := fetchUniqueCollaborators(c.old, c.new) - if err != nil { - if c.err { - continue - } - - t.Fatal(err) - } - - assert.Equal(t, c.result, uc) - } -} - -func TestPrepareNewVersion_read_rules(t *testing.T) { - cd, err := NewWithCollaborators([]string{"0x010203040506"}) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) - assert.Equal(t, cd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) - cd.DocumentRoot = utils.RandomSlice(32) - - // prepare with zero collaborators - ncd, err := PrepareNewVersion(*cd, nil) - assert.NoError(t, err) - assert.NotNil(t, ncd) - assert.Len(t, ncd.ReadRules, 1) - assert.Len(t, ncd.Roles, 1) - assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) - - // prepare with no unique one - ncd, err = PrepareNewVersion(*cd, []string{"0x010203040506"}) - assert.NoError(t, err) - assert.NotNil(t, ncd) - assert.Len(t, ncd.ReadRules, 1) - assert.Len(t, ncd.Roles, 1) - assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) - - // prepare with unique collaborators - ncd, err = PrepareNewVersion(*cd, []string{"0x010202030203", "0x020301020304"}) - assert.NoError(t, err) - assert.NotNil(t, ncd) - assert.Len(t, ncd.ReadRules, 2) - assert.Len(t, ncd.Roles, 2) - assert.Equal(t, ncd.Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}, {1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) - assert.Equal(t, ncd.Roles[0].Collaborators, [][]byte{{1, 2, 3, 4, 5, 6}}) - assert.Equal(t, ncd.Roles[1].Collaborators, [][]byte{{1, 2, 2, 3, 2, 3}, {2, 3, 1, 2, 3, 4}}) -} diff --git a/coredocument/read_acls.go b/coredocument/read_acls.go deleted file mode 100644 index ad5e2c32d..000000000 --- a/coredocument/read_acls.go +++ /dev/null @@ -1,245 +0,0 @@ -package coredocument - -import ( - "bytes" - - "github.com/centrifuge/go-centrifuge/utils" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/ethereum/go-ethereum/common" -) - -const ( - // ErrZeroCollaborators error when no collaborators are passed - ErrZeroCollaborators = errors.Error("require at least one collaborator") - - // nftByteCount is the length of combined bytes of registry and tokenID - nftByteCount = 52 -) - -// TokenRegistry defines NFT retrieval functions. -type TokenRegistry interface { - // OwnerOf to retrieve owner of the tokenID - OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) -} - -// initReadRules initiates the read rules for a given coredocument. -// Collaborators are given Read_Sign action. -// if the rules are created already, this is a no-op. -func initReadRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { - if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { - return nil - } - - if len(collabs) < 1 { - return ErrZeroCollaborators - } - - return addCollaboratorsToReadSignRules(cd, collabs) -} - -func addCollaboratorsToReadSignRules(cd *coredocumentpb.CoreDocument, collabs []identity.CentID) error { - if len(collabs) == 0 { - return nil - } - - // create a role for given collaborators - role := new(coredocumentpb.Role) - rk, err := utils.ConvertIntToByte32(len(cd.Roles)) - if err != nil { - return err - } - role.RoleKey = rk[:] - for _, c := range collabs { - c := c - role.Collaborators = append(role.Collaborators, c[:]) - } - - addNewRule(cd, role, coredocumentpb.Action_ACTION_READ_SIGN) - - return nil -} - -// addNewRule creates a new rule as per the role and action. -func addNewRule(cd *coredocumentpb.CoreDocument, role *coredocumentpb.Role, action coredocumentpb.Action) { - cd.Roles = append(cd.Roles, role) - - rule := new(coredocumentpb.ReadRule) - rule.Roles = append(rule.Roles, role.RoleKey) - rule.Action = action - cd.ReadRules = append(cd.ReadRules, rule) -} - -// AddNFTToReadRules adds NFT token to the read rules of core document. -func AddNFTToReadRules(cd *coredocumentpb.CoreDocument, registry common.Address, tokenID []byte) error { - nft, err := ConstructNFT(registry, tokenID) - if err != nil { - return errors.New("failed to construct NFT: %v", err) - } - - role := new(coredocumentpb.Role) - rk, err := utils.ConvertIntToByte32(len(cd.Roles)) - if err != nil { - return err - } - role.RoleKey = rk[:] - role.Nfts = append(role.Nfts, nft) - addNewRule(cd, role, coredocumentpb.Action_ACTION_READ) - return FillSalts(cd) -} - -// ConstructNFT appends registry and tokenID to byte slice -func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { - var nft []byte - // first 20 bytes of registry - nft = append(nft, registry.Bytes()...) - - // next 32 bytes of the tokenID - nft = append(nft, tokenID...) - - if len(nft) != nftByteCount { - return nil, errors.New("byte length mismatch") - } - - return nft, nil -} - -// ReadAccessValidator defines validator functions for account . -type ReadAccessValidator interface { - AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool - NFTOwnerCanRead( - cd *coredocumentpb.CoreDocument, - registry common.Address, - tokenID []byte, - account identity.CentID) error -} - -// readAccessValidator implements ReadAccessValidator. -type readAccessValidator struct { - tokenRegistry TokenRegistry -} - -// AccountCanRead validate if the core document can be read by the account . -// Returns an error if not. -func (r readAccessValidator) AccountCanRead(cd *coredocumentpb.CoreDocument, account identity.CentID) bool { - // loop though read rules - return findRole(cd, coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { - return isAccountInRole(role, account) - }) -} - -func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { - for _, role := range roles { - if utils.IsSameByteSlice(role.RoleKey, key) { - return role, nil - } - } - - return nil, errors.New("role %d not found", key) -} - -// isAccountInRole returns true if account is in the given role as collaborators. -func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { - for _, id := range role.Collaborators { - if bytes.Equal(id, account[:]) { - return true - } - } - - return false -} - -// AccountValidator returns the ReadAccessValidator to verify account . -func AccountValidator() ReadAccessValidator { - return readAccessValidator{} -} - -// NftValidator returns the ReadAccessValidator for nft owner verification. -func NftValidator(tr TokenRegistry) ReadAccessValidator { - return readAccessValidator{tokenRegistry: tr} -} - -// NFTOwnerCanRead checks if the nft owner/account can read the document -// Note: signature should be calculated from the hash which is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -func (r readAccessValidator) NFTOwnerCanRead( - cd *coredocumentpb.CoreDocument, - registry common.Address, - tokenID []byte, - account identity.CentID) error { - - // check if the account can read the doc - if r.AccountCanRead(cd, account) { - return nil - } - - // check if the nft is present in read rules - found := findRole(cd, coredocumentpb.Action_ACTION_READ, func(role *coredocumentpb.Role) bool { - return isNFTInRole(role, registry, tokenID) - }) - - if !found { - return errors.New("nft missing") - } - - // get the owner of the NFT - owner, err := r.tokenRegistry.OwnerOf(registry, tokenID) - if err != nil { - return errors.New("failed to get NFT owner: %v", err) - } - - // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address - if !bytes.Equal(owner.Bytes(), account[:]) { - return errors.New("account (%v) not owner of the NFT", account.String()) - } - - return nil -} - -// findRole calls OnRole for every role, -// if onRole returns true, returns true -// else returns false -func findRole( - cd *coredocumentpb.CoreDocument, - action coredocumentpb.Action, - onRole func(role *coredocumentpb.Role) bool) bool { - for _, rule := range cd.ReadRules { - if rule.Action != action { - continue - } - - for _, rk := range rule.Roles { - role, err := getRole(rk, cd.Roles) - if err != nil { - // seems like roles and rules are not in sync - // skip to next one - continue - } - - if onRole(role) { - return true - } - - } - } - - return false -} - -// isNFTInRole checks if the given nft(registry + token) is part of the core document role. -func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) bool { - enft, err := ConstructNFT(registry, tokenID) - if err != nil { - return false - } - - for _, n := range role.Nfts { - if bytes.Equal(n, enft) { - return true - } - } - - return false -} diff --git a/coredocument/read_acls_test.go b/coredocument/read_acls_test.go deleted file mode 100644 index 44e10373b..000000000 --- a/coredocument/read_acls_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// +build unit - -package coredocument - -import ( - "testing" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestReadACLs_initReadRules(t *testing.T) { - cd := New() - err := initReadRules(cd, nil) - assert.Error(t, err) - assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) - - cs := []identity.CentID{identity.RandomCentID()} - err = initReadRules(cd, cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) - - err = initReadRules(cd, cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) -} - -func TestReadAccessValidator_AccountCanRead(t *testing.T) { - pv := AccountValidator() - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) - - cd, err := NewWithCollaborators([]string{account.String()}) - assert.NoError(t, err) - assert.NotNil(t, cd.ReadRules) - assert.NotNil(t, cd.Roles) - - // account who cant access - rcid := identity.RandomCentID() - assert.False(t, pv.AccountCanRead(cd, rcid)) - - // account can access - assert.True(t, pv.AccountCanRead(cd, account)) -} - -func Test_addNFTToReadRules(t *testing.T) { - // wrong registry or token format - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(34) - - err := AddNFTToReadRules(nil, registry, tokenID) - assert.Error(t, err) - - cd, err := NewWithCollaborators([]string{"0x010203040506"}) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) - assert.Len(t, cd.Roles, 1) - - tokenID = utils.RandomSlice(32) - err = AddNFTToReadRules(cd, registry, tokenID) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 2) - assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) - assert.Len(t, cd.Roles, 2) -} - -type mockRegistry struct { - mock.Mock -} - -func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { - args := m.Called(registry, tokenID) - addr, _ := args.Get(0).(common.Address) - return addr, args.Error(1) -} - -func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) - - cd, err := NewWithCollaborators([]string{account.String()}) - assert.NoError(t, err) - - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - - // account can read - validator := NftValidator(nil) - err = validator.NFTOwnerCanRead(cd, registry, nil, account) - assert.NoError(t, err) - - // account not in read rules and nft missing - account, err = identity.CentIDFromString("0x010203040505") - assert.NoError(t, err) - tokenID := utils.RandomSlice(32) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - - tr := mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() - AddNFTToReadRules(cd, registry, tokenID) - validator = NftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - assert.Contains(t, err, "failed to get owner of") - tr.AssertExpectations(t) - - // not the same owner - owner := common.BytesToAddress(utils.RandomSlice(20)) - tr = mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() - validator = NftValidator(tr) - err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) - assert.Error(t, err) - tr.AssertExpectations(t) -} diff --git a/documents/anchor.go b/documents/anchor.go index 1143d0838..cc43164d7 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -3,7 +3,6 @@ package documents import ( "context" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" ) @@ -11,7 +10,7 @@ import ( // AnchorProcessor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type AnchorProcessor interface { - Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) + Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.CentID) (err error) PrepareForSignatureRequests(ctx context.Context, model Model) error RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error @@ -25,12 +24,11 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, updater updaterFunc) (Model, error) { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, err } - - id := cd.CurrentVersion + id := dm.Document.CurrentVersion err = proc.PrepareForSignatureRequests(ctx, model) if err != nil { return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to prepare document for signatures: %v", err)) diff --git a/documents/documents_test/anchor_test.go b/documents/documents_test/anchor_test.go index 41c2a285d..430ebab29 100644 --- a/documents/documents_test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -7,9 +7,9 @@ import ( "errors" "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" @@ -21,8 +21,8 @@ type mockAnchorProcessor struct { mock.Mock } -func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { - args := m.Called(coreDocument, ctx, recipient) +func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocumentModel *documents.CoreDocumentModel, recipient identity.CentID) (err error) { + args := m.Called(coreDocumentModel, ctx, recipient) return args.Error(0) } @@ -87,8 +87,8 @@ func TestAnchorDocument(t *testing.T) { // prepare fails m = &testingdocuments.MockModel{} - cd := coredocument.New() - m.On("PackCoreDocument").Return(cd, nil).Once() + dm := documents.NewCoreDocModel() + m.On("PackCoreDocument").Return(dm, nil).Once() proc := &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(errors.New("error")).Once() model, err = documents.AnchorDocument(ctxh, m, proc, updater) @@ -100,7 +100,7 @@ func TestAnchorDocument(t *testing.T) { // request signatures failed m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(errors.New("error")).Once() @@ -113,7 +113,7 @@ func TestAnchorDocument(t *testing.T) { // prepare for anchoring fails m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -127,7 +127,7 @@ func TestAnchorDocument(t *testing.T) { // anchor fails m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -142,7 +142,7 @@ func TestAnchorDocument(t *testing.T) { // send failed m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -158,7 +158,7 @@ func TestAnchorDocument(t *testing.T) { // success m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index ef3f92477..bb891c68a 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -12,7 +12,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" @@ -55,7 +54,7 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestService_ReceiveAnchoredDocument(t *testing.T) { +func TestService_ReceiveAnchoredDocumentFailed(t *testing.T) { poSrv := documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) ctxh := testingconfig.CreateAccountContext(t, cfg) err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) @@ -84,27 +83,28 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D } func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, error) { + cdm := documents.NewCoreDocModel() i := &invoice.Invoice{ - InvoiceNumber: "test_invoice", - GrossAmount: 60, - CoreDocument: coredocument.New(), + InvoiceNumber: "test_invoice", + GrossAmount: 60, + CoreDocumentModel: cdm, } dataRoot, err := i.CalculateDataRoot() if err != nil { return nil, err } // get the coreDoc for the invoice - corDoc, err := i.PackCoreDocument() + corDocMod, err := i.PackCoreDocument() if err != nil { return nil, err } - assert.Nil(t, coredocument.FillSalts(corDoc)) - - err = coredocument.CalculateSigningRoot(corDoc, dataRoot) + cds, err := documents.GenerateNewSalts(corDocMod.Document, "", nil) + assert.Nil(t, err) + corDocMod.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cds) + err = corDocMod.CalculateSigningRoot(dataRoot) if err != nil { return nil, err } - centID, err := identity.ToCentID(centIDBytes) assert.Nil(t, err) signKey := identity.IDKey{ @@ -118,21 +118,21 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, }, } - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, corDoc.SigningRoot) - - corDoc.Signatures = append(corDoc.Signatures, sig) + cd := corDocMod.Document + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) - err = coredocument.CalculateDocumentRoot(corDoc) + cd.Signatures = append(cd.Signatures, sig) + err = corDocMod.CalculateDocumentRoot() if err != nil { return nil, err } - err = i.UnpackCoreDocument(corDoc) + err = i.UnpackCoreDocument(corDocMod) if err != nil { return nil, err } if !skipSave { - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) if err != nil { return nil, err } @@ -148,29 +148,30 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv return nil, err } // get the coreDoc for the invoice - corDoc, err := i.PackCoreDocument() + corDocModel, err := i.PackCoreDocument() if err != nil { return nil, err } // hacky update to version + corDoc := corDocModel.Document corDoc.CurrentVersion = corDoc.NextVersion corDoc.NextVersion = utils.RandomSlice(32) if err != nil { return nil, err } - err = coredocument.CalculateSigningRoot(corDoc, dataRoot) + err = corDocModel.CalculateSigningRoot(dataRoot) if err != nil { return nil, err } - err = coredocument.CalculateDocumentRoot(corDoc) + err = corDocModel.CalculateDocumentRoot() if err != nil { return nil, err } - err = i.UnpackCoreDocument(corDoc) + err = i.UnpackCoreDocument(corDocModel) if err != nil { return nil, err } - err = testRepo().Create(tenantID, i.CoreDocument.CurrentVersion, i) + err = testRepo().Create(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) if err != nil { return nil, err } @@ -184,8 +185,8 @@ func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDServi Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, RevokedAt: big.NewInt(0), } - anchorID, _ := anchors.ToAnchorID(i.CoreDocument.DocumentIdentifier) - docRoot, _ := anchors.ToDocumentRoot(i.CoreDocument.DocumentRoot) + anchorID, _ := anchors.ToAnchorID(i.CoreDocumentModel.Document.DocumentIdentifier) + docRoot, _ := anchors.ToDocumentRoot(i.CoreDocumentModel.Document.DocumentRoot) mockAnchor.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() id := &testingcommons.MockID{} centID, _ := identity.ToCentID(centIDBytes) @@ -200,10 +201,10 @@ func TestService_CreateProofs(t *testing.T) { assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) idService = mockSignatureCheck(i, idService, service) - proof, err := service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + proof, err := service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.VersionID) + assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } @@ -211,12 +212,12 @@ func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) - i.CoreDocument.SigningRoot = nil - err = testRepo().Update(tenantID, i.CoreDocument.CurrentVersion, i) + i.CoreDocumentModel.Document.SigningRoot = nil + err = testRepo().Update(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invoice.invoice_number"}) + _, err = service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invoice.invoice_number"}) assert.NotNil(t, err) assert.Contains(t, err.Error(), "signing root missing") } @@ -227,7 +228,7 @@ func TestService_CreateProofsInvalidField(t *testing.T) { assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = service.CreateProofs(ctxh, i.CoreDocument.DocumentIdentifier, []string{"invalid_field"}) + _, err = service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } @@ -245,13 +246,13 @@ func TestService_CreateProofsForVersion(t *testing.T) { i, err := createAnchoredMockDocument(t, false) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - olderVersion := i.CoreDocument.CurrentVersion + olderVersion := i.CoreDocumentModel.Document.CurrentVersion i, err = updatedAnchoredMockDocument(t, i) assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - proof, err := service.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) + proof, err := service.CreateProofsForVersion(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocument.DocumentIdentifier, proof.DocumentID) + assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) @@ -262,7 +263,7 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { i, err := createAnchoredMockDocument(t, true) assert.Nil(t, err) idService = mockSignatureCheck(i, idService, service) - i.CoreDocument.SigningRoot = nil + i.CoreDocumentModel.Document.SigningRoot = nil ctxh := testingconfig.CreateAccountContext(t, cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) @@ -275,7 +276,7 @@ func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { s, _ := getServiceWithMockedLayers() assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = s.CreateProofsForVersion(ctxh, i.CoreDocument.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) + _, err = s.CreateProofsForVersion(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -299,12 +300,17 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { next = nonExistingVersion } + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: version, + NextVersion: next, + } + inv := &invoice.Invoice{ GrossAmount: int64(i + 1), - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: version, - NextVersion: next, + CoreDocumentModel: &documents.CoreDocumentModel{ + Document: cd, + TokenRegistry: nil, }, } @@ -319,7 +325,8 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { model, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.Nil(t, err) - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() + cd := dm.Document assert.Nil(t, err) assert.Equal(t, cd.CurrentVersion, currentVersion, "should return latest version") @@ -331,11 +338,15 @@ func TestService_GetVersion_successful(t *testing.T) { service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } inv := &invoice.Invoice{ GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, + CoreDocumentModel: &documents.CoreDocumentModel{ + cd, + nil, }, } @@ -346,11 +357,11 @@ func TestService_GetVersion_successful(t *testing.T) { mod, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) - cd, err := mod.PackCoreDocument() + dm, err := mod.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, documentIdentifier, cd.DocumentIdentifier, "should be same document Identifier") - assert.Equal(t, currentVersion, cd.CurrentVersion, "should be same version") + assert.Equal(t, documentIdentifier, dm.Document.DocumentIdentifier, "should be same document Identifier") + assert.Equal(t, currentVersion, dm.Document.CurrentVersion, "should be same version") } func TestService_GetCurrentVersion_error(t *testing.T) { @@ -362,11 +373,16 @@ func TestService_GetCurrentVersion_error(t *testing.T) { _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + } + inv := &invoice.Invoice{ GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, + CoreDocumentModel: &documents.CoreDocumentModel{ + cd, + nil, }, } @@ -389,11 +405,15 @@ func TestService_GetVersion_error(t *testing.T) { _, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } inv := &invoice.Invoice{ GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, + CoreDocumentModel: &documents.CoreDocumentModel{ + cd, + nil, }, } err = testRepo().Create(tenantID, currentVersion, inv) @@ -429,11 +449,15 @@ func TestService_Exists(t *testing.T) { _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) + cd := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + } inv := &invoice.Invoice{ GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, + CoreDocumentModel: &documents.CoreDocumentModel{ + cd, + nil, }, } diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 04153ce04..8b22fa2cd 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -106,10 +106,10 @@ type mockModel struct { CoreDocument *coredocumentpb.CoreDocument } -func (m *mockModel) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { +func (m *mockModel) PackCoreDocument() (*documents.CoreDocumentModel, error) { args := m.Called() - cd, _ := args.Get(0).(*coredocumentpb.CoreDocument) - return cd, args.Error(1) + dm, _ := args.Get(0).(*documents.CoreDocumentModel) + return dm, args.Error(1) } func (m *mockModel) JSON() ([]byte, error) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 83664deed..85a72f77d 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -7,9 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" @@ -51,8 +49,8 @@ type Invoice struct { DateCreated *timestamp.Timestamp ExtraData []byte - InvoiceSalts *proofs.Salts - CoreDocument *coredocumentpb.CoreDocument + InvoiceSalts *proofs.Salts + CoreDocumentModel *documents.CoreDocumentModel } // getClientData returns the client data from the invoice model @@ -157,7 +155,7 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload collaborators := append([]string{self}, payload.Collaborators...) - i.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) + i.CoreDocumentModel, err = i.CoreDocumentModel.NewWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } @@ -264,16 +262,16 @@ func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) (*proofs.S // ID returns document identifier. // Note: this is not a unique identifier for each version of the document. func (i *Invoice) ID() ([]byte, error) { - coreDoc, err := i.PackCoreDocument() + coreDocModel, err := i.PackCoreDocument() if err != nil { return []byte{}, err } - return coreDoc.DocumentIdentifier, nil + return coreDocModel.Document.DocumentIdentifier, nil } // PackCoreDocument packs the Invoice into a Core Document // If the, Invoice is new, it creates a valid identifiers -func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { +func (i *Invoice) PackCoreDocument() (*documents.CoreDocumentModel, error) { invoiceData := i.createP2PProtobuf() serializedInvoice, err := proto.Marshal(invoiceData) if err != nil { @@ -290,18 +288,24 @@ func (i *Invoice) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { return nil, errors.NewTypedError(err, errors.New("couldn't get InvoiceSalts")) } - coreDoc := new(coredocumentpb.CoreDocument) - proto.Merge(coreDoc, i.CoreDocument) - coreDoc.EmbeddedData = &invoiceAny - coreDoc.EmbeddedDataSalts = documents.ConvertToProtoSalts(invoiceSalts) - return coreDoc, err + err = i.CoreDocumentModel.PackCoreDocument(&invoiceAny, documents.ConvertToProtoSalts(invoiceSalts)) + if err != nil { + return nil, err + } + + return i.CoreDocumentModel, nil } // UnpackCoreDocument unpacks the core document into Invoice -func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error { - if coreDoc == nil { - return errors.New("core document provided is nil %v", coreDoc) +func (i *Invoice) UnpackCoreDocument(coreDocModel *documents.CoreDocumentModel) error { + if coreDocModel == nil { + return errors.New("coredocmodel is nil %v", coreDocModel) } + if coreDocModel.Document == nil { + return errors.New("core document provided is nil %v", coreDocModel.Document) + } + + coreDoc := coreDocModel.Document if coreDoc.EmbeddedData == nil || coreDoc.EmbeddedData.TypeUrl != documenttypes.InvoiceDataTypeUrl { @@ -325,11 +329,9 @@ func (i *Invoice) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error i.InvoiceSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) } - i.CoreDocument = new(coredocumentpb.CoreDocument) - proto.Merge(i.CoreDocument, coreDoc) - i.CoreDocument.EmbeddedDataSalts = nil - i.CoreDocument.EmbeddedData = nil + err = i.CoreDocumentModel.UnpackCoreDocument() return err + } // JSON marshals Invoice into a json bytes @@ -376,19 +378,19 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { } // CreateProofs generates proofs for given fields -func (i *Invoice) CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { +func (i *Invoice) CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) { // There can be failure scenarios where the core doc for the particular document // is still not saved with roots in db due to failures during getting signatures. - coreDoc, err = i.PackCoreDocument() + _, err = i.PackCoreDocument() if err != nil { - return nil, nil, errors.New("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } tree, err := i.getDocumentDataTree() if err != nil { - return coreDoc, nil, errors.New("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } - proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) - return coreDoc, proofs, err + proofs, err = i.CoreDocumentModel.CreateProofs(tree, fields) + return proofs, err } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 249f48bba..e24bb6da5 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -8,9 +8,6 @@ import ( "reflect" "testing" - "github.com/satori/go.uuid" - "github.com/stretchr/testify/mock" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" @@ -19,7 +16,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" @@ -28,7 +24,7 @@ import ( clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" @@ -36,7 +32,9 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var ctx = map[string]interface{}{} @@ -52,7 +50,7 @@ func TestMain(m *testing.M) { done := make(chan bool) txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, done, nil) - ibootstappers := []bootstrap.TestBootstrapper{ + ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, @@ -66,28 +64,35 @@ func TestMain(m *testing.M) { &Bootstrapper{}, &queue.Starter{}, } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) + bootstrap.RunTestBootstrappers(ibootstrappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) configService = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) + bootstrap.RunTestTeardown(ibootstrappers) os.Exit(result) } func TestInvoice_FromCoreDocuments_invalidParameter(t *testing.T) { invoiceModel := &Invoice{} - emptyCoreDocument := &coredocumentpb.CoreDocument{} - err := invoiceModel.UnpackCoreDocument(emptyCoreDocument) - assert.Error(t, err, "it should not be possible to init a empty core document") + emptyCoreDocModel := &documents.CoreDocumentModel{ + nil, + nil, + } + err := invoiceModel.UnpackCoreDocument(emptyCoreDocModel) + assert.Error(t, err, "it should not be possible to init with an empty core document") err = invoiceModel.UnpackCoreDocument(nil) - assert.Error(t, err, "it should not be possible to init a empty core document") + assert.Error(t, err, "it should not be possible to init with an empty core document") invalidEmbeddedData := &any.Any{TypeUrl: "invalid"} coreDocument := &coredocumentpb.CoreDocument{EmbeddedData: invalidEmbeddedData} - err = invoiceModel.UnpackCoreDocument(coreDocument) + coreDocModel := &documents.CoreDocumentModel{ + coreDocument, + nil, + } + err = invoiceModel.UnpackCoreDocument(coreDocModel) assert.Error(t, err, "it should not be possible to init invalid typeUrl") } @@ -95,21 +100,23 @@ func TestInvoice_FromCoreDocuments_invalidParameter(t *testing.T) { func TestInvoice_InitCoreDocument_successful(t *testing.T) { invoiceModel := &Invoice{} - coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - err := invoiceModel.UnpackCoreDocument(coreDocument) - assert.Nil(t, err, "valid coredocument shouldn't produce an error") + dm := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + invoiceModel.CoreDocumentModel = dm + err := invoiceModel.UnpackCoreDocument(dm) + assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") } func TestInvoice_InitCoreDocument_invalidCentId(t *testing.T) { invoiceModel := &Invoice{} - coreDocument := CreateCDWithEmbeddedInvoice(t, invoicepb.InvoiceData{ + dm := CreateCDWithEmbeddedInvoice(t, invoicepb.InvoiceData{ Recipient: utils.RandomSlice(identity.CentIDLength + 1), Sender: utils.RandomSlice(identity.CentIDLength), Payee: utils.RandomSlice(identity.CentIDLength), GrossAmount: 42, }) - err := invoiceModel.UnpackCoreDocument(coreDocument) + invoiceModel.CoreDocumentModel = dm + err := invoiceModel.UnpackCoreDocument(dm) assert.Nil(t, err) assert.NotNil(t, invoiceModel.Sender) assert.NotNil(t, invoiceModel.Payee) @@ -119,15 +126,17 @@ func TestInvoice_InitCoreDocument_invalidCentId(t *testing.T) { func TestInvoice_CoreDocument_successful(t *testing.T) { invoiceModel := &Invoice{} - //init model with a CoreDoc - coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - invoiceModel.UnpackCoreDocument(coreDocument) + //init model with a CoreDocModel + + coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + invoiceModel.CoreDocumentModel = coreDocumentModel + invoiceModel.UnpackCoreDocument(coreDocumentModel) - returnedCoreDocument, err := invoiceModel.PackCoreDocument() - assert.Nil(t, err, "transformation from invoice to CoreDoc failed") + returnedCoreDocumentModel, err := invoiceModel.PackCoreDocument() + assert.Nil(t, err, "transformation from invoice to CoreDocModel failed") - assert.Equal(t, coreDocument.EmbeddedData, returnedCoreDocument.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocument.EmbeddedDataSalts, returnedCoreDocument.EmbeddedDataSalts, "embeddedDataSalt should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedData, returnedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, returnedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") } func TestInvoice_ModelInterface(t *testing.T) { @@ -145,9 +154,10 @@ func TestInvoice_Type(t *testing.T) { func TestInvoice_JSON(t *testing.T) { invoiceModel := &Invoice{} - //init model with a CoreDoc - coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - invoiceModel.UnpackCoreDocument(coreDocument) + //init model with a CoreDocModel + coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + invoiceModel.CoreDocumentModel = coreDocumentModel + invoiceModel.UnpackCoreDocument(coreDocumentModel) jsonBytes, err := invoiceModel.JSON() assert.Nil(t, err, "marshal to json didn't work correctly") @@ -156,13 +166,13 @@ func TestInvoice_JSON(t *testing.T) { err = invoiceModel.FromJSON(jsonBytes) assert.Nil(t, err, "unmarshal JSON didn't work correctly") - receivedCoreDocument, err := invoiceModel.PackCoreDocument() + receivedCoreDocumentModel, err := invoiceModel.PackCoreDocument() assert.Nil(t, err, "JSON unmarshal damaged invoice variables") - assert.Equal(t, receivedCoreDocument.EmbeddedData, coreDocument.EmbeddedData, "JSON unmarshal damaged invoice variables") + assert.Equal(t, receivedCoreDocumentModel.Document.EmbeddedData, coreDocumentModel.Document.EmbeddedData, "JSON unmarshal damaged invoice variables") } func TestInvoiceModel_UnpackCoreDocument(t *testing.T) { - var model documents.Model = new(Invoice) + var model = new(Invoice) var err error // nil core doc @@ -170,19 +180,20 @@ func TestInvoiceModel_UnpackCoreDocument(t *testing.T) { assert.Error(t, err, "unpack must fail") // embed data missing - err = model.UnpackCoreDocument(new(coredocumentpb.CoreDocument)) + err = model.UnpackCoreDocument(new(documents.CoreDocumentModel)) assert.Error(t, err, "unpack must fail due to missing embed data") // successful - coreDocument := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - err = model.UnpackCoreDocument(coreDocument) + coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) + model.CoreDocumentModel = coreDocumentModel + err = model.UnpackCoreDocument(coreDocumentModel) assert.Nil(t, err, "valid core document with embedded invoice shouldn't produce an error") - receivedCoreDocument, err := model.PackCoreDocument() + receivedCoreDocumentModel, err := model.PackCoreDocument() assert.Nil(t, err, "model should be able to return the core document with embedded invoice") - assert.Equal(t, coreDocument.EmbeddedData, receivedCoreDocument.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocument.EmbeddedDataSalts, receivedCoreDocument.EmbeddedDataSalts, "embeddedDataSalt should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedData, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, receivedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") } func TestInvoiceModel_getClientData(t *testing.T) { @@ -253,7 +264,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Equal(t, inv.Payee[:], []byte{1, 2, 3, 3, 4, 5}) assert.Equal(t, inv.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, inv.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - assert.Equal(t, inv.CoreDocument.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + assert.Equal(t, inv.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } func TestInvoiceModel_calculateDataRoot(t *testing.T) { @@ -270,13 +281,13 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { } func TestInvoiceModel_createProofs(t *testing.T) { - i, corDoc, err := createMockInvoice(t) + i, err := createMockInvoice(t) assert.Nil(t, err) - corDoc, proof, err := i.CreateProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) + proof, err := i.CreateProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) - assert.NotNil(t, corDoc) - tree, _ := coredocument.GetDocumentRootTree(corDoc) + tree, err := i.CoreDocumentModel.GetDocumentRootTree() + assert.NoError(t, err) // Validate invoice_number valid, err := tree.ValidateProof(proof[0]) @@ -289,7 +300,7 @@ func TestInvoiceModel_createProofs(t *testing.T) { assert.True(t, valid) // Validate []byte value - assert.Equal(t, i.CoreDocument.Collaborators[0], proof[1].Value) + assert.Equal(t, i.CoreDocumentModel.Document.Collaborators[0], proof[1].Value) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -298,17 +309,17 @@ func TestInvoiceModel_createProofs(t *testing.T) { } func TestInvoiceModel_createProofsFieldDoesNotExist(t *testing.T) { - i, _, err := createMockInvoice(t) + i, err := createMockInvoice(t) assert.Nil(t, err) - _, _, err = i.CreateProofs([]string{"nonexisting"}) + _, err = i.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } func TestInvoiceModel_GetDocumentID(t *testing.T) { - i, corDoc, err := createMockInvoice(t) + i, err := createMockInvoice(t) assert.Nil(t, err) ID, err := i.ID() - assert.Equal(t, corDoc.DocumentIdentifier, ID) + assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, ID) } func TestInvoiceModel_getDocumentDataTree(t *testing.T) { @@ -320,27 +331,28 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { assert.Equal(t, "invoice.invoice_number", leaf.Property.ReadableName()) } -func createMockInvoice(t *testing.T) (*Invoice, *coredocumentpb.CoreDocument, error) { - i := &Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2, Currency: "USD", CoreDocument: coredocument.New()} - i.CoreDocument.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} +func createMockInvoice(t *testing.T) (*Invoice, error) { + i := &Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2, Currency: "USD", CoreDocumentModel: documents.NewCoreDocModel()} + i.CoreDocumentModel.Document.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} dataRoot, err := i.CalculateDataRoot() if err != nil { - return nil, nil, err + return nil, err } // get the coreDoc for the invoice - corDoc, err := i.PackCoreDocument() + + cdm, err := i.PackCoreDocument() if err != nil { - return nil, nil, err + return nil, err } - assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc, dataRoot) + + err = cdm.CalculateSigningRoot(dataRoot) if err != nil { - return nil, nil, err + return nil, err } - err = coredocument.CalculateDocumentRoot(corDoc) + err = cdm.CalculateDocumentRoot() if err != nil { - return nil, nil, err + return nil, err } - i.UnpackCoreDocument(corDoc) - return i, corDoc, nil + i.UnpackCoreDocument(cdm) + return i, nil } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index c41e1ce99..36c64e8c8 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -3,9 +3,7 @@ package invoice import ( "context" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -57,10 +55,12 @@ func DefaultService( } } -// DeriveFromCoreDocument unpacks the core document into a model -func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { - var model documents.Model = new(Invoice) - err := model.UnpackCoreDocument(cd) +// DeriveFromCoreDocumentModel takes a core document model and returns an invoice +func (s service) DeriveFromCoreDocumentModel(dm *documents.CoreDocumentModel) (documents.Model, error) { + var model documents.Model = &Invoice{ + CoreDocumentModel: dm, + } + err := model.UnpackCoreDocument(dm) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } @@ -107,7 +107,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], inv.CoreDocument.CurrentVersion, inv) + err = s.repo.Create(self.ID[:], inv.CoreDocumentModel.Document.CurrentVersion, inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -127,13 +127,13 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, nil, err } - cd, err := inv.PackCoreDocument() + dm, err := inv.PackCoreDocument() if err != nil { return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { return nil, uuid.Nil, nil, err } @@ -147,12 +147,11 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - cd, err := inv.PackCoreDocument() + dm, err := inv.PackCoreDocument() if err != nil { return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - - old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) if err != nil { return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } @@ -163,7 +162,7 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { return nil, uuid.Nil, nil, err } @@ -172,11 +171,11 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod // DeriveInvoiceResponse returns create response from invoice model func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.InvoiceResponse, error) { - cd, err := doc.PackCoreDocument() + dm, err := doc.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - + cd := dm.Document collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { cid, err := identity.ToCentID(c) @@ -239,7 +238,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv } // update core document - oldCD, err := old.PackCoreDocument() + oldDM, err := old.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } @@ -250,10 +249,9 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv } collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) - inv.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) + inv.CoreDocumentModel, err = oldDM.PrepareNewVersion(collaborators) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) } - return inv, nil } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index b6951442f..7c2f5ca12 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" @@ -16,7 +15,7 @@ import ( clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -72,14 +71,17 @@ func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { func createMockDocument() (*Invoice, error) { documentIdentifier := utils.RandomSlice(32) nextIdentifier := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + NextVersion: nextIdentifier, + } + dm := documents.NewCoreDocModel() + dm.Document = coreDoc inv1 := &Invoice{ - InvoiceNumber: "test_invoice", - GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - NextVersion: nextIdentifier, - }, + InvoiceNumber: "test_invoice", + GrossAmount: 60, + CoreDocumentModel: dm, } err := testRepo().Create(accountID, documentIdentifier, inv1) return inv1, err @@ -88,13 +90,13 @@ func createMockDocument() (*Invoice, error) { func TestService_DeriveFromCoreDocument(t *testing.T) { // nil doc invSrv := service{repo: testRepo()} - _, err := invSrv.DeriveFromCoreDocument(nil) + _, err := invSrv.DeriveFromCoreDocumentModel(nil) assert.Error(t, err, "must fail to derive") // successful data := testingdocuments.CreateInvoiceData() - coreDoc := CreateCDWithEmbeddedInvoice(t, data) - model, err := invSrv.DeriveFromCoreDocument(coreDoc) + coreDocModel := CreateCDWithEmbeddedInvoice(t, data) + model, err := invSrv.DeriveFromCoreDocumentModel(coreDocModel) assert.Nil(t, err, "must return model") assert.NotNil(t, model, "model must be non-nil") inv, ok := model.(*Invoice) @@ -122,9 +124,9 @@ func TestService_DeriveFromPayload(t *testing.T) { model, err = invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) assert.Nil(t, err, "valid invoiceData shouldn't produce an error") - receivedCoreDocument, err := model.PackCoreDocument() + receivedCoreDocumentModel, err := model.PackCoreDocument() assert.Nil(t, err, "model should be able to return the core document with embedded invoice") - assert.NotNil(t, receivedCoreDocument.EmbeddedData, "embeddedData should be field") + assert.NotNil(t, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be field") } func TestService_GetLastVersion(t *testing.T) { @@ -134,30 +136,35 @@ func TestService_GetLastVersion(t *testing.T) { assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - mod1, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) + mod1, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) assert.Nil(t, err) invLoad1, _ := mod1.(*Invoice) - assert.Equal(t, invLoad1.CoreDocument.CurrentVersion, doc.CoreDocument.DocumentIdentifier) + assert.Equal(t, invLoad1.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.DocumentIdentifier) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: doc.CoreDocumentModel.Document.DocumentIdentifier, + CurrentVersion: doc.CoreDocumentModel.Document.NextVersion, + NextVersion: thirdIdentifier, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } inv2 := &Invoice{ - GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: doc.CoreDocument.DocumentIdentifier, - CurrentVersion: doc.CoreDocument.NextVersion, - NextVersion: thirdIdentifier, - }, + GrossAmount: 60, + CoreDocumentModel: coreDocModel, } - - err = testRepo().Create(accountID, doc.CoreDocument.NextVersion, inv2) + cd := doc.CoreDocumentModel.Document + err = testRepo().Create(accountID, cd.NextVersion, inv2) assert.Nil(t, err) - mod2, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) + mod2, err := invSrv.GetCurrentVersion(ctxh, cd.DocumentIdentifier) assert.Nil(t, err) invLoad2, _ := mod2.(*Invoice) - assert.Equal(t, invLoad2.CoreDocument.CurrentVersion, doc.CoreDocument.NextVersion) - assert.Equal(t, invLoad2.CoreDocument.NextVersion, thirdIdentifier) + assert.Equal(t, invLoad2.CoreDocumentModel.Document.CurrentVersion, cd.NextVersion) + assert.Equal(t, invLoad2.CoreDocumentModel.Document.NextVersion, thirdIdentifier) } func TestService_GetVersion_wrongTyp(t *testing.T) { @@ -165,13 +172,18 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { currentVersion := utils.RandomSlice(32) documentIdentifier := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } //should be an invoice po := &purchaseorder.PurchaseOrder{ - NetAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - }, + NetAmount: 60, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) @@ -186,12 +198,17 @@ func TestService_GetVersion(t *testing.T) { _, invSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } inv := &Invoice{ - GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - }, + GrossAmount: 60, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, currentVersion, inv) assert.Nil(t, err) @@ -200,8 +217,8 @@ func TestService_GetVersion(t *testing.T) { mod, err := invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadInv, _ := mod.(*Invoice) - assert.Equal(t, loadInv.CoreDocument.CurrentVersion, currentVersion) - assert.Equal(t, loadInv.CoreDocument.DocumentIdentifier, documentIdentifier) + assert.Equal(t, loadInv.CoreDocumentModel.Document.CurrentVersion, currentVersion) + assert.Equal(t, loadInv.CoreDocumentModel.Document.DocumentIdentifier, documentIdentifier) mod, err = invSrv.GetVersion(ctxh, documentIdentifier, []byte{}) assert.Error(t, err) @@ -210,12 +227,17 @@ func TestService_GetVersion(t *testing.T) { func TestService_Exists(t *testing.T) { _, invSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } inv := &Invoice{ - GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - }, + GrossAmount: 60, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, documentIdentifier, inv) assert.Nil(t, err) @@ -245,10 +267,10 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) m, _, _, err = invSrv.Create(ctxh, po) assert.Nil(t, err) - newCD, err := m.PackCoreDocument() + newDM, err := m.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newDM.Document.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newDM.Document.CurrentVersion)) } func TestService_DeriveInvoiceData(t *testing.T) { @@ -275,9 +297,15 @@ func TestService_DeriveInvoiceResponse(t *testing.T) { assert.Nil(t, err, "must be non nil") inv, ok := inv1.(*Invoice) assert.True(t, ok) - inv.CoreDocument = &coredocumentpb.CoreDocument{ + + coreDoc := &coredocumentpb.CoreDocument{ DocumentIdentifier: []byte{}, } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } + inv.CoreDocumentModel = coreDocModel resp, err := invSrv.DeriveInvoiceResponse(inv) assert.Nil(t, err, "Derive must succeed") assert.NotNil(t, resp, "data must be non nil") @@ -320,9 +348,9 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old := new(Invoice) err = old.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), idC.ID.String()) assert.Nil(t, err) - old.CoreDocument.DocumentIdentifier = id - old.CoreDocument.CurrentVersion = id - old.CoreDocument.DocumentRoot = utils.RandomSlice(32) + old.CoreDocumentModel.Document.DocumentIdentifier = id + old.CoreDocumentModel.Document.CurrentVersion = id + old.CoreDocumentModel.Document.DocumentRoot = utils.RandomSlice(32) err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ @@ -352,17 +380,17 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) - cd, err := doc.PackCoreDocument() + dm, err := doc.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, wantCollab, cd.Collaborators[2]) - assert.Len(t, cd.Collaborators, 3) - oldCD, err := old.PackCoreDocument() + assert.Equal(t, wantCollab, dm.Document.Collaborators[2]) + assert.Len(t, dm.Document.Collaborators, 3) + oldDM, err := old.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, oldCD.DocumentIdentifier, cd.DocumentIdentifier) - assert.Equal(t, payload.Identifier, hexutil.Encode(cd.DocumentIdentifier)) - assert.Equal(t, oldCD.CurrentVersion, cd.PreviousVersion) - assert.Equal(t, oldCD.NextVersion, cd.CurrentVersion) - assert.NotNil(t, cd.NextVersion) + assert.Equal(t, oldDM.Document.DocumentIdentifier, dm.Document.DocumentIdentifier) + assert.Equal(t, payload.Identifier, hexutil.Encode(dm.Document.DocumentIdentifier)) + assert.Equal(t, oldDM.Document.CurrentVersion, dm.Document.PreviousVersion) + assert.Equal(t, oldDM.Document.NextVersion, dm.Document.CurrentVersion) + assert.NotNil(t, dm.Document.NextVersion) assert.Equal(t, payload.Data, doc.(*Invoice).getClientData()) } @@ -381,8 +409,8 @@ func TestService_Update(t *testing.T) { // missing last version model = &mockModel{} - cd := coredocument.New() - model.On("PackCoreDocument").Return(cd, nil).Once() + dm := documents.NewCoreDocModel() + model.On("PackCoreDocument").Return(dm, nil).Once() _, _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -392,15 +420,15 @@ func TestService_Update(t *testing.T) { payload.Collaborators = []string{"0x010203040506"} inv, err := invSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) - cd, err = inv.PackCoreDocument() + dm, err = inv.PackCoreDocument() assert.Nil(t, err) - cd.DocumentRoot = utils.RandomSlice(32) - inv.(*Invoice).CoreDocument = cd - testRepo().Create(accountID, cd.CurrentVersion, inv) + dm.Document.DocumentRoot = utils.RandomSlice(32) + inv.(*Invoice).CoreDocumentModel = dm + testRepo().Create(accountID, dm.Document.CurrentVersion, inv) // calculate data root fails model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() _, _, _, err = invSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -413,7 +441,7 @@ func TestService_Update(t *testing.T) { data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) collab := hexutil.Encode(utils.RandomSlice(6)) newInv, err := invSrv.DeriveFromUpdatePayload(ctxh, &clientinvoicepb.InvoiceUpdatePayload{ - Identifier: hexutil.Encode(cd.DocumentIdentifier), + Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), Collaborators: []string{collab}, Data: data, }) @@ -424,11 +452,11 @@ func TestService_Update(t *testing.T) { inv, _, _, err = invSrv.Update(ctxh, newInv) assert.Nil(t, err) assert.NotNil(t, inv) - newCD, err := inv.PackCoreDocument() + newDM, err := inv.PackCoreDocument() assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(accountID, newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(accountID, newDM.Document.DocumentIdentifier)) + assert.True(t, testRepo().Exists(accountID, newDM.Document.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, newDM.Document.PreviousVersion)) newData, err = invSrv.DeriveInvoiceData(inv) assert.Nil(t, err) assert.Equal(t, data, newData) @@ -449,7 +477,7 @@ func TestService_calculateDataRoot(t *testing.T) { // failed validator inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) + assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) @@ -461,8 +489,8 @@ func TestService_calculateDataRoot(t *testing.T) { // create failed inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) - err = invSrv.repo.Create(accountID, inv.(*Invoice).CoreDocument.CurrentVersion, inv) + assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) + err = invSrv.repo.Create(accountID, inv.(*Invoice).CoreDocumentModel.Document.CurrentVersion, inv) assert.Nil(t, err) inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, inv) @@ -472,7 +500,7 @@ func TestService_calculateDataRoot(t *testing.T) { // success inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocument.DataRoot) + assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, inv) diff --git a/documents/invoice/utils_test.go b/documents/invoice/utils_test.go index 70cb5c9e9..fe008c48b 100644 --- a/documents/invoice/utils_test.go +++ b/documents/invoice/utils_test.go @@ -3,20 +3,22 @@ package invoice import ( "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/stretchr/testify/assert" ) -func CreateCDWithEmbeddedInvoice(t *testing.T, invoiceData invoicepb.InvoiceData) *coredocumentpb.CoreDocument { +func CreateCDWithEmbeddedInvoice(t *testing.T, invoiceData invoicepb.InvoiceData) *documents.CoreDocumentModel { identifier := []byte("1") invoiceModel := &Invoice{} + invoiceModel.CoreDocumentModel = documents.NewCoreDocModel() invoiceModel.loadFromP2PProtobuf(&invoiceData) _, err := invoiceModel.getInvoiceSalts(&invoiceData) assert.NoError(t, err) - coreDocument, err := invoiceModel.PackCoreDocument() + cdm, err := invoiceModel.PackCoreDocument() assert.NoError(t, err) - coreDocument.DocumentIdentifier = identifier + cdm.Document.DocumentIdentifier = identifier - return coreDocument + return cdm } diff --git a/documents/model.go b/documents/model.go index b767e8bcb..114968d51 100644 --- a/documents/model.go +++ b/documents/model.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "github.com/golang/protobuf/proto" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" @@ -15,7 +15,10 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" ) const ( @@ -44,34 +47,43 @@ var compactProperties = map[string][]byte{ // It should only handle protocol-level Document actions type Model interface { storage.Model - // Get the ID of the document represented by this model ID() ([]byte, error) // PackCoreDocument packs the implementing document into a core document // should create the identifiers for the core document if not present - PackCoreDocument() (*coredocumentpb.CoreDocument, error) + PackCoreDocument() (*CoreDocumentModel, error) // UnpackCoreDocument must return the document.Model // assumes that core document has valid identifiers set - UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error + UnpackCoreDocument(model *CoreDocumentModel) error // CalculateDataRoot calculates the dataroot of precise-proofs tree of the model CalculateDataRoot() ([]byte, error) // CreateProofs creates precise-proofs for given fields - CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) + CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) +} + +// TokenRegistry defines NFT retrieval functions. +type TokenRegistry interface { + // OwnerOf to retrieve owner of the tokenID + OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) } // CoreDocumentModel contains methods which handle all interactions mutating or reading from a core document // Access to a core document should always go through this model type CoreDocumentModel struct { Document *coredocumentpb.CoreDocument + TokenRegistry } const ( // ErrZeroCollaborators error when no collaborators are passed ErrZeroCollaborators = errors.Error("require at least one collaborator") + + // nftByteCount is the length of combined bytes of registry and tokenID + nftByteCount = 52 ) // NewDefaultTree returns a DocumentTree with default opts @@ -97,6 +109,7 @@ func NewLeafProperty(literal string, compact []byte) proofs.Property { // NewCoreDocModel returns a new CoreDocumentModel // Note: collaborators and salts are to be filled by the caller +// TODO: double check if registry should be initialised as nil func NewCoreDocModel() *CoreDocumentModel { id := utils.RandomSlice(32) cd := &coredocumentpb.CoreDocument{ @@ -106,6 +119,7 @@ func NewCoreDocModel() *CoreDocumentModel { } return &CoreDocumentModel{ cd, + nil, } } @@ -122,24 +136,21 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu return nil, errors.New("failed to decode collaborator: %v", err) } - cs := ncd.Collaborators + cs := ocd.Collaborators for _, c := range ucs { c := c cs = append(cs, c[:]) } ncd.Collaborators = cs - - // copy read rules and roles ncd.Roles = m.Document.Roles ncd.ReadRules = m.Document.ReadRules err = ndm.addCollaboratorsToReadSignRules(ucs) if err != nil { return nil, err } - _, err = ndm.getCoreDocumentSalts() - if err != nil { + if err := ndm.setCoreDocumentSalts(); err != nil { return nil, err } @@ -163,10 +174,35 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu return nil, errors.New("DocumentRoot is nil") } ncd.PreviousRoot = ocd.DocumentRoot + // copy over token registry + ndm.TokenRegistry = m.TokenRegistry return ndm, nil } +// NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts +func (m *CoreDocumentModel) NewWithCollaborators(collaborators []string) (*CoreDocumentModel, error) { + dm := NewCoreDocModel() + ids, err := identity.CentIDsFromStrings(collaborators) + if err != nil { + return nil, errors.New("failed to decode collaborator: %v", err) + } + + for i := range ids { + dm.Document.Collaborators = append(dm.Document.Collaborators, ids[i][:]) + } + err = dm.initReadRules(ids) + if err != nil { + return nil, errors.New("failed to init read rules: %v", err) + } + + if err := dm.setCoreDocumentSalts(); err != nil { + return nil, err + } + + return dm, nil +} + // CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields []string) (proofs []*proofspb.Proof, err error) { signingRootProofHashes, err := m.getSigningRootProofHashes() @@ -174,7 +210,7 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ return nil, errors.New("createProofs error %v", err) } - cdtree, err := m.GetCoreDocTree() + cdtree, err := m.GetDocumentTree() if err != nil { return nil, errors.New("createProofs error %v", err) } @@ -206,10 +242,9 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ return proofs, nil } -// GetCoreDocTree returns the merkle tree for the coredoc root -func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err error) { +// GetDocumentTree returns the merkle tree for the coredoc root +func (m *CoreDocumentModel) GetDocumentTree() (tree *proofs.DocumentTree, err error) { document := m.Document - h := sha256.New() tree = NewDefaultTree(ConvertToProofSalts(m.Document.CoredocumentSalts)) err = tree.AddLeavesFromDocument(document) if err != nil { @@ -226,7 +261,7 @@ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err err Value: []byte(document.EmbeddedData.TypeUrl), } - err = documentTypeNode.HashNode(h, true) + err = documentTypeNode.HashNode(sha256.New(), true) if err != nil { return nil, err } @@ -240,13 +275,14 @@ func (m *CoreDocumentModel) GetCoreDocTree() (tree *proofs.DocumentTree, err err if err != nil { return nil, err } + return tree, nil } // GetDocumentSigningTree returns the merkle tree for the signing root func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proofs.DocumentTree, err error) { // coredoc tree - coreDocTree, err := m.GetCoreDocTree() + coreDocTree, err := m.GetDocumentTree() if err != nil { return nil, err } @@ -281,7 +317,6 @@ func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proof // GetDocumentRootTree returns the merkle tree for the document root func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, err error) { document := m.Document - h := sha256.New() tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) // The first leave added is the signing_root @@ -289,6 +324,7 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er if err != nil { return nil, err } + // For every signature we create a LeafNode sigProperty := NewLeafProperty(SignaturesField, compactProperties[SignaturesField]) sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) @@ -297,6 +333,8 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er Salt: make([]byte, 32), Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), } + + h := sha256.New() err = sigLengthNode.HashNode(h, true) if err != nil { return nil, err @@ -319,10 +357,12 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er if err != nil { return nil, err } + err = tree.Generate() if err != nil { return nil, err } + return tree, nil } @@ -374,6 +414,7 @@ func (m *CoreDocumentModel) getSigningRootProofHashes() (hashes [][]byte, err er if err != nil { return } + return rootProof.SortedHashes, err } @@ -437,16 +478,32 @@ func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salt return &proofSalts } -// getCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet -func (m *CoreDocumentModel) getCoreDocumentSalts() ([]*coredocumentpb.DocumentSalt, error) { +// setCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet +func (m *CoreDocumentModel) setCoreDocumentSalts() error { if m.Document.CoredocumentSalts == nil { pSalts, err := GenerateNewSalts(m.Document, "", nil) if err != nil { - return nil, err + return err } + m.Document.CoredocumentSalts = ConvertToProtoSalts(pSalts) } - return m.Document.CoredocumentSalts, nil + + return nil +} + +// PackCoreDocument sets the embed data and embed salts and generates core doc salts if not exists +func (m *CoreDocumentModel) PackCoreDocument(embedData *any.Any, embedSalts []*coredocumentpb.DocumentSalt) error { + m.Document.EmbeddedData = embedData + m.Document.EmbeddedDataSalts = embedSalts + return m.setCoreDocumentSalts() +} + +// UnpackCoreDocument sets the embed data and embed salts and generates core doc salts if not exists +func (m *CoreDocumentModel) UnpackCoreDocument() error { + m.Document.EmbeddedData = nil + m.Document.EmbeddedDataSalts = nil + return m.setCoreDocumentSalts() } // initReadRules initiates the read rules for a given CoreDocumentModel. @@ -573,3 +630,127 @@ func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []i return ids, nil } + +// GetExternalCollaborators returns collaborators of a document without the own centID. +func (m *CoreDocumentModel) GetExternalCollaborators(selfCentID identity.CentID) ([][]byte, error) { + var collabs [][]byte + + for _, collab := range m.Document.Collaborators { + collabID, err := identity.ToCentID(collab) + if err != nil { + return nil, errors.New("failed to convert to CentID: %v", err) + } + if !selfCentID.Equal(collabID) { + collabs = append(collabs, collab) + } + } + + return collabs, nil +} + +// NFTOwnerCanRead checks if the nft owner/account can read the document +func (m *CoreDocumentModel) NFTOwnerCanRead(registry common.Address, tokenID []byte, account identity.CentID) error { + // check if the account can read the doc + if m.AccountCanRead(account) { + return nil + } + + // check if the nft is present in read rules + found := m.findRole(coredocumentpb.Action_ACTION_READ, func(role *coredocumentpb.Role) bool { + return isNFTInRole(role, registry, tokenID) + }) + + if !found { + return errors.New("nft missing") + } + + // get the owner of the NFT + owner, err := m.TokenRegistry.OwnerOf(registry, tokenID) + if err != nil { + return errors.New("failed to get NFT owner: %v", err) + } + + // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address + if !bytes.Equal(owner.Bytes(), account[:]) { + return errors.New("account (%v) not owner of the NFT", account.String()) + } + + return nil +} + +// ConstructNFT appends registry and tokenID to byte slice +func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { + var nft []byte + // first 20 bytes of registry + nft = append(nft, registry.Bytes()...) + + // next 32 bytes of the tokenID + nft = append(nft, tokenID...) + + if len(nft) != nftByteCount { + return nil, errors.New("byte length mismatch") + } + + return nft, nil +} + +// AddNFTToReadRules adds NFT token to the read rules of core document. +func (m *CoreDocumentModel) AddNFTToReadRules(registry common.Address, tokenID []byte) error { + cd := m.Document + nft, err := ConstructNFT(registry, tokenID) + if err != nil { + return errors.New("failed to construct NFT: %v", err) + } + + role := new(coredocumentpb.Role) + rk, err := utils.ConvertIntToByte32(len(cd.Roles)) + if err != nil { + return err + } + role.RoleKey = rk[:] + role.Nfts = append(role.Nfts, nft) + m.addNewRule(role, coredocumentpb.Action_ACTION_READ) + if err := m.setCoreDocumentSalts(); err != nil { + return errors.New("failed to generate CoreDocumentSalts") + } + return nil +} + +//ValidateDocumentAccess validates the GetDocument request against the AccessType indicated in the request +func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) error { + // checks which access type is relevant for the request + switch docReq.GetAccessType() { + case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: + if m.AccountCanRead(requesterCentID) { + return errors.New("requester does not have access") + } + case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: + registry := common.BytesToAddress(docReq.NftRegistryAddress) + if m.NFTOwnerCanRead(registry, docReq.NftTokenId, requesterCentID) != nil { + return errors.New("requester does not have access") + } + //// case AccessTokenValidation + // case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: + // + // case p2ppb.AccessType_ACCESS_TYPE_INVALID: + default: + return errors.New("invalid access type ") + } + return nil +} + +// isNFTInRole checks if the given nft(registry + token) is part of the core document role. +func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) bool { + enft, err := ConstructNFT(registry, tokenID) + if err != nil { + return false + } + + for _, n := range role.Nfts { + if bytes.Equal(n, enft) { + return true + } + } + + return false +} diff --git a/documents/model_test.go b/documents/model_test.go index c693dccfc..533a42656 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -7,6 +7,9 @@ import ( "os" "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" @@ -153,6 +156,9 @@ func TestCoreDocumentModel_PrepareNewVersion(t *testing.T) { // DocumentRoot was updated assert.Equal(t, ncd.PreviousRoot, ocd.DocumentRoot) + + // TokenRegistry was copied over + assert.Equal(t, ndm.TokenRegistry, dm.TokenRegistry) } func TestReadACLs_initReadRules(t *testing.T) { @@ -203,7 +209,7 @@ func TestGetSigningProofHashes(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - _, err := dm.getCoreDocumentSalts() + err := dm.setCoreDocumentSalts() assert.NoError(t, err) err = dm.CalculateSigningRoot(cd.DataRoot) @@ -230,7 +236,7 @@ func TestGetDataProofHashes(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.DataRoot = utils.RandomSlice(32) - _, err := dm.getCoreDocumentSalts() + err := dm.setCoreDocumentSalts() assert.NoError(t, err) err = dm.CalculateSigningRoot(cd.DataRoot) @@ -256,7 +262,7 @@ func TestGetDocumentSigningTree(t *testing.T) { dm := NewCoreDocModel() cd := dm.Document cd.EmbeddedData = docAny - _, err := dm.getCoreDocumentSalts() + err := dm.setCoreDocumentSalts() assert.NoError(t, err) tree, err := dm.GetDocumentSigningTree(cd.DataRoot) assert.Nil(t, err) @@ -272,7 +278,7 @@ func TestGetDocumentSigningTree(t *testing.T) { func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { dm := NewCoreDocModel() cd := dm.Document - _, err := dm.getCoreDocumentSalts() + err := dm.setCoreDocumentSalts() assert.NoError(t, err) tree, err := dm.GetDocumentSigningTree(cd.DataRoot) assert.NotNil(t, err) @@ -312,13 +318,13 @@ func TestCreateProofs(t *testing.T) { cd := dm.Document cd.EmbeddedData = docAny cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} - _, err = dm.getCoreDocumentSalts() + err = dm.setCoreDocumentSalts() assert.NoError(t, err) err = dm.CalculateSigningRoot(testTree.RootHash()) assert.NoError(t, err) err = dm.CalculateDocumentRoot() assert.NoError(t, err) - cdTree, err := dm.GetCoreDocTree() + cdTree, err := dm.GetDocumentTree() assert.NoError(t, err) tests := []struct { fieldName string @@ -363,24 +369,95 @@ func TestCreateProofs(t *testing.T) { assert.True(t, valid) }) } +} + +type mockRegistry struct { + mock.Mock +} + +func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { + args := m.Called(registry, tokenID) + addr, _ := args.Get(0).(common.Address) + return addr, args.Error(1) +} + +func Test_addNFTToReadRules(t *testing.T) { + dm := NewCoreDocModel() + // wrong registry or token format + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(34) + err := dm.AddNFTToReadRules(registry, tokenID) + assert.Error(t, err) + + dm.Document.DocumentRoot = utils.RandomSlice(32) + dm, err = dm.PrepareNewVersion([]string{"0x010203040506"}) + cd := dm.Document + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 1) + assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) + assert.Len(t, cd.Roles, 1) + + tokenID = utils.RandomSlice(32) + err = dm.AddNFTToReadRules(registry, tokenID) + assert.NoError(t, err) + assert.Len(t, cd.ReadRules, 2) + assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) + assert.Len(t, cd.Roles, 2) +} + +func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { + dm := NewCoreDocModel() + dm.Document.DocumentRoot = utils.RandomSlice(32) + account, err := identity.CentIDFromString("0x010203040506") + assert.NoError(t, err) + + dm, err = dm.PrepareNewVersion([]string{account.String()}) + assert.NoError(t, err) + + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + // account can read + err = dm.NFTOwnerCanRead(registry, nil, account) + assert.NoError(t, err) + + // account not in read rules and nft missing + account, err = identity.CentIDFromString("0x010203040505") + assert.NoError(t, err) + tokenID := utils.RandomSlice(32) + err = dm.NFTOwnerCanRead(registry, tokenID, account) + assert.Error(t, err) + + tr := mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() + dm.TokenRegistry = tr + dm.AddNFTToReadRules(registry, tokenID) + err = dm.NFTOwnerCanRead(registry, tokenID, account) + assert.Error(t, err) + assert.Contains(t, err, "failed to get owner of") + tr.AssertExpectations(t) + + // not the same owner + owner := common.BytesToAddress(utils.RandomSlice(20)) + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + dm.TokenRegistry = tr + err = dm.NFTOwnerCanRead(registry, tokenID, account) + assert.Error(t, err) + tr.AssertExpectations(t) } func TestGetCoreDocumentSalts(t *testing.T) { dm := NewCoreDocModel() // From empty - salts, err := dm.getCoreDocumentSalts() + err := dm.setCoreDocumentSalts() assert.NoError(t, err) - assert.NotNil(t, salts) - assert.Equal(t, len(dm.Document.CoredocumentSalts), len(salts)) - assert.Equal(t, dm.Document.CoredocumentSalts[0], salts[0]) + assert.NotNil(t, dm.Document.CoredocumentSalts) + salts := dm.Document.CoredocumentSalts // Return existing - cSalts, err := dm.getCoreDocumentSalts() + err = dm.setCoreDocumentSalts() assert.NoError(t, err) - assert.NotNil(t, cSalts) - assert.Equal(t, len(cSalts), len(salts)) - assert.Equal(t, cSalts[0], salts[0]) + assert.NotNil(t, dm.Document.CoredocumentSalts) + assert.Equal(t, salts, dm.Document.CoredocumentSalts) } func TestGenerateNewSalts(t *testing.T) { diff --git a/documents/processor.go b/documents/processor.go index 118a0f11e..1463eeb3c 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -4,11 +4,9 @@ import ( "context" "time" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -26,7 +24,7 @@ type Config interface { type Client interface { // GetSignaturesForDocument gets the signatures for document - GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error + GetSignaturesForDocument(ctx context.Context, model *CoreDocumentModel) error // after all signatures are collected the sender sends the document including the signatures SendAnchoredDocument(ctx context.Context, receiverID identity.CentID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) @@ -51,10 +49,14 @@ func DefaultProcessor(idService identity.Service, p2pClient Client, repository a } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentpb.CoreDocument, recipient identity.CentID) (err error) { - if coreDocument == nil { +func (dp defaultProcessor) Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.CentID) (err error) { + if coreDocModel == nil { + return errors.New("passed coreDocModel is nil") + } + if coreDocModel.Document == nil { return errors.New("passed coreDoc is nil") } + coreDocument := coreDocModel.Document log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) @@ -70,18 +72,19 @@ func (dp defaultProcessor) Send(ctx context.Context, coreDocument *coredocumentp // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model Model) error { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() + if err != nil { return errors.New("failed to pack core document: %v", err) } - + cd := dm.Document dataRoot, err := model.CalculateDataRoot() if err != nil { return err } // calculate the signing root - err = coredocument.CalculateSigningRoot(cd, dataRoot) + err = dm.CalculateSigningRoot(dataRoot) if err != nil { return errors.New("failed to calculate signing root: %v", err) } @@ -94,7 +97,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, mode sig := identity.Sign(self, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) - err = model.UnpackCoreDocument(cd) + err = model.UnpackCoreDocument(dm) if err != nil { return errors.New("failed to unpack the core document: %v", err) } @@ -105,7 +108,7 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, mode // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) error { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } @@ -126,12 +129,12 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e return errors.New("failed to validate model for signature request: %v", err) } - err = dp.p2pClient.GetSignaturesForDocument(ctx, cd) + err = dp.p2pClient.GetSignaturesForDocument(ctx, dm) if err != nil { return errors.New("failed to collect signatures from the collaborators: %v", err) } - err = model.UnpackCoreDocument(cd) + err = model.UnpackCoreDocument(dm) if err != nil { return errors.New("failed to unpack core document: %v", err) } @@ -141,7 +144,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e // PrepareForAnchoring validates the signatures and generates the document root func (dp defaultProcessor) PrepareForAnchoring(model Model) error { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } @@ -152,12 +155,12 @@ func (dp defaultProcessor) PrepareForAnchoring(model Model) error { return errors.New("failed to validate signatures: %v", err) } - err = coredocument.CalculateDocumentRoot(cd) + err = dm.CalculateDocumentRoot() if err != nil { return errors.New("failed to generate document root: %v", err) } - err = model.UnpackCoreDocument(cd) + err = model.UnpackCoreDocument(dm) if err != nil { return errors.New("failed to unpack core document: %v", err) } @@ -167,7 +170,7 @@ func (dp defaultProcessor) PrepareForAnchoring(model Model) error { // AnchorDocument validates the model, and anchors the document func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) error { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } @@ -178,6 +181,7 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("pre anchor validation failed: %v", err) } + cd := dm.Document rootHash, err := anchors.ToDocumentRoot(cd.DocumentRoot) if err != nil { return errors.New("failed to get document root: %v", err) @@ -212,7 +216,7 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro // SendDocument does post anchor validations and sends the document to collaborators func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return errors.New("failed to pack core document: %v", err) } @@ -228,7 +232,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error return err } - extCollaborators, err := coredocument.GetExternalCollaborators(self.ID, cd) + extCollaborators, err := dm.GetExternalCollaborators(self.ID) if err != nil { return errors.New("get external collaborators failed: %v", err) } @@ -240,7 +244,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error continue } - erri = dp.Send(ctx, cd, cID) + erri = dp.Send(ctx, dm, cID) if erri != nil { err = errors.AppendError(err, erri) } diff --git a/documents/processor_test.go b/documents/processor_test.go index 1a4807867..eae2130b7 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -9,10 +9,9 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/ptypes/any" @@ -32,14 +31,14 @@ type mockModel struct { Model } -func (m mockModel) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { +func (m mockModel) PackCoreDocument() (*CoreDocumentModel, error) { args := m.Called() - cd, _ := args.Get(0).(*coredocumentpb.CoreDocument) + cd, _ := args.Get(0).(*CoreDocumentModel) return cd, args.Error(1) } -func (m mockModel) UnpackCoreDocument(cd *coredocumentpb.CoreDocument) error { - args := m.Called(cd) +func (m mockModel) UnpackCoreDocument(model *CoreDocumentModel) error { + args := m.Called(model) return args.Error(0) } @@ -60,28 +59,28 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "failed to pack core document") - cd := new(coredocumentpb.CoreDocument) + dm := NewCoreDocModel() + cd := dm.Document model = mockModel{} // failed to get id pub, _ := cfg.GetSigningKeyPair() cfg.Set("keys.signing.publicKey", "wrong path") - cd = coredocument.New() cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() cfg.Set("keys.signing.publicKey", pub) ctxh = testingconfig.CreateAccountContext(t, cfg) // failed unpack model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() + model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) assert.Error(t, err) @@ -91,8 +90,8 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { // success cd.Signatures = nil model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() + model.On("UnpackCoreDocument", dm).Return(nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) @@ -109,8 +108,8 @@ type p2pClient struct { Client } -func (p p2pClient) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { - args := p.Called(ctx, doc) +func (p p2pClient) GetSignaturesForDocument(ctx context.Context, model *CoreDocumentModel) error { + args := p.Called(ctx, model) return args.Error(0) } @@ -127,34 +126,35 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { assert.Contains(t, err.Error(), "failed to pack core document") // validations failed - cd := new(coredocumentpb.CoreDocument) + dm := NewCoreDocModel() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) + model.On("PackCoreDocument").Return(dm, nil).Times(4) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to validate model for signature request") // failed signature collection - cd = coredocument.New() + dm = NewCoreDocModel() + cd := dm.Document cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() - model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() + model.On("UnpackCoreDocument", dm).Return(nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForSignatureRequests(ctxh, model) assert.Nil(t, err) model.AssertExpectations(t) c := p2pClient{} - c.On("GetSignaturesForDocument", ctxh, cd).Return(errors.New("error")).Once() + c.On("GetSignaturesForDocument", ctxh, dm).Return(errors.New("error")).Once() dp.p2pClient = c model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) + model.On("PackCoreDocument").Return(dm, nil).Times(4) model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) @@ -164,11 +164,11 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // unpack fail c = p2pClient{} - c.On("GetSignaturesForDocument", ctxh, cd).Return(nil).Once() + c.On("GetSignaturesForDocument", ctxh, dm).Return(nil).Once() dp.p2pClient = c model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("PackCoreDocument").Return(dm, nil).Times(4) + model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) @@ -178,11 +178,11 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { // success c = p2pClient{} - c.On("GetSignaturesForDocument", ctxh, cd).Return(nil).Once() + c.On("GetSignaturesForDocument", ctxh, dm).Return(nil).Once() dp.p2pClient = c model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Times(4) + model.On("UnpackCoreDocument", dm).Return(nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) @@ -202,28 +202,29 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { assert.Contains(t, err.Error(), "failed to pack core document") // failed validations - cd := new(coredocumentpb.CoreDocument) + dm := NewCoreDocModel() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) + model.On("PackCoreDocument").Return(dm, nil).Times(4) err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to validate signatures") // failed unpack - cd = coredocument.New() + dm = NewCoreDocModel() + cd := dm.Document cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) + dm.setCoreDocumentSalts() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - err = coredocument.CalculateSigningRoot(cd, cd.DataRoot) + err = dm.CalculateSigningRoot(cd.DataRoot) assert.Nil(t, err) model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(errors.New("error")).Once() + model.On("PackCoreDocument").Return(dm, nil).Times(4) + model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) @@ -240,8 +241,8 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { // success model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(4) - model.On("UnpackCoreDocument", cd).Return(nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Times(4) + model.On("UnpackCoreDocument", dm).Return(nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) @@ -282,30 +283,31 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // validations failed model = mockModel{} - cd := new(coredocumentpb.CoreDocument) - model.On("PackCoreDocument").Return(cd, nil).Times(5) + dm := NewCoreDocModel() + model.On("PackCoreDocument").Return(dm, nil).Times(5) err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pre anchor validation failed") // get ID failed - cd = coredocument.New() + dm = NewCoreDocModel() + cd := dm.Document cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", Value: []byte("some data"), } - assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd, cd.DataRoot)) + dm.setCoreDocumentSalts() + assert.Nil(t, dm.CalculateSigningRoot(cd.DataRoot)) model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(5) + model.On("PackCoreDocument").Return(dm, nil).Times(5) model.On("CalculateDataRoot").Return(cd.DataRoot, nil) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) + assert.Nil(t, dm.CalculateDocumentRoot()) assert.Nil(t, err) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() err = dp.AnchorDocument(context.Background(), model) @@ -316,7 +318,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { // success model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(5) + model.On("PackCoreDocument").Return(dm, nil).Times(5) model.On("CalculateDataRoot").Return(cd.DataRoot, nil) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() @@ -347,15 +349,16 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { // failed validations model = mockModel{} - cd := new(coredocumentpb.CoreDocument) - model.On("PackCoreDocument").Return(cd, nil).Times(6) + dm := NewCoreDocModel() + model.On("PackCoreDocument").Return(dm, nil).Times(6) err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "post anchor validations failed") // failed send - cd = coredocument.New() + dm = NewCoreDocModel() + cd := dm.Document cd.DataRoot = utils.RandomSlice(32) cd.EmbeddedData = &any.Any{ TypeUrl: "some type", @@ -363,16 +366,16 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { } cd.Collaborators = [][]byte{[]byte("some id")} model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - assert.Nil(t, coredocument.FillSalts(cd)) - assert.Nil(t, coredocument.CalculateSigningRoot(cd, cd.DataRoot)) + dm.setCoreDocumentSalts() + assert.Nil(t, dm.CalculateSigningRoot(cd.DataRoot)) model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Times(6) + model.On("PackCoreDocument").Return(dm, nil).Times(6) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - assert.Nil(t, coredocument.CalculateDocumentRoot(cd)) + assert.Nil(t, dm.CalculateDocumentRoot()) docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) assert.Nil(t, err) repo := mockRepo{} diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 4ffb06c32..7c14d091a 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -7,10 +7,8 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" @@ -53,17 +51,21 @@ type PurchaseOrder struct { DateCreated *timestamp.Timestamp // purchase order date ExtraData []byte PurchaseOrderSalts *proofs.Salts - CoreDocument *coredocumentpb.CoreDocument + CoreDocumentModel *documents.CoreDocumentModel } // ID returns the DocumentIdentifier for this document // Note: this is not same as VersionIdentifier func (p *PurchaseOrder) ID() ([]byte, error) { - coreDoc, err := p.PackCoreDocument() + coreDocModel, err := p.PackCoreDocument() if err != nil { return []byte{}, err } - return coreDoc.DocumentIdentifier, nil + if coreDocModel.Document == nil { + return []byte{}, errors.New("nil core document") + } + + return coreDocModel.Document.DocumentIdentifier, nil } // getClientData returns the client data from the purchaseOrder model @@ -156,7 +158,7 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu } collaborators := append([]string{self}, payload.Collaborators...) - p.CoreDocument, err = coredocument.NewWithCollaborators(collaborators) + p.CoreDocumentModel, err = p.CoreDocumentModel.NewWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } @@ -260,7 +262,7 @@ func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb // PackCoreDocument packs the PurchaseOrder into a Core Document // If the, PurchaseOrder is new, it creates a valid identifiers -func (p *PurchaseOrder) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { +func (p *PurchaseOrder) PackCoreDocument() (*documents.CoreDocumentModel, error) { poData := p.createP2PProtobuf() poSerialized, err := proto.Marshal(poData) if err != nil { @@ -277,19 +279,24 @@ func (p *PurchaseOrder) PackCoreDocument() (*coredocumentpb.CoreDocument, error) return nil, errors.NewTypedError(err, errors.New("couldn't get POSalts")) } - coreDoc := new(coredocumentpb.CoreDocument) - proto.Merge(coreDoc, p.CoreDocument) - coreDoc.EmbeddedData = &poAny - coreDoc.EmbeddedDataSalts = documents.ConvertToProtoSalts(poSalts) - return coreDoc, err + err = p.CoreDocumentModel.PackCoreDocument(&poAny, documents.ConvertToProtoSalts(poSalts)) + if err != nil { + return nil, err + } + + return p.CoreDocumentModel, nil } // UnpackCoreDocument unpacks the core document into PurchaseOrder -func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) error { - if coreDoc == nil { - return centerrors.NilError(coreDoc) +func (p *PurchaseOrder) UnpackCoreDocument(coreDocModel *documents.CoreDocumentModel) error { + if coreDocModel == nil { + return errors.New("coredocmodel is nil %v", coreDocModel) + } + if coreDocModel.Document == nil { + return errors.New("core document provided is nil %v", coreDocModel.Document) } + coreDoc := coreDocModel.Document if coreDoc.EmbeddedData == nil || coreDoc.EmbeddedData.TypeUrl != documenttypes.PurchaseOrderDataTypeUrl { return errors.New("trying to convert document with incorrect schema") @@ -312,11 +319,9 @@ func (p *PurchaseOrder) UnpackCoreDocument(coreDoc *coredocumentpb.CoreDocument) p.PurchaseOrderSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) } - p.CoreDocument = new(coredocumentpb.CoreDocument) - proto.Merge(p.CoreDocument, coreDoc) - p.CoreDocument.EmbeddedDataSalts = nil - p.CoreDocument.EmbeddedData = nil + err = p.CoreDocumentModel.UnpackCoreDocument() return err + } // JSON marshals PurchaseOrder into a json bytes @@ -363,19 +368,18 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er } // CreateProofs generates proofs for given fields -func (p *PurchaseOrder) CreateProofs(fields []string) (coreDoc *coredocumentpb.CoreDocument, proofs []*proofspb.Proof, err error) { +func (p *PurchaseOrder) CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) { // There can be failure scenarios where the core doc for the particular document // is still not saved with roots in db due to failures during getting signatures. - coreDoc, err = p.PackCoreDocument() + _, err = p.PackCoreDocument() if err != nil { - return nil, nil, errors.New("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } tree, err := p.getDocumentDataTree() if err != nil { - return coreDoc, nil, errors.New("createProofs error %v", err) + return nil, errors.New("createProofs error %v", err) } - - proofs, err = coredocument.CreateProofs(tree, coreDoc, fields) - return coreDoc, proofs, err + proofs, err = p.CoreDocumentModel.CreateProofs(tree, fields) + return proofs, err } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 9cc38e602..f780ecd27 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -20,22 +20,20 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" @@ -83,8 +81,11 @@ func TestMain(m *testing.M) { func TestPO_FromCoreDocuments_invalidParameter(t *testing.T) { poModel := &PurchaseOrder{} - emptyCoreDocument := &coredocumentpb.CoreDocument{} - err := poModel.UnpackCoreDocument(emptyCoreDocument) + emptyCoreDocModel := &documents.CoreDocumentModel{ + nil, + nil, + } + err := poModel.UnpackCoreDocument(emptyCoreDocModel) assert.Error(t, err, "it should not be possible to init a empty core document") err = poModel.UnpackCoreDocument(nil) @@ -92,7 +93,11 @@ func TestPO_FromCoreDocuments_invalidParameter(t *testing.T) { invalidEmbeddedData := &any.Any{TypeUrl: "invalid"} coreDocument := &coredocumentpb.CoreDocument{EmbeddedData: invalidEmbeddedData} - err = poModel.UnpackCoreDocument(coreDocument) + coreDocModel := &documents.CoreDocumentModel{ + coreDocument, + nil, + } + err = poModel.UnpackCoreDocument(coreDocModel) assert.Error(t, err, "it should not be possible to init invalid typeUrl") } @@ -102,18 +107,19 @@ func TestPO_InitCoreDocument_successful(t *testing.T) { poData := testingdocuments.CreatePOData() - coreDocument := CreateCDWithEmbeddedPO(t, poData) - err := poModel.UnpackCoreDocument(coreDocument) - assert.Nil(t, err, "valid coredocument shouldn't produce an error") + coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) + poModel.CoreDocumentModel = coreDocumentModel + err := poModel.UnpackCoreDocument(coreDocumentModel) + assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") } func TestPO_InitCoreDocument_invalidCentId(t *testing.T) { poModel := &PurchaseOrder{} - coreDocument := CreateCDWithEmbeddedPO(t, purchaseorderpb.PurchaseOrderData{ + coreDocumentModel := CreateCDWithEmbeddedPO(t, purchaseorderpb.PurchaseOrderData{ Recipient: utils.RandomSlice(identity.CentIDLength + 1)}) - - err := poModel.UnpackCoreDocument(coreDocument) + poModel.CoreDocumentModel = coreDocumentModel + err := poModel.UnpackCoreDocument(coreDocumentModel) assert.Nil(t, err) assert.Nil(t, poModel.Recipient) } @@ -124,14 +130,15 @@ func TestPO_CoreDocument_successful(t *testing.T) { //init model with a CoreDoc poData := testingdocuments.CreatePOData() - coreDocument := CreateCDWithEmbeddedPO(t, poData) - poModel.UnpackCoreDocument(coreDocument) + coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) + poModel.CoreDocumentModel = coreDocumentModel + poModel.UnpackCoreDocument(coreDocumentModel) - returnedCoreDocument, err := poModel.PackCoreDocument() + returnedCoreDocumentModel, err := poModel.PackCoreDocument() assert.Nil(t, err, "transformation from purchase order to CoreDoc failed") - assert.Equal(t, coreDocument.EmbeddedData, returnedCoreDocument.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocument.EmbeddedDataSalts, returnedCoreDocument.EmbeddedDataSalts, "embeddedDataSalt should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedData, returnedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, returnedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") } func TestPO_ModelInterface(t *testing.T) { @@ -149,8 +156,9 @@ func TestPO_Type(t *testing.T) { func TestPO_JSON(t *testing.T) { poModel := &PurchaseOrder{} poData := testingdocuments.CreatePOData() - coreDocument := CreateCDWithEmbeddedPO(t, poData) - poModel.UnpackCoreDocument(coreDocument) + coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) + poModel.CoreDocumentModel = coreDocumentModel + poModel.UnpackCoreDocument(coreDocumentModel) jsonBytes, err := poModel.JSON() assert.Nil(t, err, "marshal to json didn't work correctly") @@ -159,13 +167,13 @@ func TestPO_JSON(t *testing.T) { err = poModel.FromJSON(jsonBytes) assert.Nil(t, err, "unmarshal JSON didn't work correctly") - receivedCoreDocument, err := poModel.PackCoreDocument() + receivedCoreDocumentModel, err := poModel.PackCoreDocument() assert.Nil(t, err, "JSON unmarshal damaged purchase order variables") - assert.Equal(t, receivedCoreDocument.EmbeddedData, coreDocument.EmbeddedData, "JSON unmarshal damaged purchase order variables") + assert.Equal(t, receivedCoreDocumentModel.Document.EmbeddedData, coreDocumentModel.Document.EmbeddedData, "JSON unmarshal damaged purchase order variables") } func TestPOModel_UnpackCoreDocument(t *testing.T) { - var model documents.Model = new(PurchaseOrder) + var model = new(PurchaseOrder) var err error // nil core doc @@ -173,19 +181,20 @@ func TestPOModel_UnpackCoreDocument(t *testing.T) { assert.Error(t, err, "unpack must fail") // embed data missing - err = model.UnpackCoreDocument(new(coredocumentpb.CoreDocument)) + err = model.UnpackCoreDocument(new(documents.CoreDocumentModel)) assert.Error(t, err, "unpack must fail due to missing embed data") // successful - coreDocument := CreateCDWithEmbeddedPO(t, testingdocuments.CreatePOData()) - err = model.UnpackCoreDocument(coreDocument) + coreDocumentModel := CreateCDWithEmbeddedPO(t, testingdocuments.CreatePOData()) + model.CoreDocumentModel = coreDocumentModel + err = model.UnpackCoreDocument(coreDocumentModel) assert.Nil(t, err, "valid core document with embedded purchase order shouldn't produce an error") - receivedCoreDocument, err := model.PackCoreDocument() + receivedCoreDocumentModel, err := model.PackCoreDocument() assert.Nil(t, err, "model should be able to return the core document with embedded purchase order") - assert.Equal(t, coreDocument.EmbeddedData, receivedCoreDocument.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocument.EmbeddedDataSalts, receivedCoreDocument.EmbeddedDataSalts, "embeddedDataSalt should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedData, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") + assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, receivedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") } func TestPOModel_getClientData(t *testing.T) { @@ -233,7 +242,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { assert.Equal(t, poModel.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - assert.Equal(t, poModel.CoreDocument.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) } func TestPOModel_calculateDataRoot(t *testing.T) { @@ -249,13 +258,12 @@ func TestPOModel_calculateDataRoot(t *testing.T) { assert.NotNil(t, poModel.PurchaseOrderSalts, "salts must be created") } func TestPOModel_createProofs(t *testing.T) { - poModel, corDoc, err := createMockPurchaseOrder(t) + poModel, err := createMockPurchaseOrder(t) assert.Nil(t, err) - corDoc, proof, err := poModel.CreateProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) + proof, err := poModel.CreateProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) - assert.NotNil(t, corDoc) - tree, _ := coredocument.GetDocumentRootTree(corDoc) + tree, err := poModel.CoreDocumentModel.GetDocumentRootTree() // Validate po_number valid, err := tree.ValidateProof(proof[0]) @@ -268,7 +276,7 @@ func TestPOModel_createProofs(t *testing.T) { assert.True(t, valid) // Validate []byte value - assert.Equal(t, poModel.CoreDocument.Collaborators[0], proof[1].Value) + assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators[0], proof[1].Value) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -277,9 +285,9 @@ func TestPOModel_createProofs(t *testing.T) { } func TestPOModel_createProofsFieldDoesNotExist(t *testing.T) { - poModel, _, err := createMockPurchaseOrder(t) + poModel, err := createMockPurchaseOrder(t) assert.Nil(t, err) - _, _, err = poModel.CreateProofs([]string{"nonexisting"}) + _, err = poModel.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } @@ -292,27 +300,27 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { assert.Equal(t, "po.po_number", leaf.Property.ReadableName()) } -func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, *coredocumentpb.CoreDocument, error) { - poModel := &PurchaseOrder{PoNumber: "3213121", NetAmount: 2, OrderAmount: 2, Currency: "USD", CoreDocument: coredocument.New()} - poModel.CoreDocument.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} +func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, error) { + poModel := &PurchaseOrder{PoNumber: "3213121", NetAmount: 2, OrderAmount: 2, Currency: "USD", CoreDocumentModel: documents.NewCoreDocModel()} + poModel.CoreDocumentModel.Document.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} dataRoot, err := poModel.CalculateDataRoot() if err != nil { - return nil, nil, err + return nil, err } // get the coreDoc for the purchaseOrder - corDoc, err := poModel.PackCoreDocument() + corDocModel, err := poModel.PackCoreDocument() if err != nil { - return nil, nil, err + return nil, err } - assert.Nil(t, coredocument.FillSalts(corDoc)) - err = coredocument.CalculateSigningRoot(corDoc, dataRoot) + + err = corDocModel.CalculateSigningRoot(dataRoot) if err != nil { - return nil, nil, err + return nil, err } - err = coredocument.CalculateDocumentRoot(corDoc) + err = corDocModel.CalculateDocumentRoot() if err != nil { - return nil, nil, err + return nil, err } - poModel.UnpackCoreDocument(corDoc) - return poModel, corDoc, nil + poModel.UnpackCoreDocument(corDocModel) + return poModel, nil } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 8096af99a..c7f9a0733 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -3,9 +3,7 @@ package purchaseorder import ( "context" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -57,10 +55,12 @@ func DefaultService( } } -// DeriveFromCoreDocument takes a core document and returns a purchase order -func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { - var model documents.Model = new(PurchaseOrder) - err := model.UnpackCoreDocument(cd) +// DeriveFromCoreDocumentModel takes a core document model and returns a purchase order +func (s service) DeriveFromCoreDocumentModel(coreDocModel *documents.CoreDocumentModel) (documents.Model, error) { + var model documents.Model = &PurchaseOrder{ + CoreDocumentModel: coreDocModel, + } + err := model.UnpackCoreDocument(coreDocModel) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } @@ -87,7 +87,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], po.CoreDocument.CurrentVersion, po) + err = s.repo.Create(self.ID[:], po.CoreDocumentModel.Document.CurrentVersion, po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -107,13 +107,13 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, nil, err } - cd, err := po.PackCoreDocument() + dm, err := po.PackCoreDocument() if err != nil { return nil, uuid.Nil, nil, err } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { return nil, uuid.Nil, nil, nil } @@ -127,12 +127,12 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - cd, err := po.PackCoreDocument() + dm, err := po.PackCoreDocument() if err != nil { return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - old, err := s.GetCurrentVersion(ctx, cd.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) if err != nil { return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } @@ -143,7 +143,7 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, cd.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { return nil, uuid.Nil, nil, err } @@ -195,7 +195,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpop } // update core document - oldCD, err := old.PackCoreDocument() + oldDM, err := old.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } @@ -206,7 +206,7 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpop } collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) - po.CoreDocument, err = coredocument.PrepareNewVersion(*oldCD, collaborators) + po.CoreDocumentModel, err = oldDM.PrepareNewVersion(collaborators) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) } @@ -226,11 +226,11 @@ func (s service) DerivePurchaseOrderData(doc documents.Model) (*clientpopb.Purch // DerivePurchaseOrderResponse returns po response from the model func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.PurchaseOrderResponse, error) { - cd, err := doc.PackCoreDocument() + dm, err := doc.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } - + cd := dm.Document collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { cid, err := identity.ToCentID(c) diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 7541f354c..8fc71e3be 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -8,7 +8,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" @@ -17,7 +16,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -73,8 +72,8 @@ func TestService_Update(t *testing.T) { // missing last version model = &testingdocuments.MockModel{} - cd := coredocument.New() - model.On("PackCoreDocument").Return(cd, nil).Once() + dm := documents.NewCoreDocModel() + model.On("PackCoreDocument").Return(dm, nil).Once() _, _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -84,15 +83,15 @@ func TestService_Update(t *testing.T) { payload.Collaborators = []string{"0x010203040506"} po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) - cd, err = po.PackCoreDocument() + dm, err = po.PackCoreDocument() assert.Nil(t, err) - cd.DocumentRoot = utils.RandomSlice(32) - po.(*PurchaseOrder).CoreDocument = cd - testRepo().Create(accountID, cd.CurrentVersion, po) + dm.Document.DocumentRoot = utils.RandomSlice(32) + po.(*PurchaseOrder).CoreDocumentModel = dm + testRepo().Create(accountID, dm.Document.CurrentVersion, po) // calculate data root fails model = &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() _, _, _, err = poSrv.Update(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) @@ -104,20 +103,21 @@ func TestService_Update(t *testing.T) { data.OrderAmount = 100 data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) collab := hexutil.Encode(utils.RandomSlice(6)) - newInv, err := poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{ - Identifier: hexutil.Encode(cd.DocumentIdentifier), + newPO, err := poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{ + Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), Collaborators: []string{collab}, Data: data, }) assert.Nil(t, err) - newData, err := poSrv.DerivePurchaseOrderData(newInv) + newData, err := poSrv.DerivePurchaseOrderData(newPO) assert.Nil(t, err) assert.Equal(t, data, newData) - po, _, _, err = poSrv.Update(ctxh, newInv) + po, _, _, err = poSrv.Update(ctxh, newPO) assert.Nil(t, err) assert.NotNil(t, po) - newCD, err := po.PackCoreDocument() + newDM, err := po.PackCoreDocument() + newCD := newDM.Document assert.Nil(t, err) assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) @@ -167,9 +167,10 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { old := new(PurchaseOrder) err = old.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), self.ID.String()) assert.Nil(t, err) - old.CoreDocument.DocumentIdentifier = id - old.CoreDocument.CurrentVersion = id - old.CoreDocument.DocumentRoot = utils.RandomSlice(32) + oldCD := old.CoreDocumentModel.Document + oldCD.DocumentIdentifier = id + oldCD.CurrentVersion = id + oldCD.DocumentRoot = utils.RandomSlice(32) err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ @@ -197,11 +198,13 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) - cd, err := doc.PackCoreDocument() + dm, err := doc.PackCoreDocument() + cd := dm.Document assert.Nil(t, err) assert.Equal(t, wantCollab, cd.Collaborators[2]) assert.Len(t, cd.Collaborators, 3) - oldCD, err := old.PackCoreDocument() + oldDM, err := old.PackCoreDocument() + oldCD = oldDM.Document assert.Nil(t, err) assert.Equal(t, oldCD.DocumentIdentifier, cd.DocumentIdentifier) assert.Equal(t, payload.Identifier, hexutil.Encode(cd.DocumentIdentifier)) @@ -251,13 +254,13 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { func TestService_DeriveFromCoreDocument(t *testing.T) { // nil doc poSrv := service{repo: testRepo()} - _, err := poSrv.DeriveFromCoreDocument(nil) + _, err := poSrv.DeriveFromCoreDocumentModel(nil) assert.Error(t, err, "must fail to derive") // successful data := testingdocuments.CreatePOData() - cd := CreateCDWithEmbeddedPO(t, data) - m, err := poSrv.DeriveFromCoreDocument(cd) + dm := CreateCDWithEmbeddedPO(t, data) + m, err := poSrv.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err, "must return model") assert.NotNil(t, m, "model must be non-nil") po, ok := m.(*PurchaseOrder) @@ -285,7 +288,8 @@ func TestService_Create(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, m) - newCD, err := m.PackCoreDocument() + newDM, err := m.PackCoreDocument() + newCD := newDM.Document assert.Nil(t, err) assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) @@ -324,10 +328,11 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { assert.Contains(t, err.Error(), "pack core document failed") // cent id failed - cd := coredocument.New() + dm := documents.NewCoreDocModel() + cd := dm.Document cd.Collaborators = [][]byte{{1, 2, 3, 4, 5, 6}, {5, 6, 7}} m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() r, err = poSrv.DerivePurchaseOrderResponse(m) m.AssertExpectations(t) assert.Nil(t, r) @@ -337,7 +342,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { // derive data failed cd.Collaborators = [][]byte{{1, 2, 3, 4, 5, 6}} m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(cd, nil).Once() + m.On("PackCoreDocument").Return(dm, nil).Once() r, err = poSrv.DerivePurchaseOrderResponse(m) m.AssertExpectations(t) assert.Nil(t, r) @@ -357,15 +362,19 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { func createMockDocument() (*PurchaseOrder, error) { documentIdentifier := utils.RandomSlice(32) nextIdentifier := utils.RandomSlice(32) - + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + NextVersion: nextIdentifier, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } model := &PurchaseOrder{ - PoNumber: "test_po", - OrderAmount: 42, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - NextVersion: nextIdentifier, - }, + PoNumber: "test_po", + OrderAmount: 42, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, documentIdentifier, model) return model, err @@ -375,14 +384,18 @@ func TestService_GetVersion_wrongTyp(t *testing.T) { _, poSrv := getServiceWithMockedLayers() currentVersion := utils.RandomSlice(32) documentIdentifier := utils.RandomSlice(32) - + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } //should be an po po := &invoice.Invoice{ - GrossAmount: 60, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - }, + GrossAmount: 60, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) @@ -402,30 +415,34 @@ func TestService_GetCurrentVersion(t *testing.T) { assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - mod1, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) + mod1, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) assert.Nil(t, err) poLoad1, _ := mod1.(*PurchaseOrder) - assert.Equal(t, poLoad1.CoreDocument.CurrentVersion, doc.CoreDocument.DocumentIdentifier) - + assert.Equal(t, poLoad1.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.DocumentIdentifier) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: doc.CoreDocumentModel.Document.DocumentIdentifier, + CurrentVersion: doc.CoreDocumentModel.Document.NextVersion, + NextVersion: thirdIdentifier, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } po2 := &PurchaseOrder{ - OrderAmount: 42, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: doc.CoreDocument.DocumentIdentifier, - CurrentVersion: doc.CoreDocument.NextVersion, - NextVersion: thirdIdentifier, - }, + OrderAmount: 42, + CoreDocumentModel: coreDocModel, } - err = testRepo().Create(accountID, doc.CoreDocument.NextVersion, po2) + err = testRepo().Create(accountID, doc.CoreDocumentModel.Document.NextVersion, po2) assert.Nil(t, err) - mod2, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocument.DocumentIdentifier) + mod2, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) assert.Nil(t, err) poLoad2, _ := mod2.(*PurchaseOrder) - assert.Equal(t, poLoad2.CoreDocument.CurrentVersion, doc.CoreDocument.NextVersion) - assert.Equal(t, poLoad2.CoreDocument.NextVersion, thirdIdentifier) + assert.Equal(t, poLoad2.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.NextVersion) + assert.Equal(t, poLoad2.CoreDocumentModel.Document.NextVersion, thirdIdentifier) } func TestService_GetVersion(t *testing.T) { @@ -434,13 +451,18 @@ func TestService_GetVersion(t *testing.T) { _, poSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: currentVersion, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } po := &PurchaseOrder{ - OrderAmount: 42, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - }, + OrderAmount: 42, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, currentVersion, po) assert.Nil(t, err) @@ -449,8 +471,8 @@ func TestService_GetVersion(t *testing.T) { mod, err := poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) loadpo, _ := mod.(*PurchaseOrder) - assert.Equal(t, loadpo.CoreDocument.CurrentVersion, currentVersion) - assert.Equal(t, loadpo.CoreDocument.DocumentIdentifier, documentIdentifier) + assert.Equal(t, loadpo.CoreDocumentModel.Document.CurrentVersion, currentVersion) + assert.Equal(t, loadpo.CoreDocumentModel.Document.DocumentIdentifier, documentIdentifier) mod, err = poSrv.GetVersion(ctxh, documentIdentifier, []byte{}) assert.Error(t, err) @@ -459,12 +481,17 @@ func TestService_GetVersion(t *testing.T) { func TestService_Exists(t *testing.T) { _, poSrv := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) + coreDoc := &coredocumentpb.CoreDocument{ + DocumentIdentifier: documentIdentifier, + CurrentVersion: documentIdentifier, + } + coreDocModel := &documents.CoreDocumentModel{ + coreDoc, + nil, + } po := &PurchaseOrder{ - OrderAmount: 42, - CoreDocument: &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - }, + OrderAmount: 42, + CoreDocumentModel: coreDocModel, } err := testRepo().Create(accountID, documentIdentifier, po) assert.Nil(t, err) @@ -504,8 +531,8 @@ func TestService_calculateDataRoot(t *testing.T) { // create failed po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) - err = poSrv.repo.Create(accountID, po.(*PurchaseOrder).CoreDocument.CurrentVersion, po) + assert.Nil(t, po.(*PurchaseOrder).CoreDocumentModel.Document.DataRoot) + err = poSrv.repo.Create(accountID, po.(*PurchaseOrder).CoreDocumentModel.Document.CurrentVersion, po) assert.Nil(t, err) po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, po) @@ -515,7 +542,7 @@ func TestService_calculateDataRoot(t *testing.T) { // success po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - assert.Nil(t, po.(*PurchaseOrder).CoreDocument.DataRoot) + assert.Nil(t, po.(*PurchaseOrder).CoreDocumentModel.Document.DataRoot) po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, po) diff --git a/documents/purchaseorder/utils_test.go b/documents/purchaseorder/utils_test.go index f256f2f9d..27560c5a9 100644 --- a/documents/purchaseorder/utils_test.go +++ b/documents/purchaseorder/utils_test.go @@ -3,20 +3,22 @@ package purchaseorder import ( "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/stretchr/testify/assert" ) -func CreateCDWithEmbeddedPO(t *testing.T, poData purchaseorderpb.PurchaseOrderData) *coredocumentpb.CoreDocument { +func CreateCDWithEmbeddedPO(t *testing.T, poData purchaseorderpb.PurchaseOrderData) *documents.CoreDocumentModel { identifier := []byte("1") poModel := &PurchaseOrder{} + poModel.CoreDocumentModel = documents.NewCoreDocModel() poModel.loadFromP2PProtobuf(&poData) _, err := poModel.getPurchaseOrderSalts(&poData) assert.NoError(t, err) - coreDocument, err := poModel.PackCoreDocument() + cdm, err := poModel.PackCoreDocument() assert.NoError(t, err) - coreDocument.DocumentIdentifier = identifier + cdm.Document.DocumentIdentifier = identifier - return coreDocument + return cdm } diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go deleted file mode 100644 index c4930fd3a..000000000 --- a/documents/read_acls_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// +build unit - -package documents - -//func Test_addNFTToReadRules(t *testing.T) { -// // wrong registry or token format -// registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") -// tokenID := utils.RandomSlice(34) -// -// err := coredocument.AddNFTToReadRules(nil, registry, tokenID) -// assert.Error(t, err) -// -// cd, err := coredocument.NewWithCollaborators([]string{"0x010203040506"}) -// assert.NoError(t, err) -// assert.Len(t, cd.ReadRules, 1) -// assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) -// assert.Len(t, cd.Roles, 1) -// -// tokenID = utils.RandomSlice(32) -// err = coredocument.AddNFTToReadRules(cd, registry, tokenID) -// assert.NoError(t, err) -// assert.Len(t, cd.ReadRules, 2) -// assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) -// assert.Len(t, cd.Roles, 2) -//} -// -//type mockRegistry struct { -// mock.Mock -//} -// -//func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { -// args := m.Called(registry, tokenID) -// addr, _ := args.Get(0).(common.Address) -// return addr, args.Error(1) -//} -// -//func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { -// account, err := identity.CentIDFromString("0x010203040506") -// assert.NoError(t, err) -// -// cd, err := coredocument.NewWithCollaborators([]string{account.String()}) -// assert.NoError(t, err) -// -// registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") -// -// // account can read -// validator := coredocument.NftValidator(nil) -// err = validator.NFTOwnerCanRead(cd, registry, nil, account) -// assert.NoError(t, err) -// -// // account not in read rules and nft missing -// account, err = identity.CentIDFromString("0x010203040505") -// assert.NoError(t, err) -// tokenID := utils.RandomSlice(32) -// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) -// assert.Error(t, err) -// -// tr := mockRegistry{} -// tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() -// coredocument.AddNFTToReadRules(cd, registry, tokenID) -// validator = coredocument.NftValidator(tr) -// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) -// assert.Error(t, err) -// assert.Contains(t, err, "failed to get owner of") -// tr.AssertExpectations(t) -// -// // not the same owner -// owner := common.BytesToAddress(utils.RandomSlice(20)) -// tr = mockRegistry{} -// tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() -// validator = coredocument.NftValidator(tr) -// err = validator.NFTOwnerCanRead(cd, registry, tokenID, account) -// assert.Error(t, err) -// tr.AssertExpectations(t) -//} diff --git a/documents/registry_test.go b/documents/registry_test.go index d102e57bf..a94b75ef6 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -5,9 +5,7 @@ package documents_test import ( "testing" - cd "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" ) @@ -15,11 +13,9 @@ import ( func TestRegistry_Register_LocateService_successful(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - coreDocument := testingcoredocument.GenerateCoreDocument() - documentType, err := cd.GetTypeURL(coreDocument) - assert.Nil(t, err, "should not throw an error because core document contains a type") - - err = registry.Register(documentType, a) + dm := testingdocuments.GenerateCoreDocumentModel() + documentType := dm.Document.EmbeddedData.TypeUrl + err := registry.Register(documentType, a) assert.Nil(t, err, "register didn't work with unused id") b, err := registry.LocateService(documentType) @@ -30,13 +26,14 @@ func TestRegistry_Register_LocateService_successful(t *testing.T) { func TestRegistry_Register_invalidId(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - coreDocument := testingcoredocument.GenerateCoreDocument() - coreDocument.EmbeddedData.TypeUrl = "testID_1" + dm := testingdocuments.GenerateCoreDocumentModel() + cd := dm.Document + cd.EmbeddedData.TypeUrl = "testID_1" - err := registry.Register(coreDocument.EmbeddedData.TypeUrl, a) + err := registry.Register(cd.EmbeddedData.TypeUrl, a) assert.Nil(t, err, "register didn't work with unused id") - err = registry.Register(coreDocument.EmbeddedData.TypeUrl, a) + err = registry.Register(cd.EmbeddedData.TypeUrl, a) assert.Error(t, err, "register shouldn't work with same id") err = registry.Register("testId", a) @@ -45,11 +42,10 @@ func TestRegistry_Register_invalidId(t *testing.T) { func TestRegistry_LocateService_invalid(t *testing.T) { registry := documents.NewServiceRegistry() - coreDocument := testingcoredocument.GenerateCoreDocument() - coreDocument.EmbeddedData.TypeUrl = "testID_2" - documentType, err := cd.GetTypeURL(coreDocument) - assert.Nil(t, err, "should not throw an error because core document contains a type") - - _, err = registry.LocateService(documentType) + dm := testingdocuments.GenerateCoreDocumentModel() + cd := dm.Document + cd.EmbeddedData.TypeUrl = "testID_2" + documentType := cd.EmbeddedData.TypeUrl + _, err := registry.LocateService(documentType) assert.Error(t, err, "should throw an error because no services is registered") } diff --git a/documents/service.go b/documents/service.go index 00bd1244a..16103fcc2 100644 --- a/documents/service.go +++ b/documents/service.go @@ -42,8 +42,8 @@ type Service interface { // GetVersion reads a document from the database GetVersion(ctx context.Context, documentID []byte, version []byte) (Model, error) - // DeriveFromCoreDocument derives a model given the core document - DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) + // DeriveFromCoreDocumentModel derives a model given the core document model + DeriveFromCoreDocumentModel(dm *CoreDocumentModel) (Model, error) // CreateProofs creates proofs for the latest version document given the fields CreateProofs(ctx context.Context, documentID []byte, fields []string) (*DocumentProof, error) @@ -91,12 +91,14 @@ func DefaultService( } func getIDs(model Model) ([]byte, []byte, error) { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, nil, err } + cd := dm.Document return cd.DocumentIdentifier, cd.NextVersion, nil + } func (s service) searchVersion(ctx context.Context, m Model) (Model, error) { @@ -143,13 +145,17 @@ func (s service) createProofs(model Model, fields []string) (*DocumentProof, err if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return nil, errors.NewTypedError(ErrDocumentInvalid, err) } - coreDoc, proofs, err := model.CreateProofs(fields) + proofs, err := model.CreateProofs(fields) if err != nil { return nil, errors.NewTypedError(ErrDocumentProof, err) } + coreDocModel, err := model.PackCoreDocument() + if err != nil { + return nil, errors.New("creating proofs failed while packing core document") + } return &DocumentProof{ - DocumentID: coreDoc.DocumentIdentifier, - VersionID: coreDoc.CurrentVersion, + DocumentID: coreDocModel.Document.DocumentIdentifier, + VersionID: coreDocModel.Document.CurrentVersion, FieldProofs: proofs, }, nil @@ -173,11 +179,12 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co return nil, errors.NewTypedError(ErrDocumentInvalid, err) } - doc, err := model.PackCoreDocument() + docModel, err := model.PackCoreDocument() if err != nil { return nil, errors.NewTypedError(ErrDocumentPackingCoreDocument, err) } + doc := docModel.Document srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] @@ -186,7 +193,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co } sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) - err = model.UnpackCoreDocument(doc) + err = model.UnpackCoreDocument(docModel) if err != nil { return nil, errors.NewTypedError(ErrDocumentUnPackingCoreDocument, err) } @@ -216,15 +223,22 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende return ErrDocumentConfigAccountID } + if model == nil { + return errors.New("no model given") + } + if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(ErrDocumentInvalid, err) } - doc, err := model.PackCoreDocument() + docModel, err := model.PackCoreDocument() if err != nil { return errors.NewTypedError(ErrDocumentPackingCoreDocument, err) } - + if docModel.Document == nil { + return errors.NewTypedError(ErrDocumentPackingCoreDocument, err) + } + doc := docModel.Document err = s.repo.Update(idConf.ID[:], doc.CurrentVersion, model) if err != nil { return errors.NewTypedError(ErrDocumentPersistence, err) @@ -265,28 +279,31 @@ func (s service) getVersion(ctx context.Context, documentID, version []byte) (Mo return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) } - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, err } - + cd := dm.Document if !bytes.Equal(cd.DocumentIdentifier, documentID) { return nil, errors.NewTypedError(ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) } return model, nil } -func (s service) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (Model, error) { - if cd == nil || cd.EmbeddedData == nil { +func (s service) DeriveFromCoreDocumentModel(dm *CoreDocumentModel) (Model, error) { + if dm == nil { + return nil, errors.New("no core doc model passed") + } + if dm.Document == nil || dm.Document.EmbeddedData == nil { return nil, errors.New("core document is nil") } - srv, err := s.registry.LocateService(cd.EmbeddedData.TypeUrl) + srv, err := s.registry.LocateService(dm.Document.EmbeddedData.TypeUrl) if err != nil { return nil, err } - return srv.DeriveFromCoreDocument(cd) + return srv.DeriveFromCoreDocumentModel(dm) } func (s service) Create(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) { @@ -308,10 +325,11 @@ func (s service) Update(ctx context.Context, model Model) (Model, uuid.UUID, cha } func (s service) getService(model Model) (Service, error) { - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, err } + cd := dm.Document return s.registry.LocateService(cd.EmbeddedData.TypeUrl) } diff --git a/documents/validator.go b/documents/validator.go index 00e4f043d..05bb61b38 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -56,15 +56,23 @@ func UpdateVersionValidator() Validator { return errors.New("need both the old and new model") } - oldCD, err := old.PackCoreDocument() + oldDM, err := old.PackCoreDocument() if err != nil { return errors.New("failed to fetch old core document: %v", err) } - newCD, err := new.PackCoreDocument() + newDM, err := new.PackCoreDocument() if err != nil { return errors.New("failed to fetch new core document: %v", err) } + if oldDM.Document == nil { + return errors.New("coredoc is nil") + } + if newDM.Document == nil { + return errors.New("coredoc is nil") + } + oldCD := oldDM.Document + newCD := newDM.Document checks := []struct { name string @@ -114,31 +122,17 @@ func UpdateVersionValidator() Validator { }) } -// getCoreDocument takes an model and returns the core document of the model -func getCoreDocument(model Model) (*coredocumentpb.CoreDocument, error) { - if model == nil { - return nil, errors.New("nil model") - } - - cd, err := model.PackCoreDocument() - if err != nil { - return nil, errors.New("failed to pack core document: %v", err) - } - - return cd, nil -} - // baseValidator validates the core document basic fields like identifier, versions, and salts func baseValidator() Validator { return ValidatorFunc(func(_, model Model) error { - cd, err := getCoreDocument(model) + dm, err := model.PackCoreDocument() if err != nil { return err } - - if cd == nil { + if dm.Document == nil { return errors.New("nil document") } + cd := dm.Document if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { err = errors.AppendError(err, NewError("cd_identifier", centerrors.RequiredField)) @@ -185,11 +179,12 @@ func checkSaltsFormat(salts []*coredocumentpb.DocumentSalt) bool { // recalculates the signing root and compares with existing one func signingRootValidator() Validator { return ValidatorFunc(func(_, model Model) error { - cd, err := getCoreDocument(model) + dm, err := model.PackCoreDocument() if err != nil { return err } + cd := dm.Document if utils.IsEmptyByteSlice(cd.SigningRoot) { return errors.New("signing root missing") } @@ -199,7 +194,7 @@ func signingRootValidator() Validator { return err } - tree, err := coredocument.GetDocumentSigningTree(cd, dataRoot) + tree, err := dm.GetDocumentSigningTree(dataRoot) if err != nil { return errors.New("failed to calculate signing root: %v", err) } @@ -216,16 +211,17 @@ func signingRootValidator() Validator { // recalculates the document root and compares with existing one func documentRootValidator() Validator { return ValidatorFunc(func(_, model Model) error { - cd, err := getCoreDocument(model) + dm, err := model.PackCoreDocument() if err != nil { return err } + cd := dm.Document if utils.IsEmptyByteSlice(cd.DocumentRoot) { return errors.New("document root missing") } - tree, err := coredocument.GetDocumentRootTree(cd) + tree, err := dm.GetDocumentRootTree() if err != nil { return errors.New("failed to calculate document root: %v", err) } @@ -244,11 +240,12 @@ func documentRootValidator() Validator { // Note: this needs to used only before document is sent for signatures from the collaborators func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { return ValidatorFunc(func(_, model Model) error { - cd, err := getCoreDocument(model) + dm, err := model.PackCoreDocument() if err != nil { return err } + cd := dm.Document if len(cd.Signatures) != 1 { return errors.New("expecting only one signature") } @@ -277,11 +274,12 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { // Note: this will break the current flow where we proceed to anchor even signatures verification fails func signaturesValidator(idService identity.Service) Validator { return ValidatorFunc(func(_, model Model) error { - cd, err := getCoreDocument(model) + dm, err := model.PackCoreDocument() if err != nil { return err } + cd := dm.Document if len(cd.Signatures) < 1 { return errors.New("atleast one signature expected") } @@ -304,11 +302,12 @@ func signaturesValidator(idService identity.Service) Validator { // assumes document root is generated and verified func anchoredValidator(repo anchors.AnchorRepository) Validator { return ValidatorFunc(func(_, new Model) error { - cd, err := getCoreDocument(new) + dm, err := new.PackCoreDocument() if err != nil { return errors.New("failed to get core document: %v", err) } + cd := dm.Document anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) if err != nil { return errors.New("failed to get anchorID: %v", err) diff --git a/documents/validator_test.go b/documents/validator_test.go index 9b143b122..4ffadab8f 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -5,14 +5,12 @@ package documents import ( "testing" - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/ptypes/any" @@ -143,9 +141,10 @@ func TestUpdateVersionValidator(t *testing.T) { assert.Contains(t, err.Error(), "failed to fetch old core document") // newM model pack core doc fail - oldCD := coredocument.New() + oldDM := NewCoreDocModel() + oldCD := oldDM.Document oldCD.DocumentRoot = utils.RandomSlice(32) - old.On("PackCoreDocument").Return(oldCD, nil).Once() + old.On("PackCoreDocument").Return(oldDM, nil).Once() newM.On("PackCoreDocument").Return(nil, errors.New("error")).Once() err = uvv.Validate(old, newM) old.AssertExpectations(t) @@ -154,10 +153,12 @@ func TestUpdateVersionValidator(t *testing.T) { assert.Contains(t, err.Error(), "failed to fetch new core document") // mismatched identifiers - newCD := coredocument.New() + newDM := NewCoreDocModel() + newCD := newDM.Document + newCD.DocumentRoot = utils.RandomSlice(32) newCD.NextVersion = nil - old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(newCD, nil).Once() + old.On("PackCoreDocument").Return(oldDM, nil).Once() + newM.On("PackCoreDocument").Return(newDM, nil).Once() err = uvv.Validate(old, newM) old.AssertExpectations(t) newM.AssertExpectations(t) @@ -165,40 +166,16 @@ func TestUpdateVersionValidator(t *testing.T) { assert.Equal(t, 5, errors.Len(err)) // success - newCD, err = coredocument.PrepareNewVersion(*oldCD, nil) + newDM, err = oldDM.PrepareNewVersion(nil) assert.Nil(t, err) - old.On("PackCoreDocument").Return(oldCD, nil).Once() - newM.On("PackCoreDocument").Return(newCD, nil).Once() + old.On("PackCoreDocument").Return(oldDM, nil).Once() + newM.On("PackCoreDocument").Return(newDM, nil).Once() err = uvv.Validate(old, newM) old.AssertExpectations(t) newM.AssertExpectations(t) assert.Nil(t, err) } -func Test_getCoreDocument(t *testing.T) { - // nil document - cd, err := getCoreDocument(nil) - assert.Error(t, err) - assert.Nil(t, cd) - - // pack core document fail - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - cd, err = getCoreDocument(model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Nil(t, cd) - - // success - model = mockModel{} - cd = coredocument.New() - model.On("PackCoreDocument").Return(cd, nil).Once() - got, err := getCoreDocument(model) - model.AssertExpectations(t) - assert.Nil(t, err) - assert.Equal(t, cd, got) -} - func TestValidator_baseValidator(t *testing.T) { bv := baseValidator() @@ -211,8 +188,10 @@ func TestValidator_baseValidator(t *testing.T) { // failed validator model = mockModel{} - cd := coredocument.New() - model.On("PackCoreDocument").Return(cd, nil).Once() + dm := NewCoreDocModel() + cd := dm.Document + cd.DocumentRoot = utils.RandomSlice(32) + model.On("PackCoreDocument").Return(dm, nil).Once() err = bv.Validate(nil, model) assert.Error(t, err) assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[0].Error()) @@ -220,8 +199,8 @@ func TestValidator_baseValidator(t *testing.T) { // success model = mockModel{} cd.DataRoot = utils.RandomSlice(32) - assert.Nil(t, coredocument.FillSalts(cd)) - model.On("PackCoreDocument").Return(cd, nil).Once() + dm.setCoreDocumentSalts() + model.On("PackCoreDocument").Return(dm, nil).Once() err = bv.Validate(nil, model) assert.Nil(t, err) } @@ -237,10 +216,11 @@ func TestValidator_signingRootValidator(t *testing.T) { assert.Error(t, err) // missing signing_root - cd := coredocument.New() - assert.Nil(t, coredocument.FillSalts(cd)) + dm := NewCoreDocModel() + cd := dm.Document + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = sv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -253,7 +233,7 @@ func TestValidator_signingRootValidator(t *testing.T) { Value: []byte{}, } model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = sv.Validate(nil, model) model.AssertExpectations(t) @@ -261,11 +241,11 @@ func TestValidator_signingRootValidator(t *testing.T) { assert.Contains(t, err.Error(), "signing root mismatch") // success - tree, err := coredocument.GetDocumentSigningTree(cd, cd.DataRoot) + tree, err := dm.GetDocumentSigningTree(cd.DataRoot) assert.Nil(t, err) cd.SigningRoot = tree.RootHash() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = sv.Validate(nil, model) model.AssertExpectations(t) @@ -283,10 +263,11 @@ func TestValidator_documentRootValidator(t *testing.T) { assert.Error(t, err) // missing document root - cd := coredocument.New() - assert.Nil(t, coredocument.FillSalts(cd)) + dm := NewCoreDocModel() + cd := dm.Document + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = dv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -295,18 +276,18 @@ func TestValidator_documentRootValidator(t *testing.T) { // mismatch signing roots cd.DocumentRoot = utils.RandomSlice(32) model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = dv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "document root mismatch") // success - tree, err := coredocument.GetDocumentRootTree(cd) + tree, err := dm.GetDocumentRootTree() assert.Nil(t, err) cd.DocumentRoot = tree.RootHash() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = dv.Validate(nil, model) model.AssertExpectations(t) assert.Nil(t, err) @@ -325,10 +306,12 @@ func TestValidator_selfSignatureValidator(t *testing.T) { assert.Error(t, err) // signature length mismatch - cd := coredocument.New() - assert.Nil(t, coredocument.FillSalts(cd)) + dm := NewCoreDocModel() + cd := dm.Document + cd.DocumentRoot = utils.RandomSlice(32) + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -343,7 +326,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { } cd.Signatures = append(cd.Signatures, s) model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -356,7 +339,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Nil(t, err) @@ -374,10 +357,11 @@ func TestValidator_signatureValidator(t *testing.T) { assert.Error(t, err) // signature length mismatch - cd := coredocument.New() - assert.Nil(t, coredocument.FillSalts(cd)) + dm := NewCoreDocModel() + cd := dm.Document + dm.setCoreDocumentSalts() model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = ssv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -385,7 +369,7 @@ func TestValidator_signatureValidator(t *testing.T) { // failed validation model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("fail")).Once() s := &coredocumentpb.Signature{EntityId: utils.RandomSlice(7)} cd.Signatures = append(cd.Signatures, s) @@ -396,7 +380,7 @@ func TestValidator_signatureValidator(t *testing.T) { // success model = mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() cd.SigningRoot = utils.RandomSlice(32) cd.Signatures = []*coredocumentpb.Signature{{}} @@ -415,16 +399,13 @@ func TestPreAnchorValidator(t *testing.T) { func TestValidator_anchoredValidator(t *testing.T) { av := anchoredValidator(mockRepo{}) - // fail get core document - err := av.Validate(nil, nil) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get core document") - // failed anchorID model := &mockModel{} - cd := &coredocumentpb.CoreDocument{} - model.On("PackCoreDocument").Return(cd, nil).Once() - err = av.Validate(nil, model) + dm := NewCoreDocModel() + cd := dm.Document + cd.CurrentVersion = utils.RandomSlice(30) + model.On("PackCoreDocument").Return(dm, nil).Once() + err := av.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get anchorID") @@ -432,7 +413,7 @@ func TestValidator_anchoredValidator(t *testing.T) { // failed docRoot model = &mockModel{} cd.CurrentVersion = utils.RandomSlice(32) - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -447,7 +428,7 @@ func TestValidator_anchoredValidator(t *testing.T) { r.On("GetDocumentRootOf", anchorID).Return(nil, errors.New("error")).Once() cd.DocumentRoot = utils.RandomSlice(32) model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) @@ -461,7 +442,7 @@ func TestValidator_anchoredValidator(t *testing.T) { r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() cd.DocumentRoot = utils.RandomSlice(32) model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) @@ -474,7 +455,7 @@ func TestValidator_anchoredValidator(t *testing.T) { r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() cd.DocumentRoot = docRoot[:] model = &mockModel{} - model.On("PackCoreDocument").Return(cd, nil).Once() + model.On("PackCoreDocument").Return(dm, nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) @@ -581,7 +562,7 @@ func TestValidate_baseValidator(t *testing.T) { for _, c := range tests { model := mockModel{} - model.On("PackCoreDocument", mock.Anything).Return(c.doc, nil).Once() + model.On("PackCoreDocument", mock.Anything).Return(&CoreDocumentModel{c.doc, nil}, nil).Once() err := baseValidator.Validate(nil, &model) if c.key == "" { diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 0e3eff84d..fdcefdd03 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -86,11 +85,12 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return MintRequest{}, err } - corDoc, err := model.PackCoreDocument() + corDocModel, err := model.PackCoreDocument() if err != nil { return MintRequest{}, err } + corDoc := corDocModel.Document proofs, err := s.docSrv.CreateProofs(ctx, documentID, proofFields) if err != nil { return MintRequest{}, err @@ -140,11 +140,12 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, nil, err } - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, nil, err } + cd := dm.Document registry := common.HexToAddress(registryAddress) mt := getStoredNFT(cd.Nfts, registry.Bytes()) // check if the nft is successfully minted @@ -181,28 +182,29 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - cd, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { errOut <- err return } - data := cd.EmbeddedData - cd, err = coredocument.PrepareNewVersion(*cd, nil) + data := dm.Document.EmbeddedData + newDM, err := dm.PrepareNewVersion(nil) if err != nil { errOut <- err return } - cd.EmbeddedData = data - addNFT(cd, registry.Bytes(), tokenID[:]) - err = coredocument.AddNFTToReadRules(cd, registry, tokenID.BigInt().Bytes()) + newCD := newDM.Document + newCD.EmbeddedData = data + addNFT(newDM, registry.Bytes(), tokenID[:]) + err = newDM.AddNFTToReadRules(registry, tokenID.BigInt().Bytes()) if err != nil { errOut <- err return } - model, err = s.docSrv.DeriveFromCoreDocument(cd) + model, err = s.docSrv.DeriveFromCoreDocumentModel(newDM) if err != nil { errOut <- err return @@ -217,11 +219,11 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, isDone := <-done if !isDone { // some problem occured in a child task - errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(cd.DocumentIdentifier), txID) + errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(newCD.DocumentIdentifier), txID) return } - requestData, err := s.prepareMintRequest(ctx, tokenID, cd.DocumentIdentifier, depositAddress, proofFields) + requestData, err := s.prepareMintRequest(ctx, tokenID, newCD.DocumentIdentifier, depositAddress, proofFields) if err != nil { errOut <- errors.New("failed to prepare mint request: %v", err) return @@ -277,7 +279,8 @@ func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.N // addNFT adds/replaces the NFT // Note: this is replace operation. Ensure existing token is not minted -func addNFT(cd *coredocumentpb.CoreDocument, registry, tokenID []byte) { +func addNFT(dm *documents.CoreDocumentModel, registry, tokenID []byte) { + cd := dm.Document nft := getStoredNFT(cd.Nfts, registry) if nft == nil { nft = new(coredocumentpb.NFT) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index d1341667f..244f7b106 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -12,7 +12,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" @@ -20,7 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" @@ -155,11 +154,12 @@ func TestPaymentObligationService(t *testing.T) { { "happypath", func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) { - coreDoc := coredocument.New() + coreDocModel := documents.NewCoreDocModel() + coreDoc := coreDocModel.Document coreDoc.DocumentRoot = utils.RandomSlice(32) proof := getDummyProof(coreDoc) docServiceMock := testingdocuments.MockService{} - docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocument: coreDoc}, nil) + docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocumentModel: coreDocModel}, nil) docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIDService{} @@ -259,20 +259,22 @@ func decodeHex(hex string) []byte { } func Test_addNFT(t *testing.T) { - cd := coredocument.New() + dm := documents.NewCoreDocModel() + cd := dm.Document + cd.DocumentRoot = utils.RandomSlice(32) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") tokenID := utils.RandomSlice(32) assert.Nil(t, cd.Nfts) - addNFT(cd, registry.Bytes(), tokenID) + addNFT(dm, registry.Bytes(), tokenID) assert.Len(t, cd.Nfts, 1) assert.Len(t, cd.Nfts[0].RegistryId, 32) assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) tokenID = utils.RandomSlice(32) - addNFT(cd, registry.Bytes(), tokenID) + addNFT(dm, registry.Bytes(), tokenID) assert.Len(t, cd.Nfts, 1) assert.Len(t, cd.Nfts[0].RegistryId, 32) assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 57ed3feb8..819ea13d8 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" @@ -22,7 +21,7 @@ var cfg config.Configuration var idService identity.Service var payOb nft.PaymentObligation var txManager transactions.Manager -var tokenRegistry coredocument.TokenRegistry +var tokenRegistry documents.TokenRegistry func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") @@ -32,7 +31,7 @@ func TestMain(m *testing.M) { cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txManager = ctx[transactions.BootstrappedService].(transactions.Manager) - tokenRegistry = ctx[nft.BootstrappedPayObService].(coredocument.TokenRegistry) + tokenRegistry = ctx[nft.BootstrappedPayObService].(documents.TokenRegistry) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) diff --git a/p2p/client.go b/p2p/client.go index e98ec9dab..a93a0f272 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,18 +4,18 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/golang/protobuf/proto" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/version" @@ -127,7 +127,7 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.CoreDocument, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err @@ -135,6 +135,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.C var resp *p2ppb.SignatureResponse var header *p2ppb.Header + doc := model.Document tc, err := s.config.GetAccount(receiverCentID[:]) if err == nil { @@ -146,7 +147,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.C return nil, err } - resp, err = h.RequestDocumentSignature(localPeerCtx, &p2ppb.SignatureRequest{Document: &doc}) + resp, err = h.RequestDocumentSignature(localPeerCtx, &p2ppb.SignatureRequest{Document: doc}) if err != nil { return nil, err } @@ -162,7 +163,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.C if err != nil { return nil, err } - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &doc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: doc}) if err != nil { return nil, err } @@ -190,7 +191,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, doc coredocumentpb.C header = recvEnvelope.Header } - err = validateSignatureResp(s.idService, receiverCentID, &doc, header, resp) + err = validateSignatureResp(s.idService, receiverCentID, &model, header, resp) if err != nil { return nil, err } @@ -204,8 +205,8 @@ type signatureResponseWrap struct { err error } -func (s *peer) getSignatureAsync(ctx context.Context, doc *coredocumentpb.CoreDocument, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, *doc, receiverCentID) +func (s *peer) getSignatureAsync(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, model, receiverCentID) out <- signatureResponseWrap{ resp: resp, err: err, @@ -213,7 +214,7 @@ func (s *peer) getSignatureAsync(ctx context.Context, doc *coredocumentpb.CoreDo } // GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *peer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb.CoreDocument) error { +func (s *peer) GetSignaturesForDocument(ctx context.Context, model *documents.CoreDocumentModel) error { in := make(chan signatureResponseWrap) defer close(in) @@ -227,11 +228,12 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb return centerrors.Wrap(err, "failed to get self") } - extCollaborators, err := coredocument.GetExternalCollaborators(self.ID, doc) + extCollaborators, err := model.GetExternalCollaborators(self.ID) if err != nil { return centerrors.Wrap(err, "failed to get external collaborators") } + doc := model.Document var count int peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) for _, collaborator := range extCollaborators { @@ -240,7 +242,10 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, doc *coredocumentpb return centerrors.Wrap(err, "failed to convert to CentID") } count++ - go s.getSignatureAsync(peerCtx, doc, collaboratorID, in) + m := *model + nd := *doc + m.Document = &nd + go s.getSignatureAsync(peerCtx, m, collaboratorID, in) } var responses []signatureResponseWrap @@ -270,7 +275,7 @@ func convertClientError(recv *p2ppb.Envelope) error { return errors.New(resp.Message) } -func validateSignatureResp(identityService identity.Service, receiver identity.CentID, doc *coredocumentpb.CoreDocument, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { +func validateSignatureResp(identityService identity.Service, receiver identity.CentID, model *documents.CoreDocumentModel, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { compatible := version.CheckVersion(header.NodeVersion) if !compatible { return version.IncompatibleVersionError(header.NodeVersion) @@ -281,6 +286,7 @@ func validateSignatureResp(identityService identity.Service, receiver identity.C return centerrors.New(code.AuthenticationFailed, err.Error()) } + doc := model.Document err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) if err != nil { return centerrors.New(code.AuthenticationFailed, "signature invalid") diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 4ac2bdf07..cc49fabf0 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -7,15 +7,13 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -49,28 +47,28 @@ func TestMain(m *testing.M) { func TestClient_GetSignaturesForDocument(t *testing.T) { tc, _, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - err = client.GetSignaturesForDocument(ctxh, doc) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + err = client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) - assert.Equal(t, 2, len(doc.Signatures)) + assert.Equal(t, 2, len(dm.Document.Signatures)) } func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - err = client.GetSignaturesForDocument(ctxh, doc) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + err = client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) // one signature would be missing - assert.Equal(t, 1, len(doc.Signatures)) + assert.Equal(t, 1, len(dm.Document.Signatures)) } func TestClient_SendAnchoredDocument(t *testing.T) { tc, cid, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - _, err = client.SendAnchoredDocument(ctxh, cid.CentID(), &p2ppb.AnchorDocumentRequest{Document: doc}) + _, err = client.SendAnchoredDocument(ctxh, cid.CentID(), &p2ppb.AnchorDocumentRequest{Document: dm.Document}) if assert.Error(t, err) { assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) } @@ -91,23 +89,26 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account return tcr, id, err } -func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *coredocumentpb.CoreDocument { +func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *documents.CoreDocumentModel { idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) - - doc := testingcoredocument.GenerateCoreDocumentWithCollaborators(collaborators) - - m, err := docService.DeriveFromCoreDocument(doc) + dm := testingdocuments.GenerateCoreDocumentModelWithCollaborators(collaborators) + m, err := docService.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err) droot, err := m.CalculateDataRoot() assert.Nil(t, err) - tree, _ := coredocument.GetDocumentSigningTree(doc, droot) - doc.SigningRoot = tree.RootHash() - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) - doc.Signatures = append(doc.Signatures, sig) - tree, _ = coredocument.GetDocumentRootTree(doc) - doc.DocumentRoot = tree.RootHash() - return doc + dm, err = m.PackCoreDocument() + assert.NoError(t, err) + + tree, err := dm.GetDocumentSigningTree(droot) + assert.NoError(t, err) + dm.Document.SigningRoot = tree.RootHash() + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, dm.Document.SigningRoot) + dm.Document.Signatures = append(dm.Document.Signatures, sig) + tree, err = dm.GetDocumentRootTree() + assert.NoError(t, err) + dm.Document.DocumentRoot = tree.RootHash() + return dm } diff --git a/p2p/client_test.go b/p2p/client_test.go index 151afdda7..db841d97a 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -6,16 +6,13 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/golang/protobuf/proto" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" libp2pPeer "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" @@ -23,7 +20,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" @@ -49,7 +46,9 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDoc := testingcoredocument.GenerateCoreDocument() + + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -61,7 +60,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { assert.NoError(t, err, "signature request could not be created") m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) - resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -74,7 +73,8 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { idService := getIDMocks(centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDoc := testingcoredocument.GenerateCoreDocument() + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -84,7 +84,7 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { assert.NoError(t, err, "signature request could not be created") m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) - resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -96,7 +96,8 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDoc := testingcoredocument.GenerateCoreDocument() + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -111,7 +112,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - resp, err := testClient.getSignatureForDocument(ctx, *coreDoc, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 305ae3476..47ed5c08c 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -115,11 +115,12 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { + dm := new(documents.CoreDocumentModel) if sigReq.Document == nil { return nil, errors.New("nil core document") } - - model, err := srv.docSrv.DeriveFromCoreDocument(sigReq.Document) + dm.Document = sigReq.Document + model, err := srv.docSrv.DeriveFromCoreDocumentModel(dm) if err != nil { return nil, errors.New("failed to derive from core doc: %v", err) } @@ -160,7 +161,9 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest, senderID []byte) (*p2ppb.AnchorDocumentResponse, error) { - model, err := srv.docSrv.DeriveFromCoreDocument(docReq.Document) + dm := new(documents.CoreDocumentModel) + dm.Document = docReq.Document + model, err := srv.docSrv.DeriveFromCoreDocumentModel(dm) if err != nil { return nil, errors.New("failed to derive from core doc: %v", err) } @@ -211,17 +214,15 @@ func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRe if err != nil { return nil, err } - doc, err := model.PackCoreDocument() + dm, err := model.PackCoreDocument() if err != nil { return nil, err } - - err = DocumentAccessValidator(doc, docReq, requesterCentID) - if err != nil { - return &p2ppb.GetDocumentResponse{Document: doc}, nil - } - - return nil, err + //err = dm.ValidateDocumentAccess(docReq, requesterCentID) + //if err != nil { + // return nil, err + //} + return &p2ppb.GetDocumentResponse{Document: dm.Document}, nil } func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index f2093fe67..b0403d0f5 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,18 +8,18 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/golang/protobuf/ptypes/any" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/coredocument" cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" @@ -29,7 +29,6 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/coredocument" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/proto" @@ -74,15 +73,17 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) centrifugeId := createIdentity(t) - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) assert.NotNil(t, resp) // Add signature received + doc := dm.Document doc.Signatures = append(doc.Signatures, resp.Signature) - tree, _ := coredocument.GetDocumentRootTree(doc) + tree, err := dm.GetDocumentRootTree() + assert.NoError(t, err) doc.DocumentRoot = tree.RootHash() // Anchor document @@ -97,13 +98,13 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { watchCommittedAnchor := <-anchorConfirmations assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") - anchorReq := getAnchoredRequest(doc) + anchorReq := getAnchoredRequest(dm) anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") // Retrieve document from anchor repository with document_identifier - getReq := getGetDocumentRequest(doc) + getReq := getGetDocumentRequest(dm) getDocResp, err := handler.GetDocument(ctxh, getReq, centrifugeId) assert.Nil(t, err) assert.ObjectsAreEqual(getDocResp.Document, doc) @@ -115,8 +116,8 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { tc, err := contextutil.Account(ctxh) _, err = cfgService.CreateAccount(tc) assert.NoError(t, err) - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(dm) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, req) pub, _ := cfg.GetP2PKeyPair() @@ -133,14 +134,16 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { resp := resolveSignatureResponse(t, p2pResp) assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature + doc := dm.Document assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil) + doc := dm.Document doc.SigningRoot = nil - req := getSignatureRequest(doc) + req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.NotNil(t, err, "must be non nil") assert.Nil(t, resp, "must be nil") @@ -148,14 +151,14 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { } func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(dm) ctxh := testingconfig.CreateAccountContext(t, cfg) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") - req = getSignatureRequest(doc) + req = getSignatureRequest(dm) resp, err = handler.RequestDocumentSignature(ctxh, req) assert.NotNil(t, err, "must not be nil") assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists.Error()) @@ -163,8 +166,9 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(dm) + doc := dm.Document resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") @@ -172,28 +176,30 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { sig := resp.Signature assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") //Update document - newDoc, err := coredocument.PrepareNewVersion(*doc, nil) + newDM, err := dm.PrepareNewVersion(nil) assert.Nil(t, err) - updateDocumentForP2Phandler(t, newDoc) - newDoc = prepareDocumentForP2PHandler(t, newDoc) - req = getSignatureRequest(newDoc) + updateDocumentForP2Phandler(t, newDM) + newDM = prepareDocumentForP2PHandler(t, newDM) + req = getSignatureRequest(newDM) resp, err = handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig = resp.Signature + newDoc := newDM.Document assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil) - newDoc, err := coredocument.PrepareNewVersion(*doc, nil) + dm := prepareDocumentForP2PHandler(t, nil) + newDM, err := dm.PrepareNewVersion(nil) assert.Nil(t, err) + newDoc := newDM.Document assert.NotEqual(t, newDoc.DocumentIdentifier, newDoc.CurrentVersion) - updateDocumentForP2Phandler(t, newDoc) - newDoc = prepareDocumentForP2PHandler(t, newDoc) - req := getSignatureRequest(newDoc) + updateDocumentForP2Phandler(t, newDM) + newDM = prepareDocumentForP2PHandler(t, newDM) + req := getSignatureRequest(newDM) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") @@ -204,8 +210,9 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T func TestHandler_RequestDocumentSignature(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + doc := dm.Document + req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") @@ -217,9 +224,10 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { centrifugeId := createIdentity(t) - doc := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil) // Anchor document + doc := dm.Document idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) @@ -232,7 +240,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { watchCommittedAnchor := <-anchorConfirmations assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") - anchorReq := getAnchoredRequest(doc) + anchorReq := getAnchoredRequest(dm) anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq, idConfig.ID[:]) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) @@ -255,15 +263,16 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) centrifugeId := createIdentity(t) - doc := prepareDocumentForP2PHandler(t, nil) - req := getSignatureRequest(doc) + dm := prepareDocumentForP2PHandler(t, nil) + req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) assert.NotNil(t, resp) // Add signature received + doc := dm.Document doc.Signatures = append(doc.Signatures, resp.Signature) - tree, _ := coredocument.GetDocumentRootTree(doc) + tree, _ := dm.GetDocumentRootTree() doc.DocumentRoot = tree.RootHash() // Anchor document @@ -278,7 +287,7 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { watchCommittedAnchor := <-anchorConfirmations assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") - anchorReq := getAnchoredRequest(doc) + anchorReq := getAnchoredRequest(dm) anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") @@ -321,37 +330,41 @@ func createIdentity(t *testing.T) identity.CentID { return centrifugeId } -func prepareDocumentForP2PHandler(t *testing.T, doc *coredocumentpb.CoreDocument) *coredocumentpb.CoreDocument { +func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel) *documents.CoreDocumentModel { idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) - if doc == nil { - doc = testingcoredocument.GenerateCoreDocument() + if dm == nil { + dm = testingdocuments.GenerateCoreDocumentModel() } - m, err := docSrv.DeriveFromCoreDocument(doc) + m, err := docSrv.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err) droot, err := m.CalculateDataRoot() assert.Nil(t, err) - tree, err := coredocument.GetDocumentSigningTree(doc, droot) + dm, err = m.PackCoreDocument() assert.NoError(t, err) + + tree, err := dm.GetDocumentSigningTree(droot) + assert.NoError(t, err) + doc := dm.Document doc.SigningRoot = tree.RootHash() sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) doc.Signatures = append(doc.Signatures, sig) - tree, err = coredocument.GetDocumentRootTree(doc) + tree, err = dm.GetDocumentRootTree() assert.NoError(t, err) doc.DocumentRoot = tree.RootHash() - return doc + return dm } -func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) { +func updateDocumentForP2Phandler(t *testing.T, model *documents.CoreDocumentModel) { invData := &invoicepb.InvoiceData{} dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) serializedInv, err := proto.Marshal(invData) assert.NoError(t, err) - + doc := model.Document doc.EmbeddedData = &any.Any{ TypeUrl: documenttypes.InvoiceDataTypeUrl, Value: serializedInv, @@ -361,15 +374,18 @@ func updateDocumentForP2Phandler(t *testing.T, doc *coredocumentpb.CoreDocument) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) } -func getAnchoredRequest(doc *coredocumentpb.CoreDocument) *p2ppb.AnchorDocumentRequest { - return &p2ppb.AnchorDocumentRequest{Document: doc} +func getAnchoredRequest(dm *documents.CoreDocumentModel) *p2ppb.AnchorDocumentRequest { + doc := *dm.Document + return &p2ppb.AnchorDocumentRequest{Document: &doc} } -func getSignatureRequest(doc *coredocumentpb.CoreDocument) *p2ppb.SignatureRequest { - return &p2ppb.SignatureRequest{Document: doc} +func getSignatureRequest(dm *documents.CoreDocumentModel) *p2ppb.SignatureRequest { + doc := *dm.Document + return &p2ppb.SignatureRequest{Document: &doc} } -func getGetDocumentRequest(doc *coredocumentpb.CoreDocument) *p2ppb.GetDocumentRequest { +func getGetDocumentRequest(dm *documents.CoreDocumentModel) *p2ppb.GetDocumentRequest { + doc := dm.Document return &p2ppb.GetDocumentRequest{DocumentIdentifier: doc.DocumentIdentifier} } diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 899282983..9b2f259ed 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -17,7 +17,6 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -25,7 +24,7 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/version" @@ -180,7 +179,8 @@ func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { ctx := testingconfig.CreateAccountContext(t, cfg) - req := &p2ppb.AnchorDocumentRequest{Document: coredocument.New()} + dm := documents.NewCoreDocModel() + req := &p2ppb.AnchorDocumentRequest{Document: dm.Document} p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDoc, req) assert.NoError(t, err) diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 5f976c55b..fb4829352 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -3,10 +3,6 @@ package receiver import ( "fmt" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/ethereum/go-ethereum/common" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -105,30 +101,6 @@ func HandshakeValidator(networkID uint32, idService identity.Service) ValidatorG } } -// DocumentAccessValidator validates the GetDocument request against the AccessType indicated in the request -func DocumentAccessValidator(doc *coredocumentpb.CoreDocument, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) error { - av := coredocument.AccountValidator() - // checks which access type is relevant for the request - switch docReq.GetAccessType() { - case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: - if !av.AccountCanRead(doc, requesterCentID) { - return errors.New("requester does not have access") - } - case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: - registry := common.BytesToAddress(docReq.NftRegistryAddress) - if av.NFTOwnerCanRead(doc, registry, docReq.NftTokenId, requesterCentID) != nil { - return errors.New("requester does not have access") - } - //// case AccessTokenValidation - // case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: - // - // case p2ppb.AccessType_ACCESS_TYPE_INVALID: - default: - return errors.New("invalid access type ") - } - return nil -} - func incompatibleNetworkError(configNetwork uint32, nodeNetwork uint32) error { return centerrors.New(code.NetworkMismatch, fmt.Sprintf("Incompatible network id: node network: %d, client network: %d", configNetwork, nodeNetwork)) } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 5dca6b7bf..4a1436af1 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -5,8 +5,6 @@ package receiver import ( "testing" - "github.com/centrifuge/go-centrifuge/coredocument" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -143,17 +141,17 @@ func TestValidate_handshakeValidator(t *testing.T) { } func TestDocumentAccessValidator_Collaborator(t *testing.T) { - account1, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) - cd, err := coredocument.NewWithCollaborators([]string{account1.String()}) - assert.NotNil(t, cd.Collaborators) - - docId := cd.DocumentIdentifier - req := &p2ppb.GetDocumentRequest{DocumentIdentifier: docId, AccessType: p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION} - err = DocumentAccessValidator(cd, req, account1) - assert.NoError(t, err) - - account2, err := identity.CentIDFromString("0x012345678910") - err = DocumentAccessValidator(cd, req, account2) - assert.Error(t, err, "requester does not have access") + //account1, err := identity.CentIDFromString("0x010203040506") + //assert.NoError(t, err) + //cd, err := coredocument.NewWithCollaborators([]string{account1.String()}) + //assert.NotNil(t, cd.Collaborators) + // + //docId := cd.DocumentIdentifier + //req := &p2ppb.GetDocumentRequest{DocumentIdentifier: docId, AccessType: p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION} + //err = DocumentAccessValidator(cd, req, account1) + //assert.NoError(t, err) + // + //account2, err := identity.CentIDFromString("0x012345678910") + //err = DocumentAccessValidator(cd, req, account2) + //assert.Error(t, err, "requester does not have access") } diff --git a/p2p/server_test.go b/p2p/server_test.go index d89003734..0b01a7cf1 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -23,7 +23,7 @@ import ( "github.com/centrifuge/go-centrifuge/p2p/receiver" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/testingutils/commons" + testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" ma "github.com/multiformats/go-multiaddr" @@ -40,7 +40,7 @@ func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetEthClient").Return(nil) ctx[ethereum.BootstrappedEthereumClient] = ethClient - ibootstappers := []bootstrap.TestBootstrapper{ + ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, @@ -52,10 +52,10 @@ func TestMain(m *testing.M) { } idService = &testingcommons.MockIDService{} ctx[identity.BootstrappedIDService] = idService - bootstrap.RunTestBootstrappers(ibootstappers, ctx) + bootstrap.RunTestBootstrappers(ibootstrappers, ctx) cfg = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) + bootstrap.RunTestTeardown(ibootstrappers) os.Exit(result) } diff --git a/testingutils/coredocument/coredocument.go b/testingutils/coredocument/coredocument.go deleted file mode 100644 index 66c8daaea..000000000 --- a/testingutils/coredocument/coredocument.go +++ /dev/null @@ -1,40 +0,0 @@ -// +build integration unit - -package testingcoredocument - -import ( - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/golang/protobuf/proto" - - "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/ptypes/any" -) - -func GenerateCoreDocumentWithCollaborators(collaborators [][]byte) *coredocumentpb.CoreDocument { - identifier := utils.RandomSlice(32) - invData := &invoicepb.InvoiceData{} - dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) - - serializedInv, _ := proto.Marshal(invData) - doc := &coredocumentpb.CoreDocument{ - Collaborators: collaborators, - DocumentIdentifier: identifier, - CurrentVersion: identifier, - NextVersion: utils.RandomSlice(32), - EmbeddedData: &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInv, - }, - EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), - } - cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) - doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) - return doc -} - -func GenerateCoreDocument() *coredocumentpb.CoreDocument { - return GenerateCoreDocumentWithCollaborators(nil) -} diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index b3ab23e67..6b77ad351 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -1,12 +1,14 @@ -// +build integration unit - package testingdocuments import ( "context" - + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/gogo/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/mock" ) @@ -58,13 +60,13 @@ func (m *MockService) Exists(ctx context.Context, documentID []byte) bool { type MockModel struct { documents.Model mock.Mock - CoreDocument *coredocumentpb.CoreDocument + CoreDocumentModel *documents.CoreDocumentModel } -func (m *MockModel) PackCoreDocument() (*coredocumentpb.CoreDocument, error) { +func (m *MockModel) PackCoreDocument() (*documents.CoreDocumentModel, error) { args := m.Called() - cd, _ := args.Get(0).(*coredocumentpb.CoreDocument) - return cd, args.Error(1) + dm, _ := args.Get(0).(*documents.CoreDocumentModel) + return dm, args.Error(1) } func (m *MockModel) JSON() ([]byte, error) { @@ -72,3 +74,34 @@ func (m *MockModel) JSON() ([]byte, error) { data, _ := args.Get(0).([]byte) return data, args.Error(1) } + +func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) *documents.CoreDocumentModel { + identifier := utils.RandomSlice(32) + invData := &invoicepb.InvoiceData{} + dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) + + serializedInv, _ := proto.Marshal(invData) + doc := &coredocumentpb.CoreDocument{ + Collaborators: collaborators, + DocumentIdentifier: identifier, + CurrentVersion: identifier, + NextVersion: utils.RandomSlice(32), + EmbeddedData: &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: serializedInv, + }, + EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), + } + cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) + doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) + dm := documents.NewCoreDocModel() + mockModel := MockModel { + CoreDocumentModel: dm, + } + dm.Document = doc + return mockModel.CoreDocumentModel +} + +func GenerateCoreDocumentModel() *documents.CoreDocumentModel { + return GenerateCoreDocumentModelWithCollaborators(nil) +} \ No newline at end of file From 89fbb1e0fe88ec625445e83d7cb0b09aebfd69ed Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 18 Feb 2019 13:29:58 +0100 Subject: [PATCH 191/220] Correct logs for transaction tasks (#753) --- transactions/base_task.go | 4 ++-- transactions/manager.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/transactions/base_task.go b/transactions/base_task.go index cb8334842..e60bdc746 100644 --- a/transactions/base_task.go +++ b/transactions/base_task.go @@ -49,10 +49,10 @@ func (b *BaseTask) UpdateTransaction(accountID identity.CentID, taskTypeName str // TODO this TaskStatus map update assumes that a single transaction has only one execution of a certain task type, which can be wrong, use the taskID or another unique identifier instead. if err != nil { - log.Infof("Transaction failed: %v\n", b.TxID.String()) + log.Errorf("Task %s failed for transaction: %v\n", taskTypeName, b.TxID.String()) return errors.AppendError(err, b.TxManager.UpdateTaskStatus(accountID, b.TxID, Failed, taskTypeName, err.Error())) } - log.Infof("Transaction successful:%v\n", b.TxID.String()) + log.Infof("Task %s successful for transaction:%v\n", taskTypeName, b.TxID.String()) return b.TxManager.UpdateTaskStatus(accountID, b.TxID, Success, taskTypeName, "") } diff --git a/transactions/manager.go b/transactions/manager.go index 2ecd95b11..d579121eb 100644 --- a/transactions/manager.go +++ b/transactions/manager.go @@ -19,7 +19,7 @@ type Config interface { // Manager is a manager for centrifuge transactions. type Manager interface { - // ExecuteWithinTX executes a transaction within a transaction + // ExecuteWithinTX executes the given unit of work within a transaction ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status Status, taskName, message string) error From 5d021e1020663bd2f9f9251d3bf754cc46a7ee96 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 19 Feb 2019 18:51:22 +0100 Subject: [PATCH 192/220] Converting TX API to use Hex strings (#754) * Converting TX API to use Hex strings * test * comment * fix tests --- api/server_test.go | 7 +- api/service.go | 3 +- bootstrap/bootstrappers/bootstrapper.go | 6 +- .../testingbootstrap/testing_bootstrap.go | 4 +- cmd/common_test.go | 17 ++-- contextutil/context.go | 21 ++-- documents/anchor_task.go | 12 +-- documents/anchor_task_test.go | 7 +- documents/bootstrapper.go | 3 +- documents/bootstrapper_test.go | 3 +- documents/invoice/handler_test.go | 19 ++-- documents/invoice/model_test.go | 5 +- documents/invoice/service.go | 23 +++-- documents/model.go | 3 +- documents/model_test.go | 34 +++---- documents/purchaseorder/handler_test.go | 21 ++-- documents/purchaseorder/model_test.go | 20 ++-- documents/purchaseorder/service.go | 23 +++-- documents/service.go | 14 +-- ethereum/geth_client.go | 11 +-- ethereum/geth_client_integration_test.go | 23 +++-- ethereum/transaction_status_task.go | 8 +- ...ransaction_status_task_integration_test.go | 5 +- ethereum/transaction_status_task_test.go | 7 +- identity/did/execute_integration_test.go | 5 +- identity/did/factory.go | 16 ++-- identity/did/factory_integration_test.go | 5 +- identity/did/service.go | 20 ++-- nft/bootstrapper_test.go | 7 +- nft/ethereum_payment_obligation.go | 7 +- nft/ethereum_payment_obligation_test.go | 8 +- p2p/messenger/messenger_test.go | 5 +- p2p/receiver/handler_test.go | 10 +- p2p/server_test.go | 5 +- testingutils/documents/documents.go | 5 +- testingutils/testingtx/mocktx.go | 13 ++- transactions/error.go | 15 +++ transactions/repository.go | 73 -------------- transactions/transaction.go | 95 +++++++++++++++++-- transactions/transaction_test.go | 20 ++++ transactions/{ => txv1}/base_task.go | 21 ++-- transactions/{ => txv1}/base_task_test.go | 22 ++--- transactions/{ => txv1}/bootstrapper.go | 21 +--- transactions/{ => txv1}/bootstrapper_test.go | 16 ++-- transactions/{ => txv1}/handler.go | 14 +-- transactions/{ => txv1}/handler_test.go | 18 ++-- transactions/{ => txv1}/manager.go | 85 +++++++---------- transactions/{ => txv1}/manager_test.go | 50 +++++----- transactions/txv1/repository.go | 59 ++++++++++++ transactions/{ => txv1}/repository_test.go | 31 +++--- transactions/{ => txv1}/test_bootstrapper.go | 2 +- 51 files changed, 488 insertions(+), 459 deletions(-) create mode 100644 transactions/error.go delete mode 100644 transactions/repository.go create mode 100644 transactions/transaction_test.go rename transactions/{ => txv1}/base_task.go (78%) rename transactions/{ => txv1}/base_task_test.go (71%) rename transactions/{ => txv1}/bootstrapper.go (51%) rename transactions/{ => txv1}/bootstrapper_test.go (83%) rename transactions/{ => txv1}/handler.go (81%) rename transactions/{ => txv1}/handler_test.go (80%) rename transactions/{ => txv1}/manager.go (56%) rename transactions/{ => txv1}/manager_test.go (63%) create mode 100644 transactions/txv1/repository.go rename transactions/{ => txv1}/repository_test.go (79%) rename transactions/{ => txv1}/test_bootstrapper.go (89%) diff --git a/api/server_test.go b/api/server_test.go index 481ad4675..f246de08d 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,8 +9,6 @@ import ( "sync" "testing" - "github.com/centrifuge/go-centrifuge/p2p" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -23,10 +21,11 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/stretchr/testify/assert" "google.golang.org/grpc" "google.golang.org/grpc/metadata" @@ -44,7 +43,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ðid.Bootstrapper{}, &configstore.Bootstrapper{}, diff --git a/api/service.go b/api/service.go index 88f3a7449..cd35b1027 100644 --- a/api/service.go +++ b/api/service.go @@ -19,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/grpc-ecosystem/grpc-gateway/runtime" "golang.org/x/net/context" "google.golang.org/grpc" @@ -109,7 +110,7 @@ func registerServices(ctx context.Context, cfg Config, grpcServer *grpc.Server, // transactions txSrv := nodeObjReg[transactions.BootstrappedService].(transactions.Manager) - h := transactions.GRPCHandler(txSrv, configService) + h := txv1.GRPCHandler(txSrv, configService) transactionspb.RegisterTransactionServiceServer(grpcServer, h) if err := transactionspb.RegisterTransactionServiceHandlerFromEndpoint(ctx, gwmux, addr, dopts); err != nil { return err diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index edd4d658d..4f6cab3af 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -17,7 +17,7 @@ import ( "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/version" log2 "github.com/ipfs/go-log" ) @@ -35,7 +35,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, ðid.Bootstrapper{}, @@ -57,7 +57,7 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { &version.Bootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, &did.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 8b77257bb..88acb3657 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -18,7 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" logging "github.com/ipfs/go-log" ) @@ -28,7 +28,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, ðid.Bootstrapper{}, diff --git a/cmd/common_test.go b/cmd/common_test.go index 8ebfba326..221100b15 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -10,23 +10,22 @@ import ( "path" "testing" - "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/identity/did" "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" ) @@ -38,7 +37,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, ðid.Bootstrapper{}, diff --git a/contextutil/context.go b/contextutil/context.go index 5968df10e..f7afca823 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -4,18 +4,13 @@ import ( "context" "fmt" - "github.com/satori/go.uuid" - - "github.com/ethereum/go-ethereum/common/hexutil" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" - - "github.com/centrifuge/go-centrifuge/identity" - + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/ethereum/go-ethereum/common/hexutil" ) type contextKey string @@ -35,7 +30,7 @@ func New(ctx context.Context, cfg config.Account) (context.Context, error) { } // WithTX returns a context with TX ID -func WithTX(ctx context.Context, txID uuid.UUID) context.Context { +func WithTX(ctx context.Context, txID transactions.TxID) context.Context { return context.WithValue(ctx, tx, txID) } @@ -49,10 +44,10 @@ func Self(ctx context.Context) (*identity.IDConfig, error) { } // TX returns current txID -func TX(ctx context.Context) uuid.UUID { - tid, ok := ctx.Value(tx).(uuid.UUID) +func TX(ctx context.Context) transactions.TxID { + tid, ok := ctx.Value(tx).(transactions.TxID) if !ok { - return uuid.Nil + return transactions.NilTxID() } return tid } diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 1985b9901..f8bc5c381 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -12,10 +12,10 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common/hexutil" logging "github.com/ipfs/go-log" - "github.com/satori/go.uuid" ) const ( @@ -31,7 +31,7 @@ const ( var log = logging.Logger("anchor_task") type documentAnchorTask struct { - transactions.BaseTask + txv1.BaseTask id []byte accountID identity.CentID @@ -80,7 +80,7 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { // Copy returns a new task with state. func (d *documentAnchorTask) Copy() (gocelery.CeleryTask, error) { return &documentAnchorTask{ - BaseTask: transactions.BaseTask{TxManager: d.TxManager}, + BaseTask: txv1.BaseTask{TxManager: d.TxManager}, config: d.config, processor: d.processor, modelGetFunc: d.modelGetFunc, @@ -120,7 +120,7 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { } // InitDocumentAnchorTask enqueues a new document anchor task for a given combination of accountID/modelID/txID. -func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, accountID identity.CentID, modelID []byte, txID uuid.UUID) (queue.TaskResult, error) { +func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, accountID identity.CentID, modelID []byte, txID transactions.TxID) (queue.TaskResult, error) { params := map[string]interface{}{ transactions.TxIDParam: txID.String(), DocumentIDParam: hexutil.Encode(modelID), @@ -141,8 +141,8 @@ func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, acc } // CreateAnchorTransaction creates a transaction for anchoring a document using transaction manager -func CreateAnchorTransaction(txMan transactions.Manager, tq queue.TaskQueuer, self identity.CentID, txID uuid.UUID, documentID []byte) (uuid.UUID, chan bool, error) { - txID, done, err := txMan.ExecuteWithinTX(context.Background(), self, txID, "anchor document", func(accountID identity.CentID, TID uuid.UUID, txMan transactions.Manager, errChan chan<- error) { +func CreateAnchorTransaction(txMan transactions.Manager, tq queue.TaskQueuer, self identity.CentID, txID transactions.TxID, documentID []byte) (transactions.TxID, chan bool, error) { + txID, done, err := txMan.ExecuteWithinTX(context.Background(), self, txID, "anchor document", func(accountID identity.CentID, TID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { tr, err := InitDocumentAnchorTask(txMan, tq, accountID, documentID, TID) if err != nil { errChan <- err diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index 509a976bc..ccfc00591 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -34,7 +33,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { // missing model ID { kwargs: map[string]interface{}{ - transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + transactions.TxIDParam: transactions.NewTxID().String(), }, err: "missing model ID", }, @@ -42,7 +41,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { // missing accountID { kwargs: map[string]interface{}{ - transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + transactions.TxIDParam: transactions.NewTxID().String(), DocumentIDParam: hexutil.Encode(utils.RandomSlice(32)), }, @@ -53,7 +52,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { { name: "success", kwargs: map[string]interface{}{ - transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + transactions.TxIDParam: transactions.NewTxID().String(), DocumentIDParam: hexutil.Encode(utils.RandomSlice(32)), AccountIDParam: identity.RandomCentID().String(), }, diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index a55499cbe..73867b25c 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -9,6 +9,7 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" ) const ( @@ -93,7 +94,7 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { txMan := ctx[transactions.BootstrappedService].(transactions.Manager) anchorTask := &documentAnchorTask{ - BaseTask: transactions.BaseTask{ + BaseTask: txv1.BaseTask{ TxManager: txMan, }, config: cfgService, diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 06b35a8a6..96fdf2c6e 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -14,6 +14,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/stretchr/testify/assert" ) @@ -25,7 +26,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { repo := leveldb.NewLevelDBRepository(db) ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo - ctx[transactions.BootstrappedService] = transactions.NewManager(&testingconfig.MockConfig{}, transactions.NewRepository(repo)) + ctx[transactions.BootstrappedService] = txv1.NewManager(&testingconfig.MockConfig{}, txv1.NewRepository(repo)) ctx[identity.BootstrappedIDService] = new(testingcommons.MockIDService) ctx[anchors.BootstrappedAnchorRepo] = new(testinganchors.MockAnchorRepo) err = Bootstrapper{}.Bootstrap(ctx) diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index 8b22fa2cd..a9351d5f0 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -15,7 +17,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -31,7 +32,7 @@ func (m *mockService) DeriveFromCreatePayload(ctx context.Context, payload *clie return model, args.Error(1) } -func (m *mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (m *mockService) Create(ctx context.Context, model documents.Model) (documents.Model, transactions.TxID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) return model, contextutil.TX(ctx), nil, args.Error(2) @@ -61,7 +62,7 @@ func (m *mockService) DeriveInvoiceResponse(doc documents.Model) (*clientinvoice return data, args.Error(1) } -func (m *mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (m *mockService) Update(ctx context.Context, model documents.Model) (documents.Model, transactions.TxID, chan bool, error) { args := m.Called(ctx, model) doc1, _ := args.Get(0).(documents.Model) return doc1, contextutil.TX(ctx), nil, args.Error(2) @@ -92,7 +93,7 @@ func TestGRPCHandler_Create_create_fail(t *testing.T) { h := getHandler() srv := h.service.(*mockService) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(new(Invoice), nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(nil, transactions.NilTxID().String(), errors.New("create failed")).Once() payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}} _, err := h.Create(testingconfig.HandlerContext(configService), payload) srv.AssertExpectations(t) @@ -123,7 +124,7 @@ func TestGRPCHandler_Create_DeriveInvoiceResponse_fail(t *testing.T) { srv := h.service.(*mockService) model := new(Invoice) srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() - srv.On("Create", mock.Anything, mock.Anything).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Create", mock.Anything, mock.Anything).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DeriveInvoiceResponse", mock.Anything).Return(nil, errors.New("derive response failed")) payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{Currency: "EUR"}} _, err := h.Create(testingconfig.HandlerContext(configService), payload) @@ -136,7 +137,7 @@ func TestGrpcHandler_Create(t *testing.T) { h := getHandler() srv := h.service.(*mockService) model := new(Invoice) - txID := uuid.Must(uuid.NewV4()) + txID := transactions.NewTxID() payload := &clientinvoicepb.InvoiceCreatePayload{Data: &clientinvoicepb.InvoiceData{GrossAmount: 300}, Collaborators: []string{"0x010203040506"}} response := &clientinvoicepb.InvoiceResponse{Header: &clientinvoicepb.ResponseHeader{}} srv.On("DeriveFromCreatePayload", mock.Anything, mock.Anything).Return(model, nil).Once() @@ -244,7 +245,7 @@ func TestGrpcHandler_Update_update_fail(t *testing.T) { ctx := testingconfig.HandlerContext(configService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("update error")).Once() + srv.On("Update", mock.Anything, model).Return(nil, transactions.NilTxID().String(), errors.New("update error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) assert.Error(t, err) @@ -259,7 +260,7 @@ func TestGrpcHandler_Update_derive_response_fail(t *testing.T) { ctx := testingconfig.HandlerContext(configService) payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() - srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Update", mock.Anything, model).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DeriveInvoiceResponse", model).Return(nil, errors.New("derive response error")).Once() res, err := h.Update(ctx, payload) srv.AssertExpectations(t) @@ -273,7 +274,7 @@ func TestGrpcHandler_Update(t *testing.T) { srv := h.service.(*mockService) model := &mockModel{} ctx := testingconfig.HandlerContext(configService) - txID := uuid.Must(uuid.NewV4()) + txID := transactions.NewTxID() payload := &clientinvoicepb.InvoiceUpdatePayload{Identifier: "0x010201"} resp := &clientinvoicepb.InvoiceResponse{Header: new(clientinvoicepb.ResponseHeader)} srv.On("DeriveFromUpdatePayload", mock.Anything, payload).Return(model, nil).Once() diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index e24bb6da5..ce6aef0f4 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -24,7 +24,7 @@ import ( clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" @@ -32,7 +32,6 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -48,7 +47,7 @@ func TestMain(m *testing.M) { txMan := &testingtx.MockTxManager{} ctx[transactions.BootstrappedService] = txMan done := make(chan bool) - txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, done, nil) + txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(transactions.NilTxID(), done, nil) ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 36c64e8c8..6534f7223 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" ) // Service defines specific functions for invoice @@ -116,55 +115,55 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // Create takes and invoice model and does required validation checks, tries to persist to DB -func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } inv, err = s.validateAndPersist(ctx, nil, inv, CreateValidator()) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } dm, err := inv.PackCoreDocument() if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } txID := contextutil.TX(ctx) txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } return inv, txID, done, nil } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } dm, err := inv.PackCoreDocument() if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } inv, err = s.validateAndPersist(ctx, old, inv, UpdateValidator()) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } txID := contextutil.TX(ctx) txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } return inv, txID, done, nil } diff --git a/documents/model.go b/documents/model.go index 114968d51..af33e72dc 100644 --- a/documents/model.go +++ b/documents/model.go @@ -6,9 +6,8 @@ import ( "fmt" "strings" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" diff --git a/documents/model_test.go b/documents/model_test.go index 533a42656..96b0de512 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -7,33 +7,27 @@ import ( "os" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/golang/protobuf/ptypes/any" - - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/centrifuge/go-centrifuge/anchors" - - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var ctx map[string]interface{} @@ -50,7 +44,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, &anchors.Bootstrapper{}, &Bootstrapper{}, diff --git a/documents/purchaseorder/handler_test.go b/documents/purchaseorder/handler_test.go index a0faef797..9e6e0e416 100644 --- a/documents/purchaseorder/handler_test.go +++ b/documents/purchaseorder/handler_test.go @@ -6,16 +6,15 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -25,13 +24,13 @@ type mockService struct { mock.Mock } -func (m mockService) Create(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (m mockService) Create(ctx context.Context, model documents.Model) (documents.Model, transactions.TxID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) return model, contextutil.TX(ctx), nil, args.Error(2) } -func (m mockService) Update(ctx context.Context, model documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (m mockService) Update(ctx context.Context, model documents.Model) (documents.Model, transactions.TxID, chan bool, error) { args := m.Called(ctx, model) model, _ = args.Get(0).(documents.Model) return model, contextutil.TX(ctx), nil, args.Error(2) @@ -91,7 +90,7 @@ func TestGRPCHandler_Create(t *testing.T) { // create fails srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Create", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("create failed")).Once() + srv.On("Create", mock.Anything, model).Return(nil, transactions.NilTxID().String(), errors.New("create failed")).Once() h.service = srv resp, err = h.Create(ctx, req) srv.AssertExpectations(t) @@ -101,7 +100,7 @@ func TestGRPCHandler_Create(t *testing.T) { // derive response fails srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Create", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Create", mock.Anything, model).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -113,7 +112,7 @@ func TestGRPCHandler_Create(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} srv.On("DeriveFromCreatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Create", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Create", mock.Anything, model).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Create(ctx, req) @@ -145,7 +144,7 @@ func TestGrpcHandler_Update(t *testing.T) { // create fails srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Update", mock.Anything, model).Return(nil, uuid.Nil.String(), errors.New("update failed")).Once() + srv.On("Update", mock.Anything, model).Return(nil, transactions.NilTxID().String(), errors.New("update failed")).Once() h.service = srv resp, err = h.Update(ctx, req) srv.AssertExpectations(t) @@ -155,7 +154,7 @@ func TestGrpcHandler_Update(t *testing.T) { // derive response fails srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Update", mock.Anything, model).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(nil, errors.New("derive response fails")).Once() h.service = srv resp, err = h.Update(ctx, req) @@ -167,7 +166,7 @@ func TestGrpcHandler_Update(t *testing.T) { // success eresp := &clientpopb.PurchaseOrderResponse{Header: new(clientpopb.ResponseHeader)} srv.On("DeriveFromUpdatePayload", mock.Anything, req).Return(model, nil).Once() - srv.On("Update", mock.Anything, model).Return(model, uuid.Nil.String(), nil).Once() + srv.On("Update", mock.Anything, model).Return(model, transactions.NilTxID().String(), nil).Once() srv.On("DerivePurchaseOrderResponse", model).Return(eresp, nil).Once() h.service = srv resp, err = h.Update(ctx, req) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index f780ecd27..15fcd4180 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -8,38 +8,32 @@ import ( "reflect" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/testingtx" - "github.com/satori/go.uuid" - "github.com/stretchr/testify/mock" - - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/identity/ethid" - - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var ctx = map[string]interface{}{} @@ -53,7 +47,7 @@ func TestMain(m *testing.M) { txMan := &testingtx.MockTxManager{} ctx[transactions.BootstrappedService] = txMan done := make(chan bool) - txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, done, nil) + txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(transactions.NilTxID(), done, nil) ibootstappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index c7f9a0733..4efaa9f9f 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/satori/go.uuid" ) // Service defines specific functions for purchase order @@ -96,56 +95,56 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // Create validates, persists, and anchors a purchase order -func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } po, err = s.validateAndPersist(ctx, nil, po, CreateValidator()) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } dm, err := po.PackCoreDocument() if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } txID := contextutil.TX(ctx) txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { - return nil, uuid.Nil, nil, nil + return nil, transactions.NilTxID(), nil, nil } return po, txID, done, nil } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, uuid.UUID, chan bool, error) { +func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } dm, err := po.PackCoreDocument() if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) } old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) if err != nil { - return nil, uuid.Nil, nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) + return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } po, err = s.validateAndPersist(ctx, old, po, UpdateValidator()) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } txID := contextutil.TX(ctx) txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) if err != nil { - return nil, uuid.Nil, nil, err + return nil, transactions.NilTxID(), nil, err } return po, txID, done, nil } diff --git a/documents/service.go b/documents/service.go index 16103fcc2..4df28202a 100644 --- a/documents/service.go +++ b/documents/service.go @@ -5,7 +5,7 @@ import ( "context" "time" - "github.com/satori/go.uuid" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" @@ -58,10 +58,10 @@ type Service interface { ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error // Create validates and persists Model and returns a Updated model - Create(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) + Create(ctx context.Context, model Model) (Model, transactions.TxID, chan bool, error) // Update validates and updates the model and return the updated model - Update(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) + Update(ctx context.Context, model Model) (Model, transactions.TxID, chan bool, error) } // service implements Service @@ -306,19 +306,19 @@ func (s service) DeriveFromCoreDocumentModel(dm *CoreDocumentModel) (Model, erro return srv.DeriveFromCoreDocumentModel(dm) } -func (s service) Create(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) { +func (s service) Create(ctx context.Context, model Model) (Model, transactions.TxID, chan bool, error) { srv, err := s.getService(model) if err != nil { - return nil, uuid.Nil, nil, errors.New("failed to get service: %v", err) + return nil, transactions.NilTxID(), nil, errors.New("failed to get service: %v", err) } return srv.Create(ctx, model) } -func (s service) Update(ctx context.Context, model Model) (Model, uuid.UUID, chan bool, error) { +func (s service) Update(ctx context.Context, model Model) (Model, transactions.TxID, chan bool, error) { srv, err := s.getService(model) if err != nil { - return nil, uuid.Nil, nil, errors.New("failed to get service: %v", err) + return nil, transactions.NilTxID(), nil, errors.New("failed to get service: %v", err) } return srv.Update(ctx, model) diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 34ec146b3..7ef4f6079 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -11,20 +11,17 @@ import ( "sync" "time" - "github.com/centrifuge/go-centrifuge/queue" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" logging "github.com/ipfs/go-log" - "github.com/satori/go.uuid" ) const ( @@ -203,7 +200,7 @@ func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, err // QueueEthTXStatusTask starts a new queuing transaction check task. func QueueEthTXStatusTask( accountID identity.CentID, - txID uuid.UUID, + txID transactions.TxID, txHash common.Hash, queuer queue.TaskQueuer) (res queue.TaskResult, err error) { return queuer.EnqueueJobWithMaxTries(EthTXStatusTaskName, map[string]interface{}{ diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index 973cfd28f..ede20a595 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -7,23 +7,22 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/mock" - - "github.com/centrifuge/go-centrifuge/identity/ethid" - "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var cfg config.Configuration @@ -56,7 +55,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, ðid.Bootstrapper{}, diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 74799b5ef..81d8f9873 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -39,7 +41,7 @@ type WatchTransaction struct { // TransactionStatusTask is struct for the task to check an Ethereum transaction type TransactionStatusTask struct { - transactions.BaseTask + txv1.BaseTask timeout time.Duration //state @@ -63,7 +65,7 @@ func NewTransactionStatusTask( ) *TransactionStatusTask { return &TransactionStatusTask{ timeout: timeout, - BaseTask: transactions.BaseTask{TxManager: txService}, + BaseTask: txv1.BaseTask{TxManager: txService}, ethContextInitializer: ethContextInitializer, transactionByHash: transactionByHash, transactionReceipt: transactionReceipt, @@ -84,7 +86,7 @@ func (tst *TransactionStatusTask) Copy() (gocelery.CeleryTask, error) { transactionByHash: tst.transactionByHash, transactionReceipt: tst.transactionReceipt, ethContextInitializer: tst.ethContextInitializer, - BaseTask: transactions.BaseTask{TxManager: tst.TxManager}, + BaseTask: txv1.BaseTask{TxManager: tst.TxManager}, }, nil } diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go index f0c65711b..3b636a3c9 100644 --- a/ethereum/transaction_status_task_integration_test.go +++ b/ethereum/transaction_status_task_integration_test.go @@ -11,16 +11,15 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) -func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, uuid.UUID, chan bool) { +func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, transactions.TxID, chan bool) { queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) cid := identity.RandomCentID() - tx, done, err := txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Check TX status", func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errChan chan<- error) { + tx, done, err := txManager.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "Check TX status", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { result, err := queueSrv.EnqueueJob(ethereum.EthTXStatusTaskName, map[string]interface{}{ transactions.TxIDParam: txID.String(), ethereum.TransactionAccountParam: cid.String(), diff --git a/ethereum/transaction_status_task_test.go b/ethereum/transaction_status_task_test.go index 06e4fdb99..6cd75df20 100644 --- a/ethereum/transaction_status_task_test.go +++ b/ethereum/transaction_status_task_test.go @@ -8,14 +8,13 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { task := TransactionStatusTask{} txHash := "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515" - txID := uuid.Must(uuid.NewV4()).String() + txID := transactions.NewTxID().String() cid := identity.RandomCentID() kwargs := map[string]interface{}{ @@ -39,7 +38,7 @@ func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { task := TransactionStatusTask{} tests := []map[string]interface{}{ { - transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + transactions.TxIDParam: transactions.NewTxID().String(), TransactionAccountParam: identity.RandomCentID().String(), }, { @@ -47,7 +46,7 @@ func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { TransactionTxHashParam: "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515", }, { - transactions.TxIDParam: uuid.Must(uuid.NewV4()).String(), + transactions.TxIDParam: transactions.NewTxID().String(), TransactionTxHashParam: "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515", }, { diff --git a/identity/did/execute_integration_test.go b/identity/did/execute_integration_test.go index 3b7297755..37b830ab7 100644 --- a/identity/did/execute_integration_test.go +++ b/identity/did/execute_integration_test.go @@ -27,7 +27,6 @@ import ( "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -133,8 +132,8 @@ func commitAnchorWithoutExecute(t *testing.T, anchorContract *anchors.AnchorCont txManager := ctx[transactions.BootstrappedService].(transactions.Manager) // TODO: did can be passed instead of randomCentID after CentID is DID - _, done, err := txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX add execute", - func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { + _, done, err := txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX add execute", + func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := client.SubmitTransactionWithRetries(anchorContract.Commit, opts, anchorId.BigInt(), rootHash, proofs) if err != nil { errOut <- err diff --git a/identity/did/factory.go b/identity/did/factory.go index bcde0c665..d40146fad 100644 --- a/identity/did/factory.go +++ b/identity/did/factory.go @@ -5,17 +5,13 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + id "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/satori/go.uuid" - - "github.com/centrifuge/go-centrifuge/ethereum" - id "github.com/centrifuge/go-centrifuge/identity" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" logging "github.com/ipfs/go-log" @@ -53,8 +49,8 @@ func CalculateCreatedAddress(address common.Address, nonce uint64) common.Addres return crypto.CreateAddress(address, nonce) } -func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) if err != nil { errOut <- err @@ -126,7 +122,7 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { } // TODO refactor randomCentID - txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for create identity status", s.createIdentityTX(opts)) + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for create identity status", s.createIdentityTX(opts)) if err != nil { return nil, err } diff --git a/identity/did/factory_integration_test.go b/identity/did/factory_integration_test.go index 3a425b945..06367ccbc 100644 --- a/identity/did/factory_integration_test.go +++ b/identity/did/factory_integration_test.go @@ -7,6 +7,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" @@ -16,7 +18,6 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -28,7 +29,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, ðid.Bootstrapper{}, diff --git a/identity/did/service.go b/identity/did/service.go index b8daa0ac1..29858f4c8 100644 --- a/identity/did/service.go +++ b/identity/did/service.go @@ -13,14 +13,12 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/satori/go.uuid" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -195,7 +193,7 @@ func (i service) AddKey(ctx context.Context, key Key) error { // TODO: did can be passed instead of randomCentID after CentID is DID log.Info("Add key to identity contract %s", did.ToAddress().String()) - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add key", + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for add key", i.ethereumTX(opts, contract.AddKey, key.GetKey(), key.GetPurpose(), key.GetType())) if err != nil { return err @@ -224,7 +222,7 @@ func (i service) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes } // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for add multi purpose key", + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for add multi purpose key", i.ethereumTX(opts, contract.AddMultiPurposeKey, key, purposes, keyType)) if err != nil { return err @@ -252,7 +250,7 @@ func (i service) RevokeKey(ctx context.Context, key [32]byte) error { } // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for revoke key", + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for revoke key", i.ethereumTX(opts, contract.RevokeKey, key)) if err != nil { return err @@ -268,8 +266,8 @@ func (i service) RevokeKey(ctx context.Context, key [32]byte) error { } // ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result -func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID id.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := i.client.SubmitTransactionWithRetries(contractMethod, opts, params...) if err != nil { errOut <- err @@ -335,7 +333,7 @@ func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) value := big.NewInt(0) // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), uuid.Nil, "Check TX for execute", i.ethereumTX(opts, contract.Execute, to, value, data)) + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for execute", i.ethereumTX(opts, contract.Execute, to, value, data)) if err != nil { return err } diff --git a/nft/bootstrapper_test.go b/nft/bootstrapper_test.go index 28b2e9b34..bb8c3b495 100644 --- a/nft/bootstrapper_test.go +++ b/nft/bootstrapper_test.go @@ -6,12 +6,11 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/stretchr/testify/assert" ) @@ -22,7 +21,7 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) result := m.Run() diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index fdcefdd03..5800bc11c 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" logging "github.com/ipfs/go-log" - "github.com/satori/go.uuid" ) var log = logging.Logger("nft") @@ -155,7 +154,7 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by // Mint NFT within transaction // We use context.Background() for now so that the transaction is only limited by ethereum timeouts - txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "Minting NFT", + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "Minting NFT", s.minter(ctx, tokenID, model, registry, depositAddress, proofFields)) if err != nil { return nil, nil, err @@ -174,8 +173,8 @@ func (s *ethereumPaymentObligation) isNFTMinted(registry common.Address, tokenID return err == nil } -func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, registry common.Address, depositAddress string, proofFields []string) func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, errOut chan<- error) { +func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, registry common.Address, depositAddress string, proofFields []string) func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { tc, err := contextutil.Account(ctx) if err != nil { errOut <- err diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 244f7b106..2c92f0154 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,8 +7,7 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/testingutils/testingtx" - "github.com/satori/go.uuid" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" @@ -19,9 +18,10 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -183,7 +183,7 @@ func TestPaymentObligationService(t *testing.T) { queueSrv := new(testingutils.MockQueue) txMan := &testingtx.MockTxManager{} txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(uuid.Nil, make(chan bool), nil) + mock.Anything, mock.Anything).Return(transactions.NilTxID(), make(chan bool), nil) return docServiceMock, paymentObligationMock, idServiceMock, ethClientMock, configMock, queueSrv, txMan }, &nftpb.NFTMintRequest{Identifier: "0x1212", ProofFields: []string{"collaborators[0]"}, DepositAddress: "0xf72855759a39fb75fc7341139f5d7a3974d4da08"}, diff --git a/p2p/messenger/messenger_test.go b/p2p/messenger/messenger_test.go index d9aafabb1..6866e2146 100644 --- a/p2p/messenger/messenger_test.go +++ b/p2p/messenger/messenger_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -27,7 +29,6 @@ import ( "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -82,7 +83,7 @@ func TestMain(m *testing.M) { &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, } diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 9b2f259ed..34d4ed2b2 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -8,17 +8,15 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/anchors" - - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" @@ -26,7 +24,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage/leveldb" testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/version" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" @@ -56,7 +54,7 @@ func TestMain(m *testing.M) { &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, } diff --git a/p2p/server_test.go b/p2p/server_test.go index 0b01a7cf1..3b2871d50 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -24,7 +26,6 @@ import ( "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" @@ -46,7 +47,7 @@ func TestMain(m *testing.M) { &leveldb.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, - transactions.Bootstrapper{}, + txv1.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 6b77ad351..91528e99d 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -2,6 +2,7 @@ package testingdocuments import ( "context" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" @@ -95,7 +96,7 @@ func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) *documen cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) dm := documents.NewCoreDocModel() - mockModel := MockModel { + mockModel := MockModel{ CoreDocumentModel: dm, } dm.Document = doc @@ -104,4 +105,4 @@ func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) *documen func GenerateCoreDocumentModel() *documents.CoreDocumentModel { return GenerateCoreDocumentModelWithCollaborators(nil) -} \ No newline at end of file +} diff --git a/testingutils/testingtx/mocktx.go b/testingutils/testingtx/mocktx.go index c29b6be08..1ead8ddbe 100644 --- a/testingutils/testingtx/mocktx.go +++ b/testingutils/testingtx/mocktx.go @@ -9,7 +9,6 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/centrifuge/go-centrifuge/transactions" - "github.com/satori/go.uuid" "github.com/stretchr/testify/mock" ) @@ -21,23 +20,23 @@ func (m MockTxManager) GetDefaultTaskTimeout() time.Duration { panic("implement me") } -func (m MockTxManager) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status transactions.Status, taskName, message string) error { +func (m MockTxManager) UpdateTaskStatus(accountID identity.CentID, id transactions.TxID, status transactions.Status, taskName, message string) error { panic("implement me") } -func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan transactions.Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { +func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID transactions.TxID, desc string, work func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { args := m.Called(ctx, accountID, existingTxID, desc, work) - return args.Get(0).(uuid.UUID), args.Get(1).(chan bool), args.Error(2) + return args.Get(0).(transactions.TxID), args.Get(1).(chan bool), args.Error(2) } -func (MockTxManager) GetTransaction(accountID identity.CentID, id uuid.UUID) (*transactions.Transaction, error) { +func (MockTxManager) GetTransaction(accountID identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { panic("implement me") } -func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { +func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { panic("implement me") } -func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { +func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID transactions.TxID) error { panic("implement me") } diff --git a/transactions/error.go b/transactions/error.go new file mode 100644 index 000000000..0222c4306 --- /dev/null +++ b/transactions/error.go @@ -0,0 +1,15 @@ +package transactions + +import "github.com/centrifuge/go-centrifuge/errors" + +const ( + + // ErrTransactionBootstrap error when bootstrap fails. + ErrTransactionBootstrap = errors.Error("failed to bootstrap transactions") + + // ErrTransactionMissing error when transaction doesn't exist in Repository. + ErrTransactionMissing = errors.Error("transaction doesn't exist") + + // ErrKeyConstructionFailed error when the key construction failed. + ErrKeyConstructionFailed = errors.Error("failed to construct transaction key") +) diff --git a/transactions/repository.go b/transactions/repository.go deleted file mode 100644 index 5e4422aa4..000000000 --- a/transactions/repository.go +++ /dev/null @@ -1,73 +0,0 @@ -package transactions - -import ( - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/storage" - "github.com/satori/go.uuid" -) - -const ( - // ErrTransactionMissing error when transaction doesn't exist in Repository. - ErrTransactionMissing = errors.Error("transaction doesn't exist") - - // ErrKeyConstructionFailed error when the key construction failed. - ErrKeyConstructionFailed = errors.Error("failed to construct transaction key") -) - -// Repository can be implemented by a type that handles storage for transactions. -type Repository interface { - Get(cid identity.CentID, id uuid.UUID) (*Transaction, error) - Save(transaction *Transaction) error -} - -// txRepository implements Repository. -type txRepository struct { - repo storage.Repository -} - -// NewRepository registers the the transaction model and returns the an implementation -// of the Repository. -func NewRepository(repo storage.Repository) Repository { - repo.Register(&Transaction{}) - return &txRepository{repo: repo} -} - -// getKey appends identity with id. -// With identity coming at first, we can even fetch transactions belonging to specific identity through prefix. -func getKey(cid identity.CentID, id uuid.UUID) ([]byte, error) { - if uuid.Equal(uuid.Nil, id) { - return nil, errors.New("transaction ID is not valid") - } - - return append(cid[:], id.Bytes()...), nil -} - -// Get returns the transaction associated with identity and id. -func (r *txRepository) Get(cid identity.CentID, id uuid.UUID) (*Transaction, error) { - key, err := getKey(cid, id) - if err != nil { - return nil, errors.NewTypedError(ErrKeyConstructionFailed, err) - } - - m, err := r.repo.Get(key) - if err != nil { - return nil, errors.NewTypedError(ErrTransactionMissing, err) - } - - return m.(*Transaction), nil -} - -// Save saves the transaction to the repository. -func (r *txRepository) Save(tx *Transaction) error { - key, err := getKey(tx.CID, tx.ID) - if err != nil { - return errors.NewTypedError(ErrKeyConstructionFailed, err) - } - - if r.repo.Exists(key) { - return r.repo.Update(key, tx) - } - - return r.repo.Create(key, tx) -} diff --git a/transactions/transaction.go b/transactions/transaction.go index e0037478e..b7a4f5b50 100644 --- a/transactions/transaction.go +++ b/transactions/transaction.go @@ -1,23 +1,38 @@ package transactions import ( + "context" "encoding/json" "reflect" "time" "github.com/centrifuge/go-centrifuge/identity" - + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/satori/go.uuid" ) // Status represents the status of the transaction type Status string -// Status constants const ( + // Status constants + + // Success is the success status for a transaction or a task Success Status = "success" - Failed Status = "failed" + // Failed is the failed status for a transaction or a task + Failed Status = "failed" + // Pending is the pending status for a transaction or a task Pending Status = "pending" + + // TxIDParam maps transaction ID in the kwargs. + TxIDParam = "transactionID" + + // BootstrappedRepo is the key mapped to transactions.Repository. + BootstrappedRepo = "BootstrappedRepo" + + // BootstrappedService is the key to mapped transactions.Manager + BootstrappedService = "BootstrappedService" ) // Log represents a single task in a transaction. @@ -36,9 +51,53 @@ func NewLog(action, message string) Log { } } +// TxID is a centrifuge transaction ID. Internally represented by a UUID. Externally visible as a byte slice or a hex encoded string. +type TxID uuid.UUID + +// NewTxID creates a new TxID +func NewTxID() TxID { + u := uuid.Must(uuid.NewV4()) + return TxID(u) +} + +// FromString tries to convert the given hex string txID into a type TxID +func FromString(tIDHex string) (TxID, error) { + tidBytes, err := hexutil.Decode(tIDHex) + if err != nil { + return NilTxID(), err + } + u, err := uuid.FromBytes(tidBytes) + if err != nil { + return NilTxID(), err + } + return TxID(u), nil +} + +// NilTxID returns a nil TxID +func NilTxID() TxID { + return TxID(uuid.Nil) +} + +// String marshals a TxID to its hex string form +func (t TxID) String() string { + return hexutil.Encode(t[:]) +} + +// Bytes returns the byte slice representation of the TxID +func (t TxID) Bytes() []byte { + return uuid.UUID(t).Bytes() +} + +// TxIDEqual checks if given two TxIDs are equal +func TxIDEqual(t1 TxID, t2 TxID) bool { + u1 := uuid.UUID(t1) + u2 := uuid.UUID(t2) + return uuid.Equal(u1, u2) +} + // Transaction contains details of transaction. type Transaction struct { - ID uuid.UUID + ID TxID CID identity.CentID Description string @@ -68,10 +127,10 @@ func (t *Transaction) Type() reflect.Type { return reflect.TypeOf(t) } -// newTransaction returns a new transaction with a pending state -func newTransaction(identity identity.CentID, description string) *Transaction { +// NewTransaction returns a new transaction with a pending state +func NewTransaction(identity identity.CentID, description string) *Transaction { return &Transaction{ - ID: uuid.Must(uuid.NewV4()), + ID: NewTxID(), CID: identity, Description: description, Status: Pending, @@ -79,3 +138,25 @@ func newTransaction(identity identity.CentID, description string) *Transaction { CreatedAt: time.Now().UTC(), } } + +// Config is the config interface for transactions package +type Config interface { + GetEthereumContextWaitTimeout() time.Duration +} + +// Manager is a manager for centrifuge transactions. +type Manager interface { + // ExecuteWithinTX executes the given unit of work within a transaction + ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID TxID, desc string, work func(accountID identity.CentID, txID TxID, txMan Manager, err chan<- error)) (txID TxID, done chan bool, err error) + GetTransaction(accountID identity.CentID, id TxID) (*Transaction, error) + UpdateTaskStatus(accountID identity.CentID, id TxID, status Status, taskName, message string) error + GetTransactionStatus(accountID identity.CentID, id TxID) (*transactionspb.TransactionStatusResponse, error) + WaitForTransaction(accountID identity.CentID, txID TxID) error + GetDefaultTaskTimeout() time.Duration +} + +// Repository can be implemented by a type that handles storage for transactions. +type Repository interface { + Get(cid identity.CentID, id TxID) (*Transaction, error) + Save(transaction *Transaction) error +} diff --git a/transactions/transaction_test.go b/transactions/transaction_test.go new file mode 100644 index 000000000..1c9051231 --- /dev/null +++ b/transactions/transaction_test.go @@ -0,0 +1,20 @@ +package transactions + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" +) + +func TestTxID_String(t *testing.T) { + tID := NewTxID() + tidStr := tID.String() + bs, err := hexutil.Decode(tidStr) + assert.NoError(t, err) + assert.True(t, bytes.Equal(tID[:], bs)) + tIDConv, err := FromString(tidStr) + assert.NoError(t, err) + assert.True(t, TxIDEqual(tID, tIDConv)) +} diff --git a/transactions/base_task.go b/transactions/txv1/base_task.go similarity index 78% rename from transactions/base_task.go rename to transactions/txv1/base_task.go index e60bdc746..65c629437 100644 --- a/transactions/base_task.go +++ b/transactions/txv1/base_task.go @@ -1,38 +1,33 @@ -package transactions +package txv1 import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/gocelery" logging "github.com/ipfs/go-log" - "github.com/satori/go.uuid" ) var log = logging.Logger("transaction") -const ( - // TxIDParam maps transaction ID in the kwargs. - TxIDParam = "transactionID" -) - // BaseTask holds the required details and helper functions for tasks to update transactions. // should be embedded into the task type BaseTask struct { - TxID uuid.UUID + TxID transactions.TxID // state - TxManager Manager + TxManager transactions.Manager } // ParseTransactionID parses txID. func (b *BaseTask) ParseTransactionID(taskTypeName string, kwargs map[string]interface{}) error { - txID, ok := kwargs[TxIDParam].(string) + txID, ok := kwargs[transactions.TxIDParam].(string) if !ok { return errors.New("missing transaction ID") } var err error - b.TxID, err = uuid.FromString(txID) + b.TxID, err = transactions.FromString(txID) if err != nil { return errors.New("invalid transaction ID") } @@ -50,9 +45,9 @@ func (b *BaseTask) UpdateTransaction(accountID identity.CentID, taskTypeName str // TODO this TaskStatus map update assumes that a single transaction has only one execution of a certain task type, which can be wrong, use the taskID or another unique identifier instead. if err != nil { log.Errorf("Task %s failed for transaction: %v\n", taskTypeName, b.TxID.String()) - return errors.AppendError(err, b.TxManager.UpdateTaskStatus(accountID, b.TxID, Failed, taskTypeName, err.Error())) + return errors.AppendError(err, b.TxManager.UpdateTaskStatus(accountID, b.TxID, transactions.Failed, taskTypeName, err.Error())) } log.Infof("Task %s successful for transaction:%v\n", taskTypeName, b.TxID.String()) - return b.TxManager.UpdateTaskStatus(accountID, b.TxID, Success, taskTypeName, "") + return b.TxManager.UpdateTaskStatus(accountID, b.TxID, transactions.Success, taskTypeName, "") } diff --git a/transactions/base_task_test.go b/transactions/txv1/base_task_test.go similarity index 71% rename from transactions/base_task_test.go rename to transactions/txv1/base_task_test.go index a5849538e..86b1349fc 100644 --- a/transactions/base_task_test.go +++ b/transactions/txv1/base_task_test.go @@ -1,6 +1,6 @@ // +build unit -package transactions +package txv1 import ( "testing" @@ -8,7 +8,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" - "github.com/satori/go.uuid" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -17,39 +17,39 @@ func TestDocumentAnchorTask_updateTransaction(t *testing.T) { accountID := identity.RandomCentID() name := "some task" - task.TxID = uuid.Must(uuid.NewV4()) + task.TxID = transactions.NewTxID() task.TxManager = NewManager(&mockConfig{}, NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) // missing transaction with nil error err := task.UpdateTransaction(accountID, name, nil) err = errors.GetErrs(err)[0] - assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + assert.True(t, errors.IsOfType(transactions.ErrTransactionMissing, err)) // missing transaction with error err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) err = errors.GetErrs(err)[1] - assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + assert.True(t, errors.IsOfType(transactions.ErrTransactionMissing, err)) // no error and success - tx := newTransaction(accountID, "") + tx := transactions.NewTransaction(accountID, "") assert.NoError(t, task.TxManager.(extendedManager).saveTransaction(tx)) task.TxID = tx.ID assert.NoError(t, task.UpdateTransaction(accountID, name, nil)) tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) - assert.Equal(t, tx.Status, Pending) - assert.Equal(t, tx.TaskStatus[name], Success) + assert.Equal(t, tx.Status, transactions.Pending) + assert.Equal(t, tx.TaskStatus[name], transactions.Success) assert.Len(t, tx.Logs, 1) // failed task - tx = newTransaction(accountID, "") + tx = transactions.NewTransaction(accountID, "") assert.NoError(t, task.TxManager.(extendedManager).saveTransaction(tx)) task.TxID = tx.ID err = task.UpdateTransaction(accountID, name, errors.New("anchor error")) assert.EqualError(t, errors.GetErrs(err)[0], "anchor error") tx, err = task.TxManager.GetTransaction(accountID, task.TxID) assert.NoError(t, err) - assert.Equal(t, tx.Status, Pending) - assert.Equal(t, tx.TaskStatus[name], Failed) + assert.Equal(t, tx.Status, transactions.Pending) + assert.Equal(t, tx.TaskStatus[name], transactions.Failed) assert.Len(t, tx.Logs, 1) } diff --git a/transactions/bootstrapper.go b/transactions/txv1/bootstrapper.go similarity index 51% rename from transactions/bootstrapper.go rename to transactions/txv1/bootstrapper.go index 70e5faa18..96f31c6c6 100644 --- a/transactions/bootstrapper.go +++ b/transactions/txv1/bootstrapper.go @@ -1,20 +1,9 @@ -package transactions +package txv1 import ( "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" -) - -const ( - // ErrTransactionBootstrap error when bootstrap fails. - ErrTransactionBootstrap = errors.Error("failed to bootstrap transactions") - - // BootstrappedRepo is the key mapped to transactions.Repository. - BootstrappedRepo = "BootstrappedRepo" - - // BootstrappedService is the key to mapped transactions.Manager - BootstrappedService = "BootstrappedService" + "github.com/centrifuge/go-centrifuge/transactions" ) // Bootstrapper implements bootstrap.Bootstrapper. @@ -29,13 +18,13 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { repo, ok := ctx[storage.BootstrappedDB].(storage.Repository) if !ok { - return ErrTransactionBootstrap + return transactions.ErrTransactionBootstrap } txRepo := NewRepository(repo) - ctx[BootstrappedRepo] = txRepo + ctx[transactions.BootstrappedRepo] = txRepo txSrv := NewManager(cfg, txRepo) - ctx[BootstrappedService] = txSrv + ctx[transactions.BootstrappedService] = txSrv return nil } diff --git a/transactions/bootstrapper_test.go b/transactions/txv1/bootstrapper_test.go similarity index 83% rename from transactions/bootstrapper_test.go rename to transactions/txv1/bootstrapper_test.go index 4dfb8b957..35111aa2d 100644 --- a/transactions/bootstrapper_test.go +++ b/transactions/txv1/bootstrapper_test.go @@ -1,21 +1,17 @@ // +build unit -package transactions +package txv1 import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) @@ -32,6 +28,6 @@ func TestBootstrapper_Bootstrap(t *testing.T) { ctx[storage.BootstrappedDB] = leveldb.NewLevelDBRepository(db) err = b.Bootstrap(ctx) assert.Nil(t, err) - assert.NotNil(t, ctx[BootstrappedRepo]) - assert.NotNil(t, ctx[BootstrappedService]) + assert.NotNil(t, ctx[transactions.BootstrappedRepo]) + assert.NotNil(t, ctx[transactions.BootstrappedService]) } diff --git a/transactions/handler.go b/transactions/txv1/handler.go similarity index 81% rename from transactions/handler.go rename to transactions/txv1/handler.go index 4b2643d33..9db8bebb6 100644 --- a/transactions/handler.go +++ b/transactions/txv1/handler.go @@ -1,4 +1,4 @@ -package transactions +package txv1 import ( "context" @@ -8,8 +8,8 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/transactions" logging "github.com/ipfs/go-log" - "github.com/satori/go.uuid" ) // ErrInvalidTransactionID error for Invalid transaction ID. @@ -21,13 +21,13 @@ const ErrInvalidAccountID = errors.Error("Invalid Tenant ID") var apiLog = logging.Logger("transaction-api") // GRPCHandler returns an implementation of the TransactionServiceServer -func GRPCHandler(srv Manager, configService config.Service) transactionspb.TransactionServiceServer { +func GRPCHandler(srv transactions.Manager, configService config.Service) transactionspb.TransactionServiceServer { return grpcHandler{srv: srv, configService: configService} } // grpcHandler implements transactionspb.TransactionServiceServer type grpcHandler struct { - srv Manager + srv transactions.Manager configService config.Service } @@ -39,9 +39,9 @@ func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactions return nil, err } - id := uuid.FromStringOrNil(req.TransactionId) - if id == uuid.Nil { - return nil, ErrInvalidTransactionID + id, err := transactions.FromString(req.TransactionId) + if err != nil { + return nil, errors.NewTypedError(ErrInvalidTransactionID, err) } tc, err := contextutil.Account(ctxHeader) diff --git a/transactions/handler_test.go b/transactions/txv1/handler_test.go similarity index 80% rename from transactions/handler_test.go rename to transactions/txv1/handler_test.go index fdf5c8740..8432a9601 100644 --- a/transactions/handler_test.go +++ b/transactions/txv1/handler_test.go @@ -1,24 +1,22 @@ // +build unit -package transactions +package txv1 import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" ) func TestGRPCHandler_GetTransactionStatus(t *testing.T) { cService := ctx[config.BootstrappedConfigStorage].(config.Service) - h := GRPCHandler(ctx[BootstrappedService].(Manager), cService) + h := GRPCHandler(ctx[transactions.BootstrappedService].(transactions.Manager), cService) req := new(transactionspb.TransactionStatusRequest) ctxl := testingconfig.HandlerContext(cService) @@ -39,14 +37,14 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { tcs, _ := cService.GetAllAccounts() accID, _ := tcs[0].GetIdentityID() cid, err := identity.ToCentID(accID) - tx := newTransaction(cid, "") + tx := transactions.NewTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) assert.Nil(t, res) assert.Error(t, err) - assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + assert.True(t, errors.IsOfType(transactions.ErrTransactionMissing, err)) - repo := ctx[BootstrappedRepo].(Repository) + repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) assert.Nil(t, repo.Save(tx)) // success diff --git a/transactions/manager.go b/transactions/txv1/manager.go similarity index 56% rename from transactions/manager.go rename to transactions/txv1/manager.go index d579121eb..a9e9805d8 100644 --- a/transactions/manager.go +++ b/transactions/txv1/manager.go @@ -1,63 +1,48 @@ -package transactions +package txv1 import ( "context" "fmt" "time" + "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" ) -// Config is the config interface for transactions package -type Config interface { - GetEthereumContextWaitTimeout() time.Duration -} - -// Manager is a manager for centrifuge transactions. -type Manager interface { - // ExecuteWithinTX executes the given unit of work within a transaction - ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) - GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) - UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status Status, taskName, message string) error - GetTransactionStatus(accountID identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) - WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error - GetDefaultTaskTimeout() time.Duration -} - // extendedManager exposes package specific functions. type extendedManager interface { - Manager + transactions.Manager // saveTransaction only exposed for testing within package. // DO NOT use this outside of the package, use ExecuteWithinTX to initiate a transaction with management. - saveTransaction(tx *Transaction) error + saveTransaction(tx *transactions.Transaction) error // createTransaction only exposed for testing within package. // DO NOT use this outside of the package, use ExecuteWithinTX to initiate a transaction with management. - createTransaction(accountID identity.CentID, desc string) (*Transaction, error) + createTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) } // NewManager returns a Manager implementation. -func NewManager(config Config, repo Repository) Manager { - return &service{config: config, repo: repo} +func NewManager(config transactions.Config, repo transactions.Repository) transactions.Manager { + return &manager{config: config, repo: repo} } -// service implements Manager. +// manager implements Manager. // TODO [TXManager] convert this into an implementation of node.Server and start it at node start so that we can bring down transaction go routines cleanly -type service struct { - config Config - repo Repository +type manager struct { + config transactions.Config + repo transactions.Repository } -func (s *service) GetDefaultTaskTimeout() time.Duration { +func (s *manager) GetDefaultTaskTimeout() time.Duration { return s.config.GetEthereumContextWaitTimeout() } -func (s *service) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, status Status, taskName, message string) error { +func (s *manager) UpdateTaskStatus(accountID identity.CentID, id transactions.TxID, status transactions.Status, taskName, message string) error { tx, err := s.GetTransaction(accountID, id) if err != nil { return err @@ -65,18 +50,18 @@ func (s *service) UpdateTaskStatus(accountID identity.CentID, id uuid.UUID, stat // status particular to the task tx.TaskStatus[taskName] = status - tx.Logs = append(tx.Logs, NewLog(taskName, message)) + tx.Logs = append(tx.Logs, transactions.NewLog(taskName, message)) return s.saveTransaction(tx) } // ExecuteWithinTX executes a transaction within a transaction. -func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID uuid.UUID, desc string, work func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error)) (txID uuid.UUID, done chan bool, err error) { +func (s *manager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID transactions.TxID, desc string, work func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { t, err := s.repo.Get(accountID, existingTxID) if err != nil { - t = newTransaction(accountID, desc) + t = transactions.NewTransaction(accountID, desc) err := s.saveTransaction(t) if err != nil { - return uuid.Nil, nil, err + return transactions.NilTxID(), nil, err } } done = make(chan bool) @@ -92,13 +77,13 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID break } // update tx success status only if this wasn't an existing TX. - // Otherwise if might update an existing tx pending status to success without actually being a success, - // it is assumed that status updated is already handles per task in that case. - // Checking individual task success is upto the transaction manager calling code. - if e == nil && existingTxID == uuid.Nil { - tempTx.Status = Success + // Otherwise it might update an existing tx pending status to success without actually being a success, + // It is assumed that status update is already handled per task in that case. + // Checking individual task success is upto the transaction manager users. + if e == nil && transactions.TxIDEqual(existingTxID, transactions.NilTxID()) { + tempTx.Status = transactions.Success } else if e != nil { - tempTx.Status = Failed + tempTx.Status = transactions.Failed } e = s.saveTransaction(tempTx) if e != nil { @@ -112,7 +97,7 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID log.Error(err) break } - tempTx.Logs = append(tempTx.Logs, NewLog("context closed", msg)) + tempTx.Logs = append(tempTx.Logs, transactions.NewLog("context closed", msg)) e := s.saveTransaction(tempTx) if e != nil { log.Error(e) @@ -124,7 +109,7 @@ func (s *service) ExecuteWithinTX(ctx context.Context, accountID identity.CentID } // saveTransaction saves the transaction. -func (s *service) saveTransaction(tx *Transaction) error { +func (s *manager) saveTransaction(tx *transactions.Transaction) error { err := s.repo.Save(tx) if err != nil { return err @@ -133,19 +118,19 @@ func (s *service) saveTransaction(tx *Transaction) error { } // GetTransaction returns the transaction associated with identity and id. -func (s *service) GetTransaction(accountID identity.CentID, id uuid.UUID) (*Transaction, error) { +func (s *manager) GetTransaction(accountID identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { return s.repo.Get(accountID, id) } // createTransaction creates a new transaction and saves it to the DB. -func (s *service) createTransaction(accountID identity.CentID, desc string) (*Transaction, error) { - tx := newTransaction(accountID, desc) +func (s *manager) createTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) { + tx := transactions.NewTransaction(accountID, desc) return tx, s.saveTransaction(tx) } // WaitForTransaction blocks until transaction status is moved from pending state. // Note: use it with caution as this will block. -func (s *service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) error { +func (s *manager) WaitForTransaction(accountID identity.CentID, txID transactions.TxID) error { // TODO change this to use a pre-saved done channel from ExecuteWithinTX, instead of a for loop, may require significant refactoring to handle the case of restarted node for { resp, err := s.GetTransactionStatus(accountID, txID) @@ -153,10 +138,10 @@ func (s *service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) return err } - switch Status(resp.Status) { - case Failed: + switch transactions.Status(resp.Status) { + case transactions.Failed: return errors.New("transaction failed: %v", resp.Message) - case Success: + case transactions.Success: return nil default: time.Sleep(10 * time.Millisecond) @@ -166,8 +151,8 @@ func (s *service) WaitForTransaction(accountID identity.CentID, txID uuid.UUID) } // GetTransactionStatus returns the transaction status associated with identity and id. -func (s *service) GetTransactionStatus(identity identity.CentID, id uuid.UUID) (*transactionspb.TransactionStatusResponse, error) { - tx, err := s.GetTransaction(identity, id) +func (s *manager) GetTransactionStatus(accountID identity.CentID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { + tx, err := s.GetTransaction(accountID, id) if err != nil { return nil, err } diff --git a/transactions/manager_test.go b/transactions/txv1/manager_test.go similarity index 63% rename from transactions/manager_test.go rename to transactions/txv1/manager_test.go index 4ad0e326e..903e646b4 100644 --- a/transactions/manager_test.go +++ b/transactions/txv1/manager_test.go @@ -1,6 +1,6 @@ // +build unit -package transactions +package txv1 import ( "context" @@ -9,8 +9,8 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -22,8 +22,8 @@ func (mockConfig) GetEthereumContextWaitTimeout() time.Duration { func TestService_ExecuteWithinTX_happy(t *testing.T) { cid := identity.RandomCentID() - srv := ctx[BootstrappedService].(Manager) - tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + srv := ctx[transactions.BootstrappedService].(transactions.Manager) + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { err <- nil }) <-done @@ -31,13 +31,13 @@ func TestService_ExecuteWithinTX_happy(t *testing.T) { assert.NotNil(t, tid) trn, err := srv.GetTransaction(cid, tid) assert.NoError(t, err) - assert.Equal(t, Success, trn.Status) + assert.Equal(t, transactions.Success, trn.Status) } func TestService_ExecuteWithinTX_err(t *testing.T) { cid := identity.RandomCentID() - srv := ctx[BootstrappedService].(Manager) - tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + srv := ctx[transactions.BootstrappedService].(transactions.Manager) + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { err <- errors.New("dummy") }) <-done @@ -45,14 +45,14 @@ func TestService_ExecuteWithinTX_err(t *testing.T) { assert.NotNil(t, tid) trn, err := srv.GetTransaction(cid, tid) assert.NoError(t, err) - assert.Equal(t, Failed, trn.Status) + assert.Equal(t, transactions.Failed, trn.Status) } func TestService_ExecuteWithinTX_ctxDone(t *testing.T) { cid := identity.RandomCentID() - srv := ctx[BootstrappedService].(Manager) + srv := ctx[transactions.BootstrappedService].(transactions.Manager) ctx, canc := context.WithCancel(context.Background()) - tid, done, err := srv.ExecuteWithinTX(ctx, cid, uuid.Nil, "", func(accountID identity.CentID, txID uuid.UUID, txMan Manager, err chan<- error) { + tid, done, err := srv.ExecuteWithinTX(ctx, cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { // doing nothing }) canc() @@ -61,26 +61,26 @@ func TestService_ExecuteWithinTX_ctxDone(t *testing.T) { assert.NotNil(t, tid) trn, err := srv.GetTransaction(cid, tid) assert.NoError(t, err) - assert.Equal(t, Pending, trn.Status) + assert.Equal(t, transactions.Pending, trn.Status) assert.Contains(t, trn.Logs[0].Message, "stopped because of context close") } func TestService_GetTransaction(t *testing.T) { - repo := ctx[BootstrappedRepo].(Repository) - srv := ctx[BootstrappedService].(Manager) + repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) + srv := ctx[transactions.BootstrappedService].(transactions.Manager) cid := identity.RandomCentID() bytes := utils.RandomSlice(identity.CentIDLength) assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) - txn := newTransaction(cid, "Some transaction") + txn := transactions.NewTransaction(cid, "Some transaction") // no transaction txs, err := srv.GetTransactionStatus(cid, txn.ID) assert.Nil(t, txs) assert.NotNil(t, err) - assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + assert.True(t, errors.IsOfType(transactions.ErrTransactionMissing, err)) - txn.Status = Pending + txn.Status = transactions.Pending assert.Nil(t, repo.Save(txn)) // pending with no log @@ -88,13 +88,13 @@ func TestService_GetTransaction(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, txs) assert.Equal(t, txs.TransactionId, txn.ID.String()) - assert.Equal(t, string(Pending), txs.Status) + assert.Equal(t, string(transactions.Pending), txs.Status) assert.Empty(t, txs.Message) assert.Equal(t, utils.ToTimestamp(txn.CreatedAt), txs.LastUpdated) - log := NewLog("action", "some message") + log := transactions.NewLog("action", "some message") txn.Logs = append(txn.Logs, log) - txn.Status = Success + txn.Status = transactions.Success assert.Nil(t, repo.Save(txn)) // log with message @@ -102,13 +102,13 @@ func TestService_GetTransaction(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, txs) assert.Equal(t, txs.TransactionId, txn.ID.String()) - assert.Equal(t, string(Success), txs.Status) + assert.Equal(t, string(transactions.Success), txs.Status) assert.Equal(t, log.Message, txs.Message) assert.Equal(t, utils.ToTimestamp(log.CreatedAt), txs.LastUpdated) } func TestService_CreateTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(extendedManager) + srv := ctx[transactions.BootstrappedService].(extendedManager) cid := identity.RandomCentID() tx, err := srv.createTransaction(cid, "test") assert.NoError(t, err) @@ -117,8 +117,8 @@ func TestService_CreateTransaction(t *testing.T) { } func TestService_WaitForTransaction(t *testing.T) { - srv := ctx[BootstrappedService].(extendedManager) - repo := ctx[BootstrappedRepo].(Repository) + srv := ctx[transactions.BootstrappedService].(extendedManager) + repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) cid := identity.RandomCentID() // failed @@ -126,12 +126,12 @@ func TestService_WaitForTransaction(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, tx) assert.Equal(t, cid.String(), tx.CID.String()) - tx.Status = Failed + tx.Status = transactions.Failed assert.NoError(t, repo.Save(tx)) assert.Error(t, srv.WaitForTransaction(cid, tx.ID)) // success - tx.Status = Success + tx.Status = transactions.Success assert.NoError(t, repo.Save(tx)) assert.NoError(t, srv.WaitForTransaction(cid, tx.ID)) } diff --git a/transactions/txv1/repository.go b/transactions/txv1/repository.go new file mode 100644 index 000000000..28307afb2 --- /dev/null +++ b/transactions/txv1/repository.go @@ -0,0 +1,59 @@ +package txv1 + +import ( + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/storage" + "github.com/centrifuge/go-centrifuge/transactions" +) + +// txRepository implements Repository. +type txRepository struct { + repo storage.Repository +} + +// NewRepository registers the the transaction model and returns the an implementation +// of the Repository. +func NewRepository(repo storage.Repository) transactions.Repository { + repo.Register(&transactions.Transaction{}) + return &txRepository{repo: repo} +} + +// getKey appends identity with id. +// With identity coming at first, we can even fetch transactions belonging to specific identity through prefix. +func getKey(cid identity.CentID, id transactions.TxID) ([]byte, error) { + if transactions.TxIDEqual(transactions.NilTxID(), id) { + return nil, errors.New("transaction ID is not valid") + } + + return append(cid[:], id.Bytes()...), nil +} + +// Get returns the transaction associated with identity and id. +func (r *txRepository) Get(cid identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { + key, err := getKey(cid, id) + if err != nil { + return nil, errors.NewTypedError(transactions.ErrKeyConstructionFailed, err) + } + + m, err := r.repo.Get(key) + if err != nil { + return nil, errors.NewTypedError(transactions.ErrTransactionMissing, err) + } + + return m.(*transactions.Transaction), nil +} + +// Save saves the transaction to the repository. +func (r *txRepository) Save(tx *transactions.Transaction) error { + key, err := getKey(tx.CID, tx.ID) + if err != nil { + return errors.NewTypedError(transactions.ErrKeyConstructionFailed, err) + } + + if r.repo.Exists(key) { + return r.repo.Update(key, tx) + } + + return r.repo.Create(key, tx) +} diff --git a/transactions/repository_test.go b/transactions/txv1/repository_test.go similarity index 79% rename from transactions/repository_test.go rename to transactions/txv1/repository_test.go index 6af3e64ff..4fa198be2 100644 --- a/transactions/repository_test.go +++ b/transactions/txv1/repository_test.go @@ -1,24 +1,21 @@ // +build unit -package transactions +package txv1 import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" - "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" ) @@ -41,14 +38,14 @@ func TestMain(m *testing.M) { func Test_getKey(t *testing.T) { cid := identity.RandomCentID() - id := uuid.UUID([16]byte{}) + id := transactions.NilTxID() // empty id key, err := getKey(cid, id) assert.Nil(t, key) assert.Equal(t, "transaction ID is not valid", err.Error()) - id = uuid.Must(uuid.NewV4()) + id = transactions.NewTxID() key, err = getKey(cid, id) assert.Nil(t, err) assert.Equal(t, append(cid[:], id.Bytes()...), key) @@ -59,18 +56,18 @@ func TestRepository(t *testing.T) { bytes := utils.RandomSlice(identity.CentIDLength) assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) - repo := ctx[BootstrappedRepo].(Repository) - tx := newTransaction(cid, "Some transaction") + repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) + tx := transactions.NewTransaction(cid, "Some transaction") assert.NotNil(t, tx.ID) assert.NotNil(t, tx.CID) - assert.Equal(t, Pending, tx.Status) + assert.Equal(t, transactions.Pending, tx.Status) // get tx from repo _, err := repo.Get(cid, tx.ID) - assert.True(t, errors.IsOfType(ErrTransactionMissing, err)) + assert.True(t, errors.IsOfType(transactions.ErrTransactionMissing, err)) // save tx into repo - tx.Status = Success + tx.Status = transactions.Success err = repo.Save(tx) assert.Nil(t, err) @@ -79,5 +76,5 @@ func TestRepository(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, tx) assert.Equal(t, cid, tx.CID) - assert.Equal(t, Success, tx.Status) + assert.Equal(t, transactions.Success, tx.Status) } diff --git a/transactions/test_bootstrapper.go b/transactions/txv1/test_bootstrapper.go similarity index 89% rename from transactions/test_bootstrapper.go rename to transactions/txv1/test_bootstrapper.go index cab5a3704..56848cf36 100644 --- a/transactions/test_bootstrapper.go +++ b/transactions/txv1/test_bootstrapper.go @@ -1,6 +1,6 @@ // +build unit integration -package transactions +package txv1 func (b Bootstrapper) TestBootstrap(ctx map[string]interface{}) error { return b.Bootstrap(ctx) From 42968b31c1abf41bc9c7f2eaa853a376ee8ad42d Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 20 Feb 2019 12:16:17 +0100 Subject: [PATCH 193/220] hash instead of copying the message (#759) Hash the message before signing --- cmd/centrifuge/sign_message.go | 1 - crypto/ed25519/ed25519.go | 3 - crypto/keytools.go | 1 - crypto/secp256k1/secp256k1.go | 21 +++--- crypto/secp256k1/secp256k1_test.go | 112 +++++++---------------------- crypto/sign.go | 6 +- crypto/sign_test.go | 2 +- crypto/verify.go | 6 +- 8 files changed, 42 insertions(+), 110 deletions(-) diff --git a/cmd/centrifuge/sign_message.go b/cmd/centrifuge/sign_message.go index b0bf989a0..a7f94e0a7 100644 --- a/cmd/centrifuge/sign_message.go +++ b/cmd/centrifuge/sign_message.go @@ -32,7 +32,6 @@ func init() { log.Fatal(err) } fmt.Println(hexutil.Encode(signature)) - }, } diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index d542beb7b..5594a40d8 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -3,14 +3,11 @@ package ed25519 import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-crypto" "github.com/libp2p/go-libp2p-peer" "golang.org/x/crypto/ed25519" ) -var log = logging.Logger("ed25519") - // GetPublicSigningKey returns the public key from the file func GetPublicSigningKey(fileName string) (publicKey ed25519.PublicKey, err error) { key, err := utils.ReadKeyFromPemFile(fileName, utils.PublicKey) diff --git a/crypto/keytools.go b/crypto/keytools.go index d894d942d..45f2b11c2 100644 --- a/crypto/keytools.go +++ b/crypto/keytools.go @@ -10,5 +10,4 @@ var log = logging.Logger("keytools") const ( CurveEd25519 string = "ed25519" CurveSecp256K1 string = "secp256k1" - MaxMsgLen = 32 ) diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index 63c7ea4ab..9196e7e76 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -41,16 +41,14 @@ func GenerateSigningKeyPair() (publicKey, privateKey []byte, err error) { } // Sign signs the message using private key +// We do hash the message since it not recommended to use the message as is. func Sign(message []byte, privateKey []byte) (signature []byte, err error) { - return secp256k1.Sign(message, privateKey) + return secp256k1.Sign(Hash(message), privateKey) } // SignEthereum converts message to ethereum specific format and signs it. func SignEthereum(message []byte, privateKey []byte) (signature []byte, err error) { - // The hash is calculated in Ethereum in the following way - // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). - hash := SignHash(message) - return Sign(hash, privateKey) + return secp256k1.Sign(HashWithEthPrefix(message), privateKey) } // GetAddress returns the hex of first 20 bytes of the Keccak256 has of public keuy @@ -84,7 +82,7 @@ func VerifySignatureWithAddress(address, sigHex string, msg []byte) bool { sig[signatureVPosition] -= 27 // change V value to 0 or 1 } - pubKey, err := crypto.SigToPub(SignHash(msg), sig) + pubKey, err := crypto.SigToPub(HashWithEthPrefix(msg), sig) if err != nil { return false } @@ -93,16 +91,21 @@ func VerifySignatureWithAddress(address, sigHex string, msg []byte) bool { return fromAddr == recoveredAddr } -// SignHash returns the hash of the data. +// HashWithEthPrefix returns the hash of the data. // The hash is calculated as // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // for further details see // https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L404 -func SignHash(data []byte) []byte { +func HashWithEthPrefix(data []byte) []byte { msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(data)) return crypto.Keccak256(append([]byte(msg), data...)) } +// Hash returns the hash result from Keccak256(data) +func Hash(data []byte) []byte { + return crypto.Keccak256(data) +} + // VerifySignature verifies signature using the public key provided. func VerifySignature(publicKey, message, signature []byte) bool { if len(signature) == signatureRSFormatLen+1 { @@ -111,7 +114,7 @@ func VerifySignature(publicKey, message, signature []byte) bool { signature = signature[0:signatureRSFormatLen] } // the signature should have the 64 byte [R || S] format - return secp256k1.VerifySignature(publicKey, message, signature) + return secp256k1.VerifySignature(publicKey, Hash(message), signature) } diff --git a/crypto/secp256k1/secp256k1_test.go b/crypto/secp256k1/secp256k1_test.go index da8e75a63..e9d97cb8c 100644 --- a/crypto/secp256k1/secp256k1_test.go +++ b/crypto/secp256k1/secp256k1_test.go @@ -3,19 +3,17 @@ package secp256k1 import ( - "fmt" "os" "testing" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) -const MaxMsgLen = 32 - var ctx = map[string]interface{}{} var cfg config.Configuration @@ -31,67 +29,50 @@ func TestMain(m *testing.M) { } func TestGenerateSigningKeyPair(t *testing.T) { - const PublicKeyLen = 65 const PrivateKeyLen = 32 publicKey, privateKey, _ := GenerateSigningKeyPair() assert.Equal(t, len(publicKey), PublicKeyLen, "secp256k1 public key not correct") assert.Equal(t, len(privateKey), PrivateKeyLen, "secp256k1 private key not correct") - } func TestSigningMsg(t *testing.T) { - - testMsg := make([]byte, MaxMsgLen) - copy(testMsg, "test123") - + testMsg := []byte("Hello, world!") publicKey, privateKey, _ := GenerateSigningKeyPair() - signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) correct := VerifySignature(publicKey, testMsg, signature) - assert.True(t, correct, "sign message didn't work correctly") - } -func TestVerifyFalseMsg(t *testing.T) { - - testMsg := make([]byte, MaxMsgLen) - copy(testMsg, "test123") - - falseMsg := make([]byte, MaxMsgLen) - copy(falseMsg, "false") - +func TestSigningMsg32(t *testing.T) { + testMsg := utils.RandomSlice(60) publicKey, privateKey, _ := GenerateSigningKeyPair() - signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) - correct := VerifySignature(publicKey, falseMsg, signature) + correct := VerifySignature(publicKey, testMsg, signature) + assert.True(t, correct, "sign message didn't work correctly") +} +func TestVerifyFalseMsg(t *testing.T) { + publicKey, privateKey, _ := GenerateSigningKeyPair() + signature, err := Sign([]byte("Some random message"), privateKey) + assert.Nil(t, err) + correct := VerifySignature(publicKey, utils.RandomSlice(40), signature) assert.False(t, correct, "false msg verify should be false ") - } func TestVerifyFalsePublicKey(t *testing.T) { - - testMsg := make([]byte, MaxMsgLen) - copy(testMsg, "test123") - _, privateKey, _ := GenerateSigningKeyPair() - falsePublicKey, _, _ := GenerateSigningKeyPair() - + testMsg := utils.RandomSlice(60) signature, err := Sign(testMsg, privateKey) assert.Nil(t, err) correct := VerifySignature(falsePublicKey, testMsg, signature) - assert.False(t, correct, "verify of false public key should be false") - } func TestVerifySignatureWithAddress(t *testing.T) { - testAddress := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" //signature generated with an external library (www.myetherwallet.com) testSignature := "0x526ea99711a545c745a300e363d277b221d06da2814c521f1b7aa2a3fd0741b85044541da1f985afb51bc4b25a2ab2282721957f694c37a0c68f2fa3220c5cea1c" @@ -103,98 +84,55 @@ func TestVerifySignatureWithAddress(t *testing.T) { []byte(testMsg)) assert.True(t, correct, "recovering public key from signature doesn't work correctly") - } func TestVerifySignatureWithAddressFalseMsg(t *testing.T) { - testAddress := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" //signature generated with an external library testSignature := "0x526ea99711a545c745a300e363d277b221d06da2814c521f1b7aa2a3fd0741b85044541da1f985afb51bc4b25a2ab2282721957f694c37a0c68f2fa3220c5cea1c" falseMsg := "false msg" - - correct := VerifySignatureWithAddress( - testAddress, - testSignature, - []byte(falseMsg)) - + correct := VerifySignatureWithAddress(testAddress, testSignature, []byte(falseMsg)) assert.False(t, correct, "verify signature should be false (false msg)") - } func TestVerifySignatureWithFalseAddress(t *testing.T) { - falseAddress := "0xc8dd3d66e112fae5c88fe6a677be24013e53c33e" //signature generated with an external library testSignature := "0x526ea99711a545c745a300e363d277b221d06da2814c521f1b7aa2a3fd0741b85044541da1f985afb51bc4b25a2ab2282721957f694c37a0c68f2fa3220c5cea1c" testMsg := "centrifuge" - - correct := VerifySignatureWithAddress( - falseAddress, - testSignature, - []byte(testMsg)) - + correct := VerifySignatureWithAddress(falseAddress, testSignature, []byte(testMsg)) assert.False(t, correct, "verify signature should be false (false address)") - } func TestVerifySignatureWithFalseSignature(t *testing.T) { - testAddress := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" //signature generated with an external library falseSignature := "0x8efed703a292c278d7de44ab0061144c5bc09a640d168b274b6ad6a7866b7a2542e3e1ae30871d12bf1e882f5b65585a114e9d33615f86e7538f935244071d421b" testMsg := "centrifuge" - - correct := VerifySignatureWithAddress( - testAddress, - falseSignature, - []byte(testMsg)) - + correct := VerifySignatureWithAddress(testAddress, falseSignature, []byte(testMsg)) assert.False(t, correct, "verify signature should be false (false signature)") - } func TestSignForEthereum(t *testing.T) { privateKey, _ := hexutil.Decode("0xb5fffc3933d93dc956772c69b42c4bc66123631a24e3465956d80b5b604a2d13") - address := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" - testMsg := "Centrifuge likes Ethereum" - - testMsgBytes := []byte(testMsg) - - //signature should be 0xc158e04b7e22af2380af7b2581c9f89505761d3e517a07fa6bb76889bdb50c604b1517eb4a920053e878478d171ab63c732deb8eb182e3374bcebd046e773a4500 - //verification should work on external services like https://etherscan.io/verifySig - signature, err := SignEthereum(testMsgBytes, privateKey) + addr := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" + testMsg := utils.RandomSlice(20) + signature, err := SignEthereum(testMsg, privateKey) assert.Nil(t, err) sigHex := hexutil.Encode(signature) - fmt.Println(sigHex) - - correct := VerifySignatureWithAddress(address, sigHex, testMsgBytes) - + correct := VerifySignatureWithAddress(addr, sigHex, testMsg) assert.Equal(t, correct, true, "generating ethereum signature for msg doesn't work correctly") - } -func TestSignForEthereum32Bytes(t *testing.T) { +func TestSignForEthereum32(t *testing.T) { privateKey, _ := hexutil.Decode("0xb5fffc3933d93dc956772c69b42c4bc66123631a24e3465956d80b5b604a2d13") - address := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" - - testMsgBytes := make([]byte, 32) - copy(testMsgBytes, "Centrifuge likes Ethereum") - - // this signature will not work on external services like etherscan.io because the size of testMsgBytes (32 bytes) - // is longer than the testMessage in bytes - signature, err := SignEthereum(testMsgBytes, privateKey) + addr := "0xd77c534aed04d7ce34cd425073a033db4fbe6a9d" + testMsg := utils.RandomSlice(60) + signature, err := SignEthereum(testMsg, privateKey) assert.Nil(t, err) sigHex := hexutil.Encode(signature) - - fmt.Println("address", address) - fmt.Println("msg:", hexutil.Encode(testMsgBytes)) - fmt.Println("signature:", sigHex) - - correct := VerifySignatureWithAddress(address, sigHex, testMsgBytes) - + correct := VerifySignatureWithAddress(addr, sigHex, testMsg) assert.Equal(t, correct, true, "generating ethereum signature for msg doesn't work correctly") - } func TestGetAddress(t *testing.T) { diff --git a/crypto/sign.go b/crypto/sign.go index e4038e873..d542b147d 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -17,13 +17,11 @@ func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool curveType = strings.ToLower(curveType) switch curveType { case CurveSecp256K1: - msg := make([]byte, MaxMsgLen) - copy(msg, message) if ethereumSign { - return secp256k1.SignEthereum(msg, privateKey) + return secp256k1.SignEthereum(message, privateKey) } - return secp256k1.Sign(msg, privateKey) + return secp256k1.Sign(message, privateKey) case CurveEd25519: return nil, errors.New("curve ed25519 not supported yet") default: diff --git a/crypto/sign_test.go b/crypto/sign_test.go index a184b66e2..b2a0948a6 100644 --- a/crypto/sign_test.go +++ b/crypto/sign_test.go @@ -88,7 +88,7 @@ func TestSignAndVerifyMessageEthereum(t *testing.T) { fmt.Println("address:", address) fmt.Println("msg:", string(testMsg[:])) fmt.Println("msg in hex:", hexutil.Encode(testMsg)) - fmt.Println("hash of msg: ", hexutil.Encode(secp256k1.SignHash(testMsg))) + fmt.Println("hash of msg: ", hexutil.Encode(secp256k1.HashWithEthPrefix(testMsg))) fmt.Println("signature:", hexutil.Encode(signature)) fmt.Println("Generated Signature can also be verified at https://etherscan.io/verifySig") diff --git a/crypto/verify.go b/crypto/verify.go index 19f763c3a..820069955 100644 --- a/crypto/verify.go +++ b/crypto/verify.go @@ -14,14 +14,12 @@ func VerifyMessage(publicKey, message []byte, signature []byte, curveType string switch curveType { case CurveSecp256K1: - msg := make([]byte, MaxMsgLen) - copy(msg, message) if ethereumVerify { address := secp256k1.GetAddress(publicKey) - return secp256k1.VerifySignatureWithAddress(address, hexutil.Encode(signatureBytes), msg) + return secp256k1.VerifySignatureWithAddress(address, hexutil.Encode(signatureBytes), message) } - return secp256k1.VerifySignature(publicKey, msg, signatureBytes) + return secp256k1.VerifySignature(publicKey, message, signatureBytes) case CurveEd25519: return ed25519.VerifySignature(publicKey, message, signature) default: From 3318673aed79545f548c51c540df09bb7b69e218 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 20 Feb 2019 12:24:28 +0100 Subject: [PATCH 194/220] Report card --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ead0b0129..85a4d6db3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Centrifuge OS node [![Build Status](https://travis-ci.com/centrifuge/go-centrifuge.svg?token=Sbf68xBZUZLMB3kGTKcX&branch=master)](https://travis-ci.com/centrifuge/go-centrifuge) +[![Go Report Card](https://goreportcard.com/badge/github.com/centrifuge/go-centrifuge)](https://goreportcard.com/report/github.com/centrifuge/go-centrifuge) `go-centrifuge` is the go implementation of the Centrifuge OS interacting with the peer to peer network and our Ethereum smart contracts. From ec41493e5038ac0e8c5f128aa67d4428d2360419 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 20 Feb 2019 15:52:24 +0100 Subject: [PATCH 195/220] NFT uniqeness proofs (#736) Add NFT proofs - Uniqueness proof - NFT read access proof More here - https://hackmd.io/ps0X0jRkRHaACP6aPtGzag --- documents/model.go | 242 +++++++++++++++--- documents/model_test.go | 217 ++++++++++++++++ nft/ethereum_payment_obligation.go | 138 ++++------ nft/ethereum_payment_obligation_test.go | 33 +-- nft/handler.go | 15 +- nft/handler_test.go | 33 ++- nft/payment_obligation.go | 22 +- nft/payment_obligation_integration_test.go | 242 +++++++++++++----- protobufs/gen/go/nft/service.pb.go | 104 +++++--- protobufs/gen/swagger.json | 2 +- .../gen/swagger/nft/service.swagger.json | 15 ++ protobufs/nft/service.proto | 6 + testworld/nft_test.go | 136 ++++++---- 13 files changed, 885 insertions(+), 320 deletions(-) diff --git a/documents/model.go b/documents/model.go index af33e72dc..f485dbfe6 100644 --- a/documents/model.go +++ b/documents/model.go @@ -81,6 +81,9 @@ const ( // ErrZeroCollaborators error when no collaborators are passed ErrZeroCollaborators = errors.Error("require at least one collaborator") + // ErrNFTRoleMissing errors when role to generate proof doesn't exist + ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") + // nftByteCount is the length of combined bytes of registry and tokenID nftByteCount = 52 ) @@ -127,6 +130,17 @@ func NewCoreDocModel() *CoreDocumentModel { // Note: new collaborators are added to the list with old collaborators. //TODO: this will change when collaborators are moved down to next level func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocumentModel, error) { + ndm, err := m.prepareNewVersion(collaborators) + if err != nil { + return nil, err + } + + return ndm, ndm.setCoreDocumentSalts() +} + +// prepareNewVersion prepares the next version of the CoreDocument +// Note: salts needs to be filled by the caller +func (m *CoreDocumentModel) prepareNewVersion(collaborators []string) (*CoreDocumentModel, error) { ndm := NewCoreDocModel() ncd := ndm.Document ocd := m.Document @@ -149,10 +163,6 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu return nil, err } - if err := ndm.setCoreDocumentSalts(); err != nil { - return nil, err - } - if ocd.DocumentIdentifier == nil { return nil, errors.New("Document.DocumentIdentifier is nil") } @@ -175,7 +185,6 @@ func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocu ncd.PreviousRoot = ocd.DocumentRoot // copy over token registry ndm.TokenRegistry = m.TokenRegistry - return ndm, nil } @@ -432,10 +441,11 @@ func (m *CoreDocumentModel) CalculateSigningRoot(dataRoot []byte) error { // AccountCanRead validate if the core document can be read by the account . // Returns an error if not. func (m *CoreDocumentModel) AccountCanRead(account identity.CentID) bool { - // loop though read rules - return m.findRole(coredocumentpb.Action_ACTION_READ_SIGN, func(role *coredocumentpb.Role) bool { - return isAccountInRole(role, account) - }) + // loop though read rules, check all the rules + return m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { + _, found := isAccountInRole(role, account) + return found + }, coredocumentpb.Action_ACTION_READ, coredocumentpb.Action_ACTION_READ_SIGN) } // GenerateNewSalts generates salts for new document @@ -532,17 +542,20 @@ func (m *CoreDocumentModel) addNewRule(role *coredocumentpb.Role, action coredoc cd.ReadRules = append(cd.ReadRules, rule) } -// findRole calls OnRole for every role, -// if onRole returns true, returns true -// else returns false -func (m *CoreDocumentModel) findRole(action coredocumentpb.Action, onRole func(role *coredocumentpb.Role) bool) bool { +// findRole calls OnRole for every role that matches the actions passed in +func (m *CoreDocumentModel) findRole(onRole func(rridx, ridx int, role *coredocumentpb.Role) bool, actions ...coredocumentpb.Action) bool { cd := m.Document - for _, rule := range cd.ReadRules { - if rule.Action != action { + am := make(map[int32]struct{}) + for _, a := range actions { + am[int32(a)] = struct{}{} + } + + for i, rule := range cd.ReadRules { + if _, ok := am[int32(rule.Action)]; !ok { continue } - for _, rk := range rule.Roles { + for j, rk := range rule.Roles { role, err := getRole(rk, cd.Roles) if err != nil { // seems like roles and rules are not in sync @@ -550,7 +563,7 @@ func (m *CoreDocumentModel) findRole(action coredocumentpb.Action, onRole func(r continue } - if onRole(role) { + if onRole(i, j, role) { return true } @@ -560,15 +573,15 @@ func (m *CoreDocumentModel) findRole(action coredocumentpb.Action, onRole func(r return false } -// isAccountInRole returns true if account is in the given role as collaborators. -func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) bool { - for _, id := range role.Collaborators { +// isAccountInRole returns the index of the collaborator and true if account is in the given role as collaborators. +func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) (idx int, found bool) { + for i, id := range role.Collaborators { if bytes.Equal(id, account[:]) { - return true + return i, true } } - return false + return idx, false } func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { @@ -655,9 +668,10 @@ func (m *CoreDocumentModel) NFTOwnerCanRead(registry common.Address, tokenID []b } // check if the nft is present in read rules - found := m.findRole(coredocumentpb.Action_ACTION_READ, func(role *coredocumentpb.Role) bool { - return isNFTInRole(role, registry, tokenID) - }) + found := m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { + _, found := isNFTInRole(role, registry, tokenID) + return found + }, coredocumentpb.Action_ACTION_READ) if !found { return errors.New("nft missing") @@ -739,17 +753,185 @@ func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequ } // isNFTInRole checks if the given nft(registry + token) is part of the core document role. -func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) bool { +// If found, returns the index of the nft in the role and true +func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) (nftIdx int, found bool) { enft, err := ConstructNFT(registry, tokenID) if err != nil { - return false + return nftIdx, false } - for _, n := range role.Nfts { + for i, n := range role.Nfts { if bytes.Equal(n, enft) { - return true + return i, true } } - return false + return nftIdx, false +} + +// AddNFT returns a new CoreDocument model with nft added to the Core document. If grantReadAccess is true, the nft is added +// to the read rules. +func (m *CoreDocumentModel) AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) (*CoreDocumentModel, error) { + data := m.Document.EmbeddedData + ndm, err := m.prepareNewVersion(nil) + if err != nil { + return nil, err + } + + ndm.Document.EmbeddedData = data + cd := ndm.Document + nft := getStoredNFT(cd.Nfts, registry.Bytes()) + if nft == nil { + nft = new(coredocumentpb.NFT) + // add 12 empty bytes + eb := make([]byte, 12, 12) + nft.RegistryId = append(registry.Bytes(), eb...) + cd.Nfts = append(cd.Nfts, nft) + } + nft.TokenId = tokenID + + if grantReadAccess { + err = ndm.AddNFTToReadRules(registry, tokenID) + if err != nil { + return nil, err + } + } + + return ndm, ndm.setCoreDocumentSalts() +} + +// IsNFTMinted checks if the there is an NFT that is minted against this document in the given registry. +func (m *CoreDocumentModel) IsNFTMinted(tokenRegistry TokenRegistry, registry common.Address) bool { + nft := getStoredNFT(m.Document.Nfts, registry.Bytes()) + if nft == nil { + return false + } + + _, err := tokenRegistry.OwnerOf(registry, nft.TokenId) + return err == nil +} + +func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.NFT { + for _, nft := range nfts { + if bytes.Equal(nft.RegistryId[:20], registry) { + return nft + } + } + + return nil +} + +// IsAccountInRole checks if the the account exists in the role provided +func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.CentID) bool { + role, err := getRole(roleKey, m.Document.Roles) + if err != nil { + return false + } + + _, found := isAccountInRole(role, account) + return found +} + +// GetNFTProofs generate proofs required to mint an NFT +func (m *CoreDocumentModel) GetNFTProofs( + dataRoot []byte, + account identity.CentID, + registry common.Address, + tokenID []byte, + nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { + + var pfKeys []string + if nftUniqueProof { + pk, err := getNFTUniqueProofKey(m.Document.Nfts, registry) + if err != nil { + return nil, err + } + + pfKeys = append(pfKeys, pk) + } + + if readAccessProof { + pks, err := getReadAccessProofKeys(m, registry, tokenID) + if err != nil { + return nil, err + } + + pfKeys = append(pfKeys, pks...) + } + + signingRootProofHashes, err := m.getSigningRootProofHashes() + if err != nil { + return nil, errors.New("failed to generate signing root proofs: %v", err) + } + + cdtree, err := m.GetDocumentTree() + if err != nil { + return nil, errors.New("failed to generate document tree: %v", err) + } + + for _, field := range pfKeys { + proof, err := cdtree.CreateProof(field) + if err != nil { + return nil, errors.New("failed to create proof: %v", err) + } + + proof.SortedHashes = append(proof.SortedHashes, dataRoot) + proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) + proofs = append(proofs, &proof) + } + + return proofs, nil +} + +func getReadAccessProofKeys(m *CoreDocumentModel, registry common.Address, tokenID []byte) (pks []string, err error) { + var rridx int // index of the read rules which contain the role + var ridx int // index of the role + var nftIdx int // index of the NFT in the above role + var rk []byte // role key of the above role + + found := m.findRole(func(i, j int, role *coredocumentpb.Role) bool { + z, found := isNFTInRole(role, registry, tokenID) + if found { + rridx = i + ridx = j + rk = role.RoleKey + nftIdx = z + } + + return found + }, coredocumentpb.Action_ACTION_READ) + + if !found { + return nil, ErrNFTRoleMissing + } + + return []string{ + fmt.Sprintf("read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role + fmt.Sprintf("roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists + fmt.Sprintf("read_rules[%d].action", rridx), // proof that this read rule has read access + }, nil +} + +func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) (pk string, err error) { + nft := getStoredNFT(nfts, registry.Bytes()) + if nft == nil { + return pk, errors.New("nft is missing from the document") + } + + key := hexutil.Encode(nft.RegistryId) + return fmt.Sprintf("nfts[%s]", key), nil +} + +func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.CentID) (pk string, err error) { + role, err := getRole(roleKey, roles) + if err != nil { + return pk, err + } + + idx, found := isAccountInRole(role, account) + if !found { + return pk, ErrNFTRoleMissing + } + + return fmt.Sprintf("roles[%s].collaborators[%d]", hexutil.Encode(role.RoleKey), idx), nil } diff --git a/documents/model_test.go b/documents/model_test.go index 96b0de512..3c5e8a574 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -4,6 +4,7 @@ package documents import ( "crypto/sha256" + "fmt" "os" "testing" @@ -17,6 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -483,3 +485,218 @@ func TestConvertToProofAndProtoSalts(t *testing.T) { assert.Len(t, *cSalts, len(*salts)) assert.Equal(t, (*cSalts)[0].Value, (*salts)[0].Value) } + +func TestCoreDocumentModel_AddNFT(t *testing.T) { + dm := NewCoreDocModel() + cd := dm.Document + cd.DocumentRoot = utils.RandomSlice(32) + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") + tokenID := utils.RandomSlice(32) + assert.Nil(t, cd.Nfts) + assert.Nil(t, cd.ReadRules) + assert.Nil(t, cd.Roles) + + ndm, err := dm.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + cd = ndm.Document + assert.Len(t, cd.Nfts, 1) + assert.Len(t, cd.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) + assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) + assert.Len(t, cd.ReadRules, 1) + assert.Len(t, cd.Roles, 1) + assert.Len(t, cd.Roles[0].Nfts, 1) + + tokenID = utils.RandomSlice(32) + cd.DocumentRoot = utils.RandomSlice(32) + ndm, err = ndm.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + cd = ndm.Document + assert.Len(t, cd.Nfts, 1) + assert.Len(t, cd.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) + assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) + assert.Len(t, cd.ReadRules, 2) + assert.Len(t, cd.Roles, 2) + assert.Len(t, cd.Roles[1].Nfts, 1) +} + +func TestCoreDocumentModel_IsNFTMinted(t *testing.T) { + dm := NewCoreDocModel() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + assert.False(t, dm.IsNFTMinted(nil, registry)) + + cd := dm.Document + cd.DocumentRoot = utils.RandomSlice(32) + tokenID := utils.RandomSlice(32) + owner := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") + ndm, err := dm.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + + tr := new(mockRegistry) + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + assert.True(t, ndm.IsNFTMinted(tr, registry)) + tr.AssertExpectations(t) +} + +func TestCoreDocumentModel_IsAccountInRole(t *testing.T) { + dm := NewCoreDocModel() + account := identity.RandomCentID() + roleKey := make([]byte, 32, 32) + assert.False(t, dm.IsAccountInRole(roleKey, account)) + + err := dm.initReadRules([]identity.CentID{account}) + assert.NoError(t, err) + assert.True(t, dm.IsAccountInRole(roleKey, account)) +} + +func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { + dm := NewCoreDocModel() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(32) + + pfs, err := getReadAccessProofKeys(dm, registry, tokenID) + assert.Error(t, err) + assert.Nil(t, pfs) + + dm.Document.DocumentRoot = utils.RandomSlice(32) + ndm, err := dm.AddNFT(true, registry, tokenID) + assert.NoError(t, err) + assert.NotNil(t, ndm) + + pfs, err = getReadAccessProofKeys(ndm, registry, tokenID) + assert.NoError(t, err) + assert.Len(t, pfs, 3) + assert.Equal(t, "read_rules[0].roles[0]", pfs[0]) + assert.Equal(t, fmt.Sprintf("roles[%s].nfts[0]", hexutil.Encode(make([]byte, 32, 32))), pfs[1]) + assert.Equal(t, "read_rules[0].action", pfs[2]) +} + +func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { + dm := NewCoreDocModel() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + pf, err := getNFTUniqueProofKey(dm.Document.Nfts, registry) + assert.Error(t, err) + assert.Empty(t, pf) + + dm.Document.DocumentRoot = utils.RandomSlice(32) + tokenID := utils.RandomSlice(32) + ndm, err := dm.AddNFT(false, registry, tokenID) + assert.NoError(t, err) + assert.NotNil(t, ndm) + + pf, err = getNFTUniqueProofKey(ndm.Document.Nfts, registry) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf("nfts[%s]", hexutil.Encode(append(registry.Bytes(), make([]byte, 12, 12)...))), pf) +} + +func TestCoreDocument_getRoleProofKey(t *testing.T) { + dm := NewCoreDocModel() + roleKey := make([]byte, 32, 32) + account := identity.RandomCentID() + pf, err := getRoleProofKey(dm.Document.Roles, roleKey, account) + assert.Error(t, err) + assert.Empty(t, pf) + + err = dm.initReadRules([]identity.CentID{account}) + assert.NoError(t, err) + + pf, err = getRoleProofKey(dm.Document.Roles, roleKey, identity.RandomCentID()) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrNFTRoleMissing, err)) + assert.Empty(t, pf) + + pf, err = getRoleProofKey(dm.Document.Roles, roleKey, account) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf("roles[%s].collaborators[0]", hexutil.Encode(roleKey)), pf) +} + +func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { + dataRoot := utils.RandomSlice(32) + dm := NewCoreDocModel() + invData := &invoicepb.InvoiceData{} + dataSalts, err := GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) + assert.NoError(t, err) + + dm.Document.EmbeddedData = &any.Any{Value: utils.RandomSlice(32), TypeUrl: documenttypes.InvoiceDataTypeUrl} + account := identity.RandomCentID() + assert.NoError(t, dm.initReadRules([]identity.CentID{account})) + + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(32) + dm.Document.DocumentRoot = utils.RandomSlice(32) + dm, err = dm.AddNFT(true, registry, tokenID) + assert.NoError(t, err) + dm.Document.EmbeddedDataSalts = ConvertToProtoSalts(dataSalts) + assert.NoError(t, err) + assert.NoError(t, dm.setCoreDocumentSalts()) + assert.NoError(t, dm.CalculateSigningRoot(dataRoot)) + assert.NoError(t, dm.CalculateDocumentRoot()) + + tests := []struct { + registry common.Address + tokenID []byte + nftReadAccess bool + nftUniqueProof bool + error bool + }{ + + // failed nft unique proof + { + nftUniqueProof: true, + registry: common.BytesToAddress(utils.RandomSlice(20)), + error: true, + }, + + // good nft unique proof + { + nftUniqueProof: true, + registry: registry, + }, + + // failed read access proof + { + nftReadAccess: true, + registry: registry, + tokenID: utils.RandomSlice(32), + error: true, + }, + + // good read access proof + { + nftReadAccess: true, + registry: registry, + tokenID: tokenID, + }, + + // all proofs + { + nftUniqueProof: true, + registry: registry, + nftReadAccess: true, + tokenID: tokenID, + }, + } + + tree, err := dm.GetDocumentRootTree() + assert.NoError(t, err) + + for _, c := range tests { + pfs, err := dm.GetNFTProofs(dataRoot, account, c.registry, c.tokenID, c.nftUniqueProof, c.nftReadAccess) + if c.error { + assert.Error(t, err) + continue + } + + assert.NoError(t, err) + assert.True(t, len(pfs) > 0) + + for _, pf := range pfs { + valid, err := tree.ValidateProof(pf) + assert.NoError(t, err) + assert.True(t, valid) + } + } + +} diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 5800bc11c..7d7dcb274 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -1,12 +1,10 @@ package nft import ( - "bytes" "context" "math/big" "time" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" @@ -17,27 +15,17 @@ import ( "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" logging "github.com/ipfs/go-log" ) var log = logging.Logger("nft") -// ErrNFTMinted error for NFT already minted for registry -const ErrNFTMinted = errors.Error("NFT already minted") - -// ethereumPaymentObligationContract is an abstraction over the contract code to help in mocking it out -type ethereumPaymentObligationContract interface { - - // Mint method abstracts Mint method on the contract - Mint(opts *bind.TransactOpts, to common.Address, tokenID *big.Int, tokenURI string, anchorID *big.Int, merkleRoot [32]byte, values []string, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) - - // OwnerOf to retrieve owner of the tokenID - OwnerOf(opts *bind.CallOpts, tokenID *big.Int) (common.Address, error) -} +const ( + // ErrNFTMinted error for NFT already minted for registry + ErrNFTMinted = errors.Error("NFT already minted") +) // Config is the config interface for nft package type Config interface { @@ -78,38 +66,52 @@ func newEthereumPaymentObligation( } } -func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, tokenID TokenID, documentID []byte, depositAddress string, proofFields []string) (MintRequest, error) { - model, err := s.docSrv.GetCurrentVersion(ctx, documentID) +func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, tokenID TokenID, cid identity.CentID, req MintNFTRequest) (mreq MintRequest, err error) { + docProofs, err := s.docSrv.CreateProofs(ctx, req.DocumentID, req.ProofFields) if err != nil { - return MintRequest{}, err + return mreq, err } - corDocModel, err := model.PackCoreDocument() + model, err := s.docSrv.GetCurrentVersion(ctx, req.DocumentID) if err != nil { - return MintRequest{}, err + return mreq, err } - corDoc := corDocModel.Document - proofs, err := s.docSrv.CreateProofs(ctx, documentID, proofFields) + coreDoc, err := model.PackCoreDocument() if err != nil { - return MintRequest{}, err + return mreq, err } - toAddress := common.HexToAddress(depositAddress) + dataRoot, err := model.CalculateDataRoot() + if err != nil { + return mreq, err + } - anchorID, err := anchors.ToAnchorID(corDoc.CurrentVersion) + pfs, err := coreDoc.GetNFTProofs( + dataRoot, + cid, + req.RegistryAddress, + tokenID[:], + req.SubmitTokenProof, + req.GrantNFTReadAccess && req.SubmitNFTReadAccessProof) if err != nil { - return MintRequest{}, err + return mreq, err } - rootHash, err := anchors.ToDocumentRoot(corDoc.DocumentRoot) + docProofs.FieldProofs = append(docProofs.FieldProofs, pfs...) + anchorID, err := anchors.ToAnchorID(coreDoc.Document.CurrentVersion) if err != nil { - return MintRequest{}, err + return mreq, err } - requestData, err := NewMintRequest(tokenID, toAddress, anchorID, proofs.FieldProofs, rootHash) + rootHash, err := anchors.ToDocumentRoot(coreDoc.Document.DocumentRoot) if err != nil { - return MintRequest{}, err + return mreq, err + } + + requestData, err := NewMintRequest(tokenID, req.DepositAddress, anchorID, pfs, rootHash) + if err != nil { + return mreq, err } return requestData, nil @@ -117,7 +119,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke } // MintNFT mints an NFT -func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) { +func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, req MintNFTRequest) (*MintNFTResponse, chan bool, error) { tc, err := contextutil.Account(ctx) if err != nil { return nil, nil, err @@ -133,8 +135,12 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, nil, err } + if !req.GrantNFTReadAccess && req.SubmitNFTReadAccessProof { + return nil, nil, errors.New("enable grant_nft_access to generate Read Access Proof") + } + tokenID := NewTokenID() - model, err := s.docSrv.GetCurrentVersion(ctx, documentID) + model, err := s.docSrv.GetCurrentVersion(ctx, req.DocumentID) if err != nil { return nil, nil, err } @@ -144,18 +150,15 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by return nil, nil, err } - cd := dm.Document - registry := common.HexToAddress(registryAddress) - mt := getStoredNFT(cd.Nfts, registry.Bytes()) - // check if the nft is successfully minted - if mt != nil && s.isNFTMinted(registry, mt.TokenId) { - return nil, nil, errors.NewTypedError(ErrNFTMinted, errors.New("registry %v", registry.String())) + // check if the nft is successfully minted already + if dm.IsNFTMinted(s, req.RegistryAddress) { + return nil, nil, errors.NewTypedError(ErrNFTMinted, errors.New("registry %v", req.RegistryAddress.String())) } // Mint NFT within transaction // We use context.Background() for now so that the transaction is only limited by ethereum timeouts txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "Minting NFT", - s.minter(ctx, tokenID, model, registry, depositAddress, proofFields)) + s.minter(ctx, tokenID, model, req)) if err != nil { return nil, nil, err } @@ -166,14 +169,7 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, documentID []by }, done, nil } -func (s *ethereumPaymentObligation) isNFTMinted(registry common.Address, tokenID []byte) bool { - // since OwnerOf throws when owner is zero address, - // if err is not thrown, we can assume that NFT is minted - _, err := s.OwnerOf(registry, tokenID) - return err == nil -} - -func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, registry common.Address, depositAddress string, proofFields []string) func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { +func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, req MintNFTRequest) func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { return func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { tc, err := contextutil.Account(ctx) if err != nil { @@ -187,23 +183,13 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - data := dm.Document.EmbeddedData - newDM, err := dm.PrepareNewVersion(nil) + ndm, err := dm.AddNFT(req.GrantNFTReadAccess, req.RegistryAddress, tokenID[:]) if err != nil { errOut <- err return } - newCD := newDM.Document - newCD.EmbeddedData = data - addNFT(newDM, registry.Bytes(), tokenID[:]) - err = newDM.AddNFTToReadRules(registry, tokenID.BigInt().Bytes()) - if err != nil { - errOut <- err - return - } - - model, err = s.docSrv.DeriveFromCoreDocumentModel(newDM) + model, err = s.docSrv.DeriveFromCoreDocumentModel(ndm) if err != nil { errOut <- err return @@ -218,11 +204,11 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, isDone := <-done if !isDone { // some problem occured in a child task - errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(newCD.DocumentIdentifier), txID) + errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(req.DocumentID), txID) return } - requestData, err := s.prepareMintRequest(ctx, tokenID, newCD.DocumentIdentifier, depositAddress, proofFields) + requestData, err := s.prepareMintRequest(ctx, tokenID, accountID, req) if err != nil { errOut <- errors.New("failed to prepare mint request: %v", err) return @@ -234,7 +220,7 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - contract, err := s.bindContract(registry, s.ethClient) + contract, err := s.bindContract(req.RegistryAddress, s.ethClient) if err != nil { errOut <- err return @@ -266,32 +252,6 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, } } -func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.NFT { - for _, nft := range nfts { - if bytes.Equal(nft.RegistryId[:20], registry) { - return nft - } - } - - return nil -} - -// addNFT adds/replaces the NFT -// Note: this is replace operation. Ensure existing token is not minted -func addNFT(dm *documents.CoreDocumentModel, registry, tokenID []byte) { - cd := dm.Document - nft := getStoredNFT(cd.Nfts, registry) - if nft == nil { - nft = new(coredocumentpb.NFT) - // add 12 empty bytes - eb := make([]byte, 12, 12) - nft.RegistryId = append(registry, eb...) - cd.Nfts = append(cd.Nfts, nft) - } - - nft.TokenId = tokenID -} - // OwnerOf returns the owner of the NFT token on ethereum chain func (s *ethereumPaymentObligation) OwnerOf(registry common.Address, tokenID []byte) (owner common.Address, err error) { contract, err := s.bindContract(registry, s.ethClient) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 2c92f0154..03000130b 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" @@ -22,6 +20,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" @@ -202,7 +201,13 @@ func TestPaymentObligationService(t *testing.T) { return &EthereumPaymentObligationContract{}, nil }, txMan, func() (uint64, error) { return 10, nil }) ctxh := testingconfig.CreateAccountContext(t, &mockCfg) - _, _, err := service.MintNFT(ctxh, decodeHex(test.request.Identifier), test.request.RegistryAddress, test.request.DepositAddress, test.request.ProofFields) + req := MintNFTRequest{ + DocumentID: decodeHex(test.request.Identifier), + RegistryAddress: common.HexToAddress(test.request.RegistryAddress), + DepositAddress: common.HexToAddress(test.request.DepositAddress), + ProofFields: test.request.ProofFields, + } + _, _, err := service.MintNFT(ctxh, req) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { @@ -257,25 +262,3 @@ func decodeHex(hex string) []byte { h, _ := hexutil.Decode(hex) return h } - -func Test_addNFT(t *testing.T) { - dm := documents.NewCoreDocModel() - cd := dm.Document - cd.DocumentRoot = utils.RandomSlice(32) - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") - tokenID := utils.RandomSlice(32) - assert.Nil(t, cd.Nfts) - - addNFT(dm, registry.Bytes(), tokenID) - assert.Len(t, cd.Nfts, 1) - assert.Len(t, cd.Nfts[0].RegistryId, 32) - assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) - assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) - - tokenID = utils.RandomSlice(32) - addNFT(dm, registry.Bytes(), tokenID) - assert.Len(t, cd.Nfts, 1) - assert.Len(t, cd.Nfts[0].RegistryId, 32) - assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) -} diff --git a/nft/handler.go b/nft/handler.go index 32f594109..83f8ed30b 100644 --- a/nft/handler.go +++ b/nft/handler.go @@ -41,10 +41,19 @@ func (g grpcHandler) MintNFT(ctx context.Context, request *nftpb.NFTMintRequest) identifier, err := hexutil.Decode(request.Identifier) if err != nil { - return nil, centerrors.New(code.Unknown, err.Error()) + return nil, err } - resp, _, err := g.service.MintNFT(ctxHeader, identifier, request.RegistryAddress, request.DepositAddress, request.ProofFields) + req := MintNFTRequest{ + DocumentID: identifier, + RegistryAddress: common.HexToAddress(request.RegistryAddress), + DepositAddress: common.HexToAddress(request.DepositAddress), + ProofFields: request.ProofFields, + GrantNFTReadAccess: request.GrantNftAccess, + SubmitNFTReadAccessProof: request.SubmitNftOwnerAccessProof, + SubmitTokenProof: request.SubmitTokenProof, + } + resp, _, err := g.service.MintNFT(ctxHeader, req) if err != nil { return nil, centerrors.New(code.Unknown, err.Error()) } @@ -63,6 +72,6 @@ func validateParameters(request *nftpb.NFTMintRequest) error { if !common.IsHexAddress(request.DepositAddress) { return centerrors.New(code.Unknown, "DepositAddress is not a valid Ethereum address") } - return nil + return nil } diff --git a/nft/handler_test.go b/nft/handler_test.go index 1ed5a1aa9..e502fec92 100644 --- a/nft/handler_test.go +++ b/nft/handler_test.go @@ -8,13 +8,11 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/config" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -24,8 +22,8 @@ type mockPaymentObligationService struct { mock.Mock } -func (m *mockPaymentObligationService) MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) { - args := m.Called(ctx, documentID, registryAddress, depositAddress, proofFields) +func (m *mockPaymentObligationService) MintNFT(ctx context.Context, request MintNFTRequest) (*MintNFTResponse, chan bool, error) { + args := m.Called(ctx, request) resp, _ := args.Get(0).(*MintNFTResponse) return resp, nil, args.Error(1) } @@ -38,10 +36,13 @@ func TestNFTMint_success(t *testing.T) { tokID := big.NewInt(1) nftResponse := &MintNFTResponse{TokenID: tokID.String()} - mockService. - On("MintNFT", mock.Anything, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return(nftResponse, nil) - + req := MintNFTRequest{ + DocumentID: docID, + RegistryAddress: common.HexToAddress(nftMintRequest.RegistryAddress), + DepositAddress: common.HexToAddress(nftMintRequest.DepositAddress), + ProofFields: nftMintRequest.ProofFields, + } + mockService.On("MintNFT", mock.Anything, req).Return(nftResponse, nil) handler := grpcHandler{mockConfigStore, mockService} nftMintResponse, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) mockService.AssertExpectations(t) @@ -70,10 +71,14 @@ func TestNFTMint_ServiceError(t *testing.T) { nftMintRequest := getTestSetupData() mockService := &mockPaymentObligationService{} docID, _ := hexutil.Decode(nftMintRequest.Identifier) - mockService. - On("MintNFT", mock.Anything, docID, nftMintRequest.RegistryAddress, nftMintRequest.DepositAddress, nftMintRequest.ProofFields). - Return(nil, errors.New("service error")) - + req := MintNFTRequest{ + DocumentID: docID, + RegistryAddress: common.HexToAddress(nftMintRequest.RegistryAddress), + DepositAddress: common.HexToAddress(nftMintRequest.DepositAddress), + ProofFields: nftMintRequest.ProofFields, + } + + mockService.On("MintNFT", mock.Anything, req).Return(nil, errors.New("service error")) mockConfigStore := mockmockConfigStore() handler := grpcHandler{mockConfigStore, mockService} _, err := handler.MintNFT(testingconfig.HandlerContext(mockConfigStore), nftMintRequest) diff --git a/nft/payment_obligation.go b/nft/payment_obligation.go index db7b28125..9c8268bb5 100644 --- a/nft/payment_obligation.go +++ b/nft/payment_obligation.go @@ -5,10 +5,9 @@ import ( "math/big" "github.com/centrifuge/go-centrifuge/errors" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ) // TokenIDLength is the length of an NFT token ID @@ -25,8 +24,8 @@ func NewTokenID() TokenID { return tid } -// FromString converts given hex string to a TokenID -func FromString(hexStr string) (TokenID, error) { +// TokenIDFromString converts given hex string to a TokenID +func TokenIDFromString(hexStr string) (TokenID, error) { tokenIDBytes, err := hexutil.Decode(hexStr) if err != nil { return NewTokenID(), err @@ -54,10 +53,21 @@ func (t TokenID) String() string { return hexutil.Encode(t[:]) } +// MintNFTRequest holds required fields for minting NFT +type MintNFTRequest struct { + DocumentID []byte + RegistryAddress common.Address + DepositAddress common.Address + ProofFields []string + GrantNFTReadAccess bool + SubmitTokenProof bool + SubmitNFTReadAccessProof bool +} + // PaymentObligation handles transactions related to minting of NFTs type PaymentObligation interface { // MintNFT mints an NFT - MintNFT(ctx context.Context, documentID []byte, registryAddress, depositAddress string, proofFields []string) (*MintNFTResponse, chan bool, error) + MintNFT(ctx context.Context, request MintNFTRequest) (*MintNFTResponse, chan bool, error) } // MintNFTResponse holds tokenID and transaction ID. diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 819ea13d8..8f8ce8f8e 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -3,17 +3,28 @@ package nft_test import ( + "context" "os" "testing" + "time" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/invoice" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/golang/protobuf/ptypes/timestamp" + "github.com/stretchr/testify/assert" ) var registry *documents.ServiceRegistry @@ -37,72 +48,165 @@ func TestMain(m *testing.M) { os.Exit(result) } -//func TestPaymentObligationService_mint(t *testing.T) { -// // create identity -// log.Debug("Create Identity for Testing") -// cid := testingidentity.CreateIdentityWithKeys(cfg, idService) -// -// // create invoice (anchor) -// service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) -// assert.Nil(t, err, "should not error out when getting invoice service") -// ctx := testingconfig.CreateAccountContext(t, cfg) -// invoiceService := service.(invoice.Service) -// dueDate := time.Now().Add(4 * 24 * time.Hour) -// model, err := invoiceService.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ -// Collaborators: []string{}, -// Data: &invoicepb.InvoiceData{ -// InvoiceNumber: "2132131", -// GrossAmount: 123, -// NetAmount: 123, -// Currency: "EUR", -// DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, -// }, -// }) -// assert.Nil(t, err, "should not error out when creating invoice model") -// modelUpdated, txID, _, err := invoiceService.Create(ctx, model) -// err = txManager.WaitForTransaction(cid, txID) -// assert.Nil(t, err) -// -// // get ID -// ID, err := modelUpdated.ID() -// assert.Nil(t, err, "should not error out when getting invoice ID") -// // call mint -// // assert no error -// depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" -// registry := cfg.GetContractAddress(config.PaymentObligation) -// resp, done, err := payOb.MintNFT( -// ctx, -// ID, -// registry.String(), -// depositAddr, -// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}, -// ) -// assert.Nil(t, err, "should not error out when minting an invoice") -// assert.NotNil(t, resp.TokenID, "token id should be present") -// tokenID, err := nft.FromString(resp.TokenID) -// assert.Nil(t, err, "should not error out when getting tokenID hex") -// <-done -// assert.NoError(t, txManager.WaitForTransaction(cid, uuid.Must(uuid.FromString(resp.TransactionID)))) -// owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) -// assert.NoError(t, err) -// assert.Equal(t, common.HexToAddress(depositAddr), owner) -// doc, err := invoiceService.GetCurrentVersion(ctx, ID) -// assert.NoError(t, err) -// cd, err := doc.PackCoreDocument() -// assert.NoError(t, err) -// assert.Len(t, cd.Roles, 2) -// assert.Len(t, cd.Roles[1].Nfts, 1) -// newNFT := cd.Roles[1].Nfts[0] -// enft, err := coredocument.ConstructNFT(registry, tokenID.BigInt().Bytes()) -// assert.NoError(t, err) -// assert.Equal(t, enft, newNFT) -// -// // try to mint the NFT again -// _, _, err = payOb.MintNFT(ctx, -// ID, -// registry.String(), -// depositAddr, -// []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "collaborators[0]"}) -// assert.Error(t, err) -// assert.True(t, errors.IsOfType(nft.ErrNFTMinted, err)) -//} +func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address, string, documents.Service, identity.CentID) { + // create identity + log.Debug("Create Identity for Testing") + cid := testingidentity.CreateIdentityWithKeys(cfg, idService) + + // create invoice (anchor) + service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) + assert.Nil(t, err, "should not error out when getting invoice service") + ctx := testingconfig.CreateAccountContext(t, cfg) + invSrv := service.(invoice.Service) + dueDate := time.Now().Add(4 * 24 * time.Hour) + model, err := invSrv.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ + Collaborators: []string{}, + Data: &invoicepb.InvoiceData{ + InvoiceNumber: "2132131", + GrossAmount: 123, + NetAmount: 123, + Currency: "EUR", + DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, + }, + }) + assert.Nil(t, err, "should not error out when creating invoice model") + modelUpdated, txID, _, err := invSrv.Create(ctx, model) + err = txManager.WaitForTransaction(cid, txID) + assert.Nil(t, err) + + // get ID + id, err := modelUpdated.ID() + assert.Nil(t, err, "should not error out when getting invoice ID") + // call mint + // assert no error + depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" + registry := cfg.GetContractAddress(config.PaymentObligation) + + return ctx, id, registry, depositAddr, invSrv, cid +} + +func mintNFT(t *testing.T, ctx context.Context, req nft.MintNFTRequest, cid identity.CentID, registry common.Address) nft.TokenID { + resp, done, err := payOb.MintNFT(ctx, req) + assert.Nil(t, err, "should not error out when minting an invoice") + assert.NotNil(t, resp.TokenID, "token id should be present") + tokenID, err := nft.TokenIDFromString(resp.TokenID) + assert.Nil(t, err, "should not error out when getting tokenID hex") + <-done + txID, err := transactions.FromString(resp.TransactionID) + assert.NoError(t, err) + assert.NoError(t, txManager.WaitForTransaction(cid, txID)) + owner, err := tokenRegistry.OwnerOf(registry, tokenID.BigInt().Bytes()) + assert.NoError(t, err) + assert.Equal(t, req.DepositAddress, owner) + return tokenID +} + +func TestPaymentObligationService_mint_grant_read_access(t *testing.T) { + t.SkipNow() + ctx, id, registry, depositAddr, invSrv, cid := prepareForNFTMinting(t) + req := nft.MintNFTRequest{ + DocumentID: id, + RegistryAddress: registry, + DepositAddress: common.HexToAddress(depositAddr), + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date"}, + GrantNFTReadAccess: true, + } + tokenID := mintNFT(t, ctx, req, cid, registry) + doc, err := invSrv.GetCurrentVersion(ctx, id) + assert.NoError(t, err) + md, err := doc.PackCoreDocument() + assert.NoError(t, err) + cd := md.Document + assert.Len(t, cd.Roles, 2) + assert.Len(t, cd.Roles[1].Nfts, 1) + newNFT := cd.Roles[1].Nfts[0] + enft, err := documents.ConstructNFT(registry, tokenID.BigInt().Bytes()) + assert.NoError(t, err) + assert.Equal(t, enft, newNFT) + + // try to mint the NFT again + _, _, err = payOb.MintNFT(ctx, req) + assert.Error(t, err) + assert.True(t, errors.IsOfType(nft.ErrNFTMinted, err)) +} + +func failMintNFT(t *testing.T, grantNFT, nftReadAccess bool) { + ctx, id, registry, depositAddr, _, _ := prepareForNFTMinting(t) + req := nft.MintNFTRequest{ + DocumentID: id, + RegistryAddress: registry, + DepositAddress: common.HexToAddress(depositAddr), + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date"}, + GrantNFTReadAccess: grantNFT, + SubmitNFTReadAccessProof: nftReadAccess, + } + + _, _, err := payOb.MintNFT(ctx, req) + assert.Error(t, err) + if !nftReadAccess { + assert.True(t, errors.IsOfType(documents.ErrNFTRoleMissing, err)) + } +} + +func TestEthereumPaymentObligation_MintNFT_no_grant_access(t *testing.T) { + t.SkipNow() + failMintNFT(t, false, true) +} + +func mintNFTWithProofs(t *testing.T, grantAccess, tokenProof, readAccessProof bool) { + ctx, id, registry, depositAddr, invSrv, cid := prepareForNFTMinting(t) + req := nft.MintNFTRequest{ + DocumentID: id, + RegistryAddress: registry, + DepositAddress: common.HexToAddress(depositAddr), + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "next_version"}, + GrantNFTReadAccess: grantAccess, + SubmitTokenProof: tokenProof, + SubmitNFTReadAccessProof: readAccessProof, + } + mintNFT(t, ctx, req, cid, registry) + doc, err := invSrv.GetCurrentVersion(ctx, id) + assert.NoError(t, err) + cd, err := doc.PackCoreDocument() + assert.NoError(t, err) + roleCount := 1 + if grantAccess { + roleCount++ + } + assert.Len(t, cd.Document.Roles, roleCount) +} + +func TestEthereumPaymentObligation_MintNFT(t *testing.T) { + t.SkipNow() + tests := []struct { + grantAccess, tokenProof, readAccessProof bool + }{ + { + grantAccess: true, + }, + + { + tokenProof: true, + }, + + { + grantAccess: true, + tokenProof: true, + }, + + { + grantAccess: true, + readAccessProof: true, + }, + + { + grantAccess: true, + tokenProof: true, + readAccessProof: true, + }, + } + + for _, c := range tests { + mintNFTWithProofs(t, c.grantAccess, c.tokenProof, c.readAccessProof) + } +} diff --git a/protobufs/gen/go/nft/service.pb.go b/protobufs/gen/go/nft/service.pb.go index a6163d15d..000415180 100644 --- a/protobufs/gen/go/nft/service.pb.go +++ b/protobufs/gen/go/nft/service.pb.go @@ -36,7 +36,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_15c9f80dd06d1ac1, []int{0} + return fileDescriptor_service_10e4a4ecba67c7da, []int{0} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -67,9 +67,15 @@ type NFTMintRequest struct { // Document identifier Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` // The contract address of the registry where the token should be minted - RegistryAddress string `protobuf:"bytes,2,opt,name=registry_address,json=registryAddress,proto3" json:"registry_address,omitempty"` - DepositAddress string `protobuf:"bytes,3,opt,name=deposit_address,json=depositAddress,proto3" json:"deposit_address,omitempty"` - ProofFields []string `protobuf:"bytes,4,rep,name=proof_fields,json=proofFields,proto3" json:"proof_fields,omitempty"` + RegistryAddress string `protobuf:"bytes,2,opt,name=registry_address,json=registryAddress,proto3" json:"registry_address,omitempty"` + DepositAddress string `protobuf:"bytes,3,opt,name=deposit_address,json=depositAddress,proto3" json:"deposit_address,omitempty"` + ProofFields []string `protobuf:"bytes,4,rep,name=proof_fields,json=proofFields,proto3" json:"proof_fields,omitempty"` + // proof that nft is part of document + SubmitTokenProof bool `protobuf:"varint,5,opt,name=submit_token_proof,json=submitTokenProof,proto3" json:"submit_token_proof,omitempty"` + // proof that nft owner can access the document if nft_grant_access is true + SubmitNftOwnerAccessProof bool `protobuf:"varint,7,opt,name=submit_nft_owner_access_proof,json=submitNftOwnerAccessProof,proto3" json:"submit_nft_owner_access_proof,omitempty"` + // grant nft read access to the document + GrantNftAccess bool `protobuf:"varint,8,opt,name=grant_nft_access,json=grantNftAccess,proto3" json:"grant_nft_access,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -79,7 +85,7 @@ func (m *NFTMintRequest) Reset() { *m = NFTMintRequest{} } func (m *NFTMintRequest) String() string { return proto.CompactTextString(m) } func (*NFTMintRequest) ProtoMessage() {} func (*NFTMintRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_15c9f80dd06d1ac1, []int{1} + return fileDescriptor_service_10e4a4ecba67c7da, []int{1} } func (m *NFTMintRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintRequest.Unmarshal(m, b) @@ -127,6 +133,27 @@ func (m *NFTMintRequest) GetProofFields() []string { return nil } +func (m *NFTMintRequest) GetSubmitTokenProof() bool { + if m != nil { + return m.SubmitTokenProof + } + return false +} + +func (m *NFTMintRequest) GetSubmitNftOwnerAccessProof() bool { + if m != nil { + return m.SubmitNftOwnerAccessProof + } + return false +} + +func (m *NFTMintRequest) GetGrantNftAccess() bool { + if m != nil { + return m.GrantNftAccess + } + return false +} + type NFTMintResponse struct { Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` TokenId string `protobuf:"bytes,2,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` @@ -139,7 +166,7 @@ func (m *NFTMintResponse) Reset() { *m = NFTMintResponse{} } func (m *NFTMintResponse) String() string { return proto.CompactTextString(m) } func (*NFTMintResponse) ProtoMessage() {} func (*NFTMintResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_15c9f80dd06d1ac1, []int{2} + return fileDescriptor_service_10e4a4ecba67c7da, []int{2} } func (m *NFTMintResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NFTMintResponse.Unmarshal(m, b) @@ -251,34 +278,39 @@ var _NFTService_serviceDesc = grpc.ServiceDesc{ Metadata: "nft/service.proto", } -func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_15c9f80dd06d1ac1) } - -var fileDescriptor_service_15c9f80dd06d1ac1 = []byte{ - // 410 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0x87, 0xe5, 0x86, 0x36, 0x74, 0x52, 0x92, 0xb2, 0x70, 0x08, 0x11, 0x42, 0x8b, 0x25, 0x20, - 0xfc, 0x69, 0x2c, 0x95, 0x03, 0x12, 0xb7, 0x14, 0x64, 0xd1, 0x03, 0x51, 0x65, 0x72, 0x81, 0x4b, - 0xb4, 0xf5, 0xce, 0x9a, 0x15, 0xcd, 0xac, 0xd9, 0x9d, 0x50, 0x71, 0x45, 0xe2, 0x05, 0xe0, 0x21, - 0x78, 0x20, 0x5e, 0x81, 0x07, 0x41, 0x5e, 0xa7, 0x55, 0xa3, 0x9e, 0x2c, 0x7f, 0xfa, 0x76, 0xe6, - 0x37, 0x33, 0x70, 0x9b, 0x0c, 0x67, 0x01, 0xfd, 0x37, 0x5b, 0xe2, 0xa4, 0xf6, 0x8e, 0x9d, 0xe8, - 0x90, 0xe1, 0xd1, 0xfd, 0xca, 0xb9, 0xea, 0x0c, 0x33, 0x55, 0xdb, 0x4c, 0x11, 0x39, 0x56, 0x6c, - 0x1d, 0x85, 0x56, 0x19, 0xbd, 0x88, 0x9f, 0xf2, 0xa0, 0x42, 0x3a, 0x08, 0xe7, 0xaa, 0xaa, 0xd0, - 0x67, 0xae, 0x8e, 0xc6, 0x75, 0x3b, 0x7d, 0x05, 0xfd, 0x02, 0x43, 0xed, 0x28, 0xe0, 0x3b, 0x54, - 0x1a, 0xbd, 0x78, 0x04, 0x7d, 0xf6, 0x8a, 0x82, 0x2a, 0x1b, 0x6f, 0x61, 0xf5, 0x70, 0x5b, 0x26, - 0xe3, 0xdd, 0xe2, 0xd6, 0x15, 0x7a, 0xac, 0xd3, 0x3f, 0x09, 0xf4, 0x67, 0xf9, 0xfc, 0xbd, 0x25, - 0x2e, 0xf0, 0xeb, 0x0a, 0x03, 0x8b, 0x07, 0x00, 0x56, 0x23, 0xb1, 0x35, 0x16, 0xfd, 0x30, 0x89, - 0xaf, 0xae, 0x10, 0xf1, 0x14, 0xf6, 0x3d, 0x56, 0x36, 0xb0, 0xff, 0xbe, 0x50, 0x5a, 0x7b, 0x0c, - 0x61, 0xb8, 0x15, 0xad, 0xc1, 0x05, 0x9f, 0xb6, 0x58, 0x3c, 0x81, 0x81, 0xc6, 0xda, 0x05, 0xcb, - 0x97, 0x66, 0x27, 0x9a, 0xfd, 0x35, 0xbe, 0x10, 0x1f, 0xc2, 0x5e, 0xed, 0x9d, 0x33, 0x0b, 0x63, - 0xf1, 0x4c, 0x87, 0xe1, 0x0d, 0xd9, 0x19, 0xef, 0x16, 0xbd, 0xc8, 0xf2, 0x88, 0xd2, 0x8f, 0x30, - 0xb8, 0x0c, 0xda, 0x4e, 0x2a, 0x9e, 0xc3, 0xce, 0xe7, 0x38, 0x6d, 0x4c, 0xd9, 0x3b, 0xbc, 0x33, - 0x21, 0xc3, 0x93, 0xcd, 0x45, 0x14, 0x6b, 0x45, 0xdc, 0x83, 0x9b, 0xec, 0xbe, 0x60, 0x5c, 0x45, - 0x1b, 0xb7, 0x1b, 0xff, 0x8f, 0xf5, 0xe1, 0xcf, 0x04, 0x60, 0x96, 0xcf, 0x3f, 0xb4, 0x37, 0x12, - 0xe7, 0xd0, 0x6d, 0xda, 0xcc, 0xf2, 0xb9, 0x68, 0x2b, 0x6e, 0x2e, 0x68, 0x74, 0x77, 0x13, 0xb6, - 0xdd, 0xd2, 0xe9, 0xaf, 0xe9, 0x78, 0xf4, 0xb8, 0x41, 0x52, 0x91, 0x9c, 0xe5, 0x73, 0x69, 0xbc, - 0x5b, 0x4a, 0x25, 0xdf, 0x20, 0xb1, 0xb7, 0x66, 0x55, 0xa1, 0x7c, 0xeb, 0xca, 0xd5, 0x12, 0x89, - 0x7f, 0xfc, 0xfd, 0xf7, 0x7b, 0x6b, 0x3f, 0xed, 0x65, 0x31, 0x41, 0xb6, 0xb4, 0xc4, 0xaf, 0x93, - 0x67, 0x47, 0x12, 0xba, 0xa5, 0x5b, 0x36, 0xd5, 0x8f, 0xf6, 0xd6, 0x61, 0x4e, 0x9a, 0xf3, 0x9e, - 0x24, 0x9f, 0xb6, 0xc9, 0x70, 0x7d, 0x7a, 0xba, 0x13, 0xcf, 0xfd, 0xf2, 0x7f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xbb, 0x61, 0xbb, 0x11, 0x54, 0x02, 0x00, 0x00, +func init() { proto.RegisterFile("nft/service.proto", fileDescriptor_service_10e4a4ecba67c7da) } + +var fileDescriptor_service_10e4a4ecba67c7da = []byte{ + // 484 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xc1, 0x6e, 0x13, 0x3d, + 0x10, 0x80, 0x95, 0xe4, 0x6f, 0x93, 0x3a, 0xfd, 0x93, 0x60, 0x38, 0xa4, 0x11, 0xa0, 0x25, 0x12, + 0x10, 0xa0, 0xcd, 0x4a, 0xe5, 0x80, 0xc4, 0x89, 0x14, 0x14, 0xd1, 0x03, 0x4b, 0xb4, 0xe4, 0x02, + 0x97, 0x95, 0xb3, 0x1e, 0x2f, 0x16, 0xcd, 0x78, 0xb1, 0x27, 0x44, 0x5c, 0x91, 0x78, 0x01, 0x78, + 0x22, 0x9e, 0x81, 0x57, 0xe0, 0x41, 0xd0, 0xda, 0xdb, 0xaa, 0x11, 0xa7, 0xd5, 0x7e, 0xf3, 0xcd, + 0xd8, 0x9e, 0x19, 0x76, 0x03, 0x15, 0xc5, 0x0e, 0xec, 0x17, 0x9d, 0xc3, 0xb4, 0xb4, 0x86, 0x0c, + 0x6f, 0xa1, 0xa2, 0xd1, 0xed, 0xc2, 0x98, 0xe2, 0x02, 0x62, 0x51, 0xea, 0x58, 0x20, 0x1a, 0x12, + 0xa4, 0x0d, 0xba, 0xa0, 0x8c, 0x8e, 0xfd, 0x27, 0x3f, 0x29, 0x00, 0x4f, 0xdc, 0x56, 0x14, 0x05, + 0xd8, 0xd8, 0x94, 0xde, 0xf8, 0xd7, 0x1e, 0x3f, 0x63, 0xbd, 0x14, 0x5c, 0x69, 0xd0, 0xc1, 0x6b, + 0x10, 0x12, 0x2c, 0xbf, 0xcf, 0x7a, 0x64, 0x05, 0x3a, 0x91, 0x57, 0x5e, 0xa6, 0xe5, 0x70, 0x2f, + 0x6a, 0x4c, 0x0e, 0xd2, 0xff, 0xaf, 0xd1, 0x73, 0x39, 0xfe, 0xd5, 0x64, 0xbd, 0x64, 0xbe, 0x7c, + 0xa3, 0x91, 0x52, 0xf8, 0xbc, 0x01, 0x47, 0xfc, 0x2e, 0x63, 0x5a, 0x02, 0x92, 0x56, 0x1a, 0xec, + 0xb0, 0xe1, 0xb3, 0xae, 0x11, 0xfe, 0x88, 0x0d, 0x2c, 0x14, 0xda, 0x91, 0xfd, 0x9a, 0x09, 0x29, + 0x2d, 0x38, 0x37, 0x6c, 0x7a, 0xab, 0x7f, 0xc9, 0x67, 0x01, 0xf3, 0x87, 0xac, 0x2f, 0xa1, 0x34, + 0x4e, 0xd3, 0x95, 0xd9, 0xf2, 0x66, 0xaf, 0xc6, 0x97, 0xe2, 0x3d, 0x76, 0x58, 0x5a, 0x63, 0x54, + 0xa6, 0x34, 0x5c, 0x48, 0x37, 0xfc, 0x2f, 0x6a, 0x4d, 0x0e, 0xd2, 0xae, 0x67, 0x73, 0x8f, 0xf8, + 0x31, 0xe3, 0x6e, 0xb3, 0x5a, 0x6b, 0xca, 0xc8, 0x7c, 0x02, 0xcc, 0x7c, 0xcc, 0x3f, 0xaa, 0x93, + 0x0e, 0x42, 0x64, 0x59, 0x05, 0x16, 0x15, 0xe7, 0x2f, 0xd8, 0x9d, 0xda, 0x46, 0x45, 0x99, 0xd9, + 0x22, 0xd8, 0x4c, 0xe4, 0x39, 0x38, 0x57, 0x27, 0xb6, 0x7d, 0xe2, 0x51, 0x90, 0x12, 0x45, 0x6f, + 0x2b, 0x65, 0xe6, 0x8d, 0x50, 0x61, 0xc2, 0x06, 0x85, 0x15, 0x18, 0x0a, 0x84, 0xd4, 0x61, 0xc7, + 0x27, 0xf5, 0x3c, 0x4f, 0x14, 0x05, 0x7d, 0xfc, 0x9e, 0xf5, 0xaf, 0x5a, 0x18, 0x66, 0xc0, 0x9f, + 0xb0, 0xfd, 0x8f, 0x7e, 0x0e, 0xbe, 0x7f, 0xdd, 0xd3, 0x9b, 0x53, 0x54, 0x34, 0xdd, 0x1d, 0x51, + 0x5a, 0x2b, 0xfc, 0x88, 0x75, 0xc2, 0x93, 0xb4, 0xac, 0x1b, 0xd9, 0xf6, 0xff, 0xe7, 0xf2, 0xf4, + 0x7b, 0x83, 0xb1, 0x64, 0xbe, 0x7c, 0x17, 0xb6, 0x87, 0x6f, 0x59, 0xbb, 0x3a, 0x26, 0x99, 0x2f, + 0x79, 0xa8, 0xb8, 0x3b, 0xba, 0xd1, 0xad, 0x5d, 0x18, 0x4e, 0x1b, 0xcf, 0x7e, 0xcc, 0x26, 0xa3, + 0x07, 0x15, 0x8a, 0x04, 0x46, 0xc9, 0x7c, 0x19, 0x29, 0x6b, 0xd6, 0x91, 0x88, 0x5e, 0x02, 0x92, + 0xd5, 0x6a, 0x53, 0x40, 0xf4, 0xca, 0xe4, 0x9b, 0x35, 0x20, 0x7d, 0xfb, 0xfd, 0xe7, 0x67, 0x73, + 0x30, 0xee, 0xc6, 0xfe, 0x06, 0xf1, 0x5a, 0x23, 0x3d, 0x6f, 0x3c, 0x3e, 0x8b, 0x58, 0x3b, 0x37, + 0xeb, 0xaa, 0xfa, 0xd9, 0x61, 0x7d, 0x99, 0x45, 0xb5, 0x78, 0x8b, 0xc6, 0x87, 0x3d, 0x54, 0x54, + 0xae, 0x56, 0xfb, 0x7e, 0x11, 0x9f, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xdb, 0x53, 0x5a, + 0xee, 0x02, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index cf8024866..6582c8058 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/nft/service.swagger.json b/protobufs/gen/swagger/nft/service.swagger.json index 86836a122..4f7e4bdfc 100644 --- a/protobufs/gen/swagger/nft/service.swagger.json +++ b/protobufs/gen/swagger/nft/service.swagger.json @@ -63,6 +63,21 @@ "items": { "type": "string" } + }, + "submit_token_proof": { + "type": "boolean", + "format": "boolean", + "title": "proof that nft is part of document" + }, + "submit_nft_owner_access_proof": { + "type": "boolean", + "format": "boolean", + "title": "proof that nft owner can access the document if nft_grant_access is true" + }, + "grant_nft_access": { + "type": "boolean", + "format": "boolean", + "title": "grant nft read access to the document" } } }, diff --git a/protobufs/nft/service.proto b/protobufs/nft/service.proto index a0c8315c2..4a7ed6021 100644 --- a/protobufs/nft/service.proto +++ b/protobufs/nft/service.proto @@ -34,6 +34,12 @@ message NFTMintRequest { string registry_address = 2; string deposit_address = 3; repeated string proof_fields = 4; + // proof that nft is part of document + bool submit_token_proof = 5; + // proof that nft owner can access the document if nft_grant_access is true + bool submit_nft_owner_access_proof = 7; + // grant nft read access to the document + bool grant_nft_access = 8; } message NFTMintResponse { diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 78f8ef565..83cc29180 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -7,15 +7,53 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/config" - "github.com/stretchr/testify/assert" ) -// -//func TestPaymentObligationMint_invoice_successful(t *testing.T) { -// t.Parallel() -// paymentObligationMint(t, typeInvoice) -//} +func TestPaymentObligationMint_invoice_successful(t *testing.T) { + t.SkipNow() + t.Parallel() + tests := []struct { + name string + grantAccess, tokenProof, readAccessProof bool + }{ + { + name: "grant access", + grantAccess: true, + }, + + { + name: "token proof", + tokenProof: true, + }, + + { + name: "grant access and token proof", + grantAccess: true, + tokenProof: true, + }, + + { + name: "grant access and read access proof", + grantAccess: true, + readAccessProof: true, + }, + + { + name: "grant access, token proof and read access proof", + grantAccess: true, + tokenProof: true, + readAccessProof: true, + }, + } + + for _, c := range tests { + t.Run("", func(t *testing.T) { + t.Parallel() + paymentObligationMint(t, typeInvoice, c.grantAccess, c.tokenProof, c.readAccessProof) + }) + } +} /* TODO: testcase not stable func TestPaymentObligationMint_po_successful(t *testing.T) { @@ -24,7 +62,7 @@ func TestPaymentObligationMint_po_successful(t *testing.T) { } */ -func paymentObligationMint(t *testing.T, documentType string) { +func paymentObligationMint(t *testing.T, documentType string, grantNFTAccess, tokenProof, nftReadAccessProof bool) { alice := doctorFord.getHostTestSuite(t, "Alice") bob := doctorFord.getHostTestSuite(t, "Bob") @@ -59,10 +97,13 @@ func paymentObligationMint(t *testing.T, documentType string) { http.StatusOK, map[string]interface{}{ - "identifier": docIdentifier, - "registryAddress": doctorFord.getHost("Alice").config.GetContractAddress(config.PaymentObligation).String(), - "depositAddress": "0x44a0579754d6c94e7bb2c26bfa7394311cc50ccb", // Centrifuge address - "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", "collaborators[0]"}, + "identifier": docIdentifier, + "registryAddress": doctorFord.getHost("Alice").config.GetContractAddress(config.PaymentObligation).String(), + "depositAddress": "0x44a0579754d6c94e7bb2c26bfa7394311cc50ccb", // Centrifuge address + "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", "next_version"}, + "submitTokenProof": tokenProof, + "submitNftOwnerAccessProof": nftReadAccessProof, + "grantNftAccess": grantNFTAccess, }, } @@ -75,39 +116,40 @@ func paymentObligationMint(t *testing.T, documentType string) { } -//func TestPaymentObligationMint_errors(t *testing.T) { -// t.Parallel() -// alice := doctorFord.getHostTestSuite(t, "Alice") -// tests := []struct { -// errorMsg string -// httpStatus int -// payload map[string]interface{} -// }{ -// { -// -// "RegistryAddress is not a valid Ethereum address", -// http.StatusInternalServerError, -// map[string]interface{}{ -// -// "registryAddress": "0x123", -// }, -// }, -// { -// "DepositAddress is not a valid Ethereum address", -// http.StatusInternalServerError, -// map[string]interface{}{ -// -// "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address -// "depositAddress": "abc", -// }, -// }, -// } -// for _, test := range tests { -// t.Run(test.errorMsg, func(t *testing.T) { -// t.Parallel() -// response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) -// assert.Nil(t, err, "it should be possible to call the API endpoint") -// response.Value("error").String().Contains(test.errorMsg) -// }) -// } -//} +func TestPaymentObligationMint_errors(t *testing.T) { + t.SkipNow() + t.Parallel() + alice := doctorFord.getHostTestSuite(t, "Alice") + tests := []struct { + errorMsg string + httpStatus int + payload map[string]interface{} + }{ + { + + "RegistryAddress is not a valid Ethereum address", + http.StatusInternalServerError, + map[string]interface{}{ + + "registryAddress": "0x123", + }, + }, + { + "DepositAddress is not a valid Ethereum address", + http.StatusInternalServerError, + map[string]interface{}{ + + "registryAddress": "0xf72855759a39fb75fc7341139f5d7a3974d4da08", //dummy address + "depositAddress": "abc", + }, + }, + } + for _, test := range tests { + t.Run(test.errorMsg, func(t *testing.T) { + t.Parallel() + response, err := alice.host.mintNFT(alice.httpExpect, alice.id.String(), test.httpStatus, test.payload) + assert.Nil(t, err, "it should be possible to call the API endpoint") + response.Value("error").String().Contains(test.errorMsg) + }) + } +} From 3b8eeee82e689588327e1bf5b65db08017084323 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Thu, 21 Feb 2019 18:33:10 +0100 Subject: [PATCH 196/220] Update protobufs (#765) * Update protobufs * test --- Gopkg.lock | 4 ++-- Gopkg.toml | 2 +- documents/processor_test.go | 1 + p2p/doc.go | 5 +++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 4cbf3b520..d85ee8fef 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" [[projects]] - digest = "1:dfe1a0223d1205b5d387f9409d72e88877c7470c79930dd00da6d63f4b0af963" + digest = "1:3dfab93e13cbc54458ddd94ac88c0f01eb724b28a7dd3eef5923903d1fe71cef" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "5615ef01001f185e1ecbe10eb9604b5eeaae0b04" + revision = "3e3292cf89ce246d64863fa28ac1f4cb4e57dd3e" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 041ada96f..64a5fd890 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "5615ef01001f185e1ecbe10eb9604b5eeaae0b04" + revision = "3e3292cf89ce246d64863fa28ac1f4cb4e57dd3e" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/processor_test.go b/documents/processor_test.go index eae2130b7..fbcfe8960 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -50,6 +50,7 @@ func (m mockModel) CalculateDataRoot() ([]byte, error) { func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { srv := &testingcommons.MockIDService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) + // pack failed model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() diff --git a/p2p/doc.go b/p2p/doc.go index f80d26ba5..ace471588 100644 --- a/p2p/doc.go +++ b/p2p/doc.go @@ -4,7 +4,8 @@ network to communicate about various protocol activities such as document consen Background -In order to understand the design decisions behind the protocol one needs a quick background on libp2p and protobufs the tech stack used by the initial implementation of the protocol - `go-centrifuge`, though the wire protocol it self is independant of this stack. +In order to understand the design decisions behind the protocol one needs a quick background on libp2p and protobufs the tech stack used by the initial implementation of the protocol - `go-centrifuge`, though the wire protocol it self is independent +of this stack. - Libp2p protocol multiplexing @@ -23,7 +24,7 @@ The Protocol 1. Protocol Identifier -Centrifuge wire protocol uses libp2p protocol multiplexing as a way to differenciate protocol versions as well as the centrifuge ID that a particular message is targetted at in the centrifuge node. +Centrifuge wire protocol uses libp2p protocol multiplexing as a way to differentiate protocol versions as well as the centrifuge ID that a particular message is targeted at in the centrifuge node. i.e. at the start of the node protocol handlers are registered for each protocol version for each `centrifugeID` configured in the system. Given this requirement a centrifuge protocol identifier string must comply to the following format, `/centrifuge//` Eg: `/centrifuge/0.0.1/0xf71876181dce` From f99ab737ce474dfddc8d084a9d7f6cb640050196 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Mon, 25 Feb 2019 15:05:26 +0100 Subject: [PATCH 197/220] Identity 1.2 (#775) * identity migration: update to latest contracts (#748) * use new identity contracts * removed registry from config * removed helper functions * identity migrate cmd package * formatting * identity migration: new package structure (#749) * use new identity contracts * removed registry from config * removed helper functions * identity migrate cmd package * formatting * fixed changes * package changed * moved did service interface * fixed tests in ideth package * added did.go * fixed cmd package (#750) * identity migration: mockService and boostrapper document service (#751) * fixed cmd package * added mock did service and did service to documents bootstrapper * fixed document bootstrapper * removed old service from document bootstrapper * identity migration: documents (#757) * fixed cmd package * added mock did service and did service to documents bootstrapper * fixed document bootstrapper * removed old service from document bootstrapper * migration identity replaced validators * fixed selfSignatureValidator test * fixed signature Validator * documents unit test fixed * fixed tests for invoice and purchaseorder * formatting * Identity (#758) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * fix documents/invoice * fix po tests * comments * fix cmd * Fix unit tests except oldID + anchor and linting (#761) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * fix documents/invoice * fix po tests * comments * fix cmd * fmt + fix all unit tests except anchor+oldID * fix unit tests * swagger * Id migration: new anchoring (#763) * removed old anchor contract * fixed unit tests * updated anchor methods * fixed integration test anchor commit * removed event listener task from anchor * anchor passing uuid * fixed anchoring integration test * added channel as return * added integration test for anchoring * fixed identity tests * fixed unit tests * formatting * WIP: Fix integration tests (#764) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * fix documents/invoice * fix po tests * comments * fix cmd * fmt + fix all unit tests except anchor+oldID * fix unit tests * swagger * compilation error fix integration * keys * test * integration * fix integration tests * fix unit tests * Merged develop (#767) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * Converting TX API to use Hex strings (#754) * Converting TX API to use Hex strings * test * comment * fix tests * fix documents/invoice * fix po tests * comments * fix cmd * fmt + fix all unit tests except anchor+oldID * hash instead of copying the message (#759) Hash the message before signing * Report card * fix unit tests * NFT uniqeness proofs (#736) Add NFT proofs - Uniqueness proof - NFT read access proof More here - https://hackmd.io/ps0X0jRkRHaACP6aPtGzag * swagger * compilation error fix integration * keys * test * integration * fix integration tests * Update protobufs (#765) * Update protobufs * test * fix unit tests * revert migrations * fixed multi case identity address * nft in testworld uncomment * fixed unit tests in configstore * ID Comment Fixes (#772) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * Converting TX API to use Hex strings (#754) * Converting TX API to use Hex strings * test * comment * fix tests * fix documents/invoice * fix po tests * comments * fix cmd * fmt + fix all unit tests except anchor+oldID * hash instead of copying the message (#759) Hash the message before signing * Report card * fix unit tests * NFT uniqeness proofs (#736) Add NFT proofs - Uniqueness proof - NFT read access proof More here - https://hackmd.io/ps0X0jRkRHaACP6aPtGzag * swagger * compilation error fix integration * keys * test * integration * fix integration tests * Update protobufs (#765) * Update protobufs * test * fix unit tests * revert migrations * fix comments * fix comments * Add bytecode check (#774) * Refactor/nfts remove cd (#747) * config * p2p * Correct logs for transaction tasks (#753) * wip * fix p2p and config tests * Converting TX API to use Hex strings (#754) * Converting TX API to use Hex strings * test * comment * fix tests * fix documents/invoice * fix po tests * comments * fix cmd * fmt + fix all unit tests except anchor+oldID * hash instead of copying the message (#759) Hash the message before signing * Report card * fix unit tests * NFT uniqeness proofs (#736) Add NFT proofs - Uniqueness proof - NFT read access proof More here - https://hackmd.io/ps0X0jRkRHaACP6aPtGzag * swagger * compilation error fix integration * keys * test * integration * fix integration tests * Update protobufs (#765) * Update protobufs * test * fix unit tests * revert migrations * add bytecode check * add bytecode check * fixes * fixed testworld bytecode check * formatting * remove bytecode check * remove bin --- Gopkg.lock | 13 +- Gopkg.toml | 10 +- anchors/anchor.go | 14 +- anchors/anchor_confirmation_task.go | 200 ---- anchors/anchor_confirmation_task_test.go | 160 --- anchors/anchor_repository.go | 4 +- anchors/anchor_repository_integration_test.go | 82 +- anchors/bootstrapper.go | 29 +- anchors/ethereum_anchor_repository.go | 224 ---- .../ethereum_anchor_repository_contract.go | 629 ----------- anchors/service.go | 157 +++ ...hor_repository_test.go => service_test.go} | 25 +- api/server_test.go | 5 +- bootstrap/bootstrappers/bootstrapper.go | 8 +- .../testingbootstrap/testing_bootstrap.go | 4 +- build/configs/default_config.yaml | 18 +- build/configs/testing_config.yaml | 2 +- cmd/centrifuge/create_config.go | 5 +- cmd/centrifuge/manage_identities.go | 62 +- cmd/centrifuge_cmd_test.go | 3 +- cmd/common.go | 126 +-- cmd/common_test.go | 29 +- config/configstore/bootstrapper.go | 8 +- config/configstore/handler_test.go | 16 +- config/configstore/model.go | 114 +- config/configstore/model_test.go | 20 +- config/configstore/repository_test.go | 3 +- config/configstore/service.go | 45 +- .../configstore/service_integration_test.go | 25 +- config/configstore/service_test.go | 20 +- config/configuration.go | 29 +- crypto/sign.go | 7 +- crypto/verify_test.go | 4 +- documents/anchor.go | 2 +- documents/anchor_task.go | 10 +- documents/anchor_task_test.go | 4 +- documents/bootstrapper.go | 17 +- documents/bootstrapper_test.go | 6 +- documents/documents_test/anchor_test.go | 2 +- documents/documents_test/service_test.go | 34 +- documents/invoice/model.go | 33 +- documents/invoice/model_test.go | 51 +- documents/invoice/service.go | 11 +- documents/invoice/service_test.go | 31 +- documents/invoice/utils_test.go | 2 + documents/model.go | 37 +- documents/model_test.go | 75 +- documents/processor.go | 33 +- documents/processor_test.go | 51 +- documents/purchaseorder/model.go | 11 +- documents/purchaseorder/model_test.go | 39 +- documents/purchaseorder/service.go | 13 +- documents/purchaseorder/service_test.go | 34 +- documents/purchaseorder/utils_test.go | 2 + documents/service.go | 14 +- documents/validator.go | 24 +- documents/validator_test.go | 20 +- ethereum/geth_client.go | 2 +- ethereum/geth_client_integration_test.go | 5 +- ethereum/transaction_status_task.go | 4 +- ...ransaction_status_task_integration_test.go | 8 +- ethereum/transaction_status_task_test.go | 9 +- identity/did.go | 312 ++++++ identity/did/bootstrapper.go | 179 ---- identity/did/key.go | 62 -- identity/ethid/bootstrapper.go | 69 -- identity/ethid/bootstrapper_test.go | 14 - identity/ethid/ethereum_identity.go | 573 ---------- identity/ethid/ethereum_identity_contract.go | 991 ------------------ .../ethereum_identity_factory_contract.go | 315 ------ .../ethereum_identity_integration_test.go | 147 --- .../ethereum_identity_registry_contract.go | 495 --------- identity/ethid/ethereum_identity_test.go | 423 -------- .../id_registration_confirmation_task.go | 124 --- .../id_registration_confirmation_task_test.go | 47 - .../key_registration_confirmation_task.go | 180 ---- ...key_registration_confirmation_task_test.go | 84 -- identity/ethid/test_bootstrapper.go | 11 - identity/ethid/util.go | 38 - identity/identity.go | 254 ----- identity/identity_test.go | 208 ---- identity/ideth/bootstrapper.go | 66 ++ identity/{did => ideth}/bootstrapper_test.go | 2 +- .../execute_integration_test.go | 25 +- identity/{did => ideth}/factory.go | 47 +- identity/{did => ideth}/factory_contract.go | 2 +- .../factory_integration_test.go | 15 +- identity/{did => ideth}/identity_contract.go | 2 +- identity/{did => ideth}/service.go | 237 ++--- .../service_integration_test.go | 35 +- identity/{did => ideth}/test_bootstrapper.go | 2 +- nft/bootstrapper.go | 2 +- nft/ethereum_payment_obligation.go | 15 +- nft/ethereum_payment_obligation_test.go | 11 +- nft/payment_obligation_integration_test.go | 22 +- p2p/bootstrapper.go | 2 +- p2p/bootstrapper_test.go | 6 +- p2p/client.go | 35 +- p2p/client_integration_test.go | 58 +- p2p/client_test.go | 59 +- p2p/common/protocol.go | 19 +- p2p/common/protocol_test.go | 16 +- p2p/messenger/messenger_test.go | 9 +- p2p/receiver/handler.go | 17 +- p2p/receiver/handler_integration_test.go | 152 +-- p2p/receiver/handler_test.go | 17 +- p2p/receiver/validator.go | 21 +- p2p/receiver/validator_test.go | 19 +- p2p/server.go | 13 +- p2p/server_test.go | 7 +- protobufs/config/service.proto | 1 + protobufs/gen/go/config/service.pb.go | 123 ++- protobufs/gen/swagger.json | 2 +- .../gen/swagger/config/service.swagger.json | 6 + resources/data.go | 8 +- testingutils/commons/mock_did_identity.go | 128 +++ testingutils/commons/mock_identity.go | 119 --- testingutils/documents/documents.go | 5 + testingutils/documents/invoice.go | 20 +- testingutils/documents/purchaseorder.go | 10 +- testingutils/identity/identity.go | 97 +- testingutils/setup.go | 4 +- testingutils/testingtx/mocktx.go | 10 +- testingutils/utils.go | 2 +- testworld/config_test.go | 1 + testworld/park.go | 27 +- testworld/start_test.go | 8 +- testworld/util.go | 108 -- transactions/transaction.go | 18 +- transactions/txv1/base_task.go | 2 +- transactions/txv1/base_task_test.go | 5 +- transactions/txv1/handler.go | 6 +- transactions/txv1/handler_test.go | 2 +- transactions/txv1/manager.go | 16 +- transactions/txv1/manager_test.go | 24 +- transactions/txv1/repository.go | 6 +- transactions/txv1/repository_test.go | 17 +- 137 files changed, 1951 insertions(+), 6967 deletions(-) delete mode 100644 anchors/anchor_confirmation_task.go delete mode 100644 anchors/anchor_confirmation_task_test.go delete mode 100644 anchors/ethereum_anchor_repository.go delete mode 100644 anchors/ethereum_anchor_repository_contract.go create mode 100644 anchors/service.go rename anchors/{ethereum_anchor_repository_test.go => service_test.go} (70%) create mode 100644 identity/did.go delete mode 100644 identity/did/bootstrapper.go delete mode 100644 identity/did/key.go delete mode 100644 identity/ethid/bootstrapper.go delete mode 100644 identity/ethid/bootstrapper_test.go delete mode 100644 identity/ethid/ethereum_identity.go delete mode 100644 identity/ethid/ethereum_identity_contract.go delete mode 100644 identity/ethid/ethereum_identity_factory_contract.go delete mode 100644 identity/ethid/ethereum_identity_integration_test.go delete mode 100644 identity/ethid/ethereum_identity_registry_contract.go delete mode 100644 identity/ethid/ethereum_identity_test.go delete mode 100644 identity/ethid/id_registration_confirmation_task.go delete mode 100644 identity/ethid/id_registration_confirmation_task_test.go delete mode 100644 identity/ethid/key_registration_confirmation_task.go delete mode 100644 identity/ethid/key_registration_confirmation_task_test.go delete mode 100644 identity/ethid/test_bootstrapper.go delete mode 100644 identity/ethid/util.go delete mode 100644 identity/identity.go delete mode 100644 identity/identity_test.go create mode 100644 identity/ideth/bootstrapper.go rename identity/{did => ideth}/bootstrapper_test.go (94%) rename identity/{did => ideth}/execute_integration_test.go (89%) rename identity/{did => ideth}/factory.go (71%) rename identity/{did => ideth}/factory_contract.go (99%) rename identity/{did => ideth}/factory_integration_test.go (87%) rename identity/{did => ideth}/identity_contract.go (99%) rename identity/{did => ideth}/service.go (57%) rename identity/{did => ideth}/service_integration_test.go (87%) rename identity/{did => ideth}/test_bootstrapper.go (93%) create mode 100644 testingutils/commons/mock_did_identity.go delete mode 100644 testingutils/commons/mock_identity.go delete mode 100644 testworld/util.go diff --git a/Gopkg.lock b/Gopkg.lock index d85ee8fef..4764a9e9a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,11 +57,11 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - digest = "1:4542fc4bb0f0bab4d9fad7bf85ca7152cf706eb0ccb1f501899f625af6865d34" + digest = "1:bedc0b304fccce285e74ebae57d61c4b190b1a420b0c07afb1d4c2da56d164b8" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" + revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" [[projects]] digest = "1:3dfab93e13cbc54458ddd94ac88c0f01eb724b28a7dd3eef5923903d1fe71cef" @@ -847,13 +847,6 @@ revision = "c2353362d570a7bfa228149c62842019201cfb71" version = "v1.8.0" -[[projects]] - digest = "1:bedc0b304fccce285e74ebae57d61c4b190b1a420b0c07afb1d4c2da56d164b8" - name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" - packages = ["."] - pruneopts = "T" - revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" - [[projects]] digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" name = "github.com/mattn/go-colorable" @@ -1545,10 +1538,10 @@ "github.com/libp2p/go-libp2p-peerstore", "github.com/libp2p/go-libp2p-protocol", "github.com/magiconair/properties/assert", - "github.com/manuelpolzhofer/centrifuge-ethereum-contracts", "github.com/mitchellh/go-homedir", "github.com/multiformats/go-multiaddr", "github.com/multiformats/go-multihash", + "github.com/pkg/errors", "github.com/roboll/go-vendorinstall", "github.com/satori/go.uuid", "github.com/savaki/jq", diff --git a/Gopkg.toml b/Gopkg.toml index 64a5fd890..6b3c9812d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -24,7 +24,7 @@ # go-tests = true # unused-packages = true -required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/manuelpolzhofer/centrifuge-ethereum-contracts", "github.com/roboll/go-vendorinstall", "github.com/golang/protobuf/protoc-gen-go", "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway", "golang.org/x/tools/cmd/goimports"] +required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/roboll/go-vendorinstall", "github.com/golang/protobuf/protoc-gen-go", "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway", "golang.org/x/tools/cmd/goimports"] [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" @@ -32,10 +32,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - revision = "978840734a4a2fccd5d8dc7e462d9108079c5b5d" - -[[override]] - name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" [[constraint]] @@ -270,10 +266,6 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts","github.com/ma name = "github.com/centrifuge/centrifuge-ethereum-contracts" unused-packages = false -[[prune.project]] - name = "github.com/manuelpolzhofer/centrifuge-ethereum-contracts" - unused-packages = false - [[prune.project]] name = "github.com/ethereum/go-ethereum" unused-packages = false diff --git a/anchors/anchor.go b/anchors/anchor.go index 6de125f13..ea75d1506 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -74,7 +74,7 @@ func RandomDocumentRoot() DocumentRoot { type PreCommitData struct { AnchorID AnchorID SigningRoot DocumentRoot - CentrifugeID identity.CentID + DID identity.DID Signature []byte ExpirationBlock *big.Int SchemaVersion uint @@ -85,9 +85,7 @@ type CommitData struct { BlockHeight uint64 AnchorID AnchorID DocumentRoot DocumentRoot - CentrifugeID identity.CentID DocumentProofs [][DocumentProofLength]byte - Signature []byte SchemaVersion uint } @@ -109,11 +107,11 @@ func supportedSchemaVersion() uint { } // newPreCommitData returns a PreCommitData with passed in details -func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.CentID, signature []byte, expirationBlock *big.Int) (preCommitData *PreCommitData) { +func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.DID, signature []byte, expirationBlock *big.Int) (preCommitData *PreCommitData) { return &PreCommitData{ AnchorID: anchorID, SigningRoot: signingRoot, - CentrifugeID: centrifugeID, + DID: centrifugeID, Signature: signature, ExpirationBlock: expirationBlock, SchemaVersion: supportedSchemaVersion(), @@ -121,19 +119,17 @@ func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID } // NewCommitData returns a CommitData with passed in details -func NewCommitData(blockHeight uint64, anchorID AnchorID, documentRoot DocumentRoot, centrifugeID identity.CentID, documentProofs [][32]byte, signature []byte) (commitData *CommitData) { +func NewCommitData(blockHeight uint64, anchorID AnchorID, documentRoot DocumentRoot, documentProofs [][32]byte) (commitData *CommitData) { return &CommitData{ BlockHeight: blockHeight, AnchorID: anchorID, DocumentRoot: documentRoot, - CentrifugeID: centrifugeID, DocumentProofs: documentProofs, - Signature: signature, } } // GenerateCommitHash generates Keccak256 message from AnchorID, CentID, DocumentRoot -func GenerateCommitHash(anchorID AnchorID, centrifugeID identity.CentID, documentRoot DocumentRoot) []byte { +func GenerateCommitHash(anchorID AnchorID, centrifugeID identity.DID, documentRoot DocumentRoot) []byte { msg := append(anchorID[:], documentRoot[:]...) msg = append(msg, centrifugeID[:]...) return crypto.Keccak256(msg) diff --git a/anchors/anchor_confirmation_task.go b/anchors/anchor_confirmation_task.go deleted file mode 100644 index 6b5e52993..000000000 --- a/anchors/anchor_confirmation_task.go +++ /dev/null @@ -1,200 +0,0 @@ -package anchors - -import ( - "context" - "math/big" - "time" - - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -const ( - anchorRepositoryConfirmationTaskName string = "anchorRepositoryConfirmationTaskName" - anchorIDParam string = "anchorIDParam" - centIDParam string = "centIDParam" - blockHeight string = "blockHeight" - addressParam string = "addressParam" -) - -type anchorCommittedWatcher interface { - FilterAnchorCommitted( - opts *bind.FilterOpts, - from []common.Address, - anchorID []*big.Int, - centID []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) -} - -// anchorConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumAnchoryRepositoryContract. -// To see how it gets registered see bootstrapper.go and to see how it gets used see setUpRegistrationEventListener method -type anchorConfirmationTask struct { - // task parameters - From common.Address - AnchorID AnchorID - CentrifugeID identity.CentID - BlockHeight uint64 - Timeout time.Duration - - // state - EthContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) - EthContext context.Context - AnchorCommittedFilterer anchorCommittedWatcher -} - -// TaskTypeName returns anchorRepositoryConfirmationTaskName -func (act *anchorConfirmationTask) TaskTypeName() string { - return anchorRepositoryConfirmationTaskName -} - -// Copy returns a new instance of anchorConfirmationTask -func (act *anchorConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &anchorConfirmationTask{ - act.From, - act.AnchorID, - act.CentrifugeID, - act.BlockHeight, - act.Timeout, - act.EthContextInitializer, - act.EthContext, - act.AnchorCommittedFilterer, - }, nil -} - -// ParseKwargs parses args to anchorConfirmationTask -func (act *anchorConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - anchorID, ok := kwargs[anchorIDParam] - if !ok { - return errors.New("undefined kwarg " + anchorIDParam) - } - - anchorIDBytes, err := getBytesAnchorID(anchorID) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", anchorIDParam, err.Error()) - } - - act.AnchorID = anchorIDBytes - - //parse the centrifuge id - centID, ok := kwargs[centIDParam] - if !ok { - return errors.New("undefined kwarg " + centIDParam) - } - - centIDBytes, err := getBytesCentrifugeID(centID) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) - } - - act.CentrifugeID = centIDBytes - - // parse the address - address, ok := kwargs[addressParam] - if !ok { - return errors.New("undefined kwarg " + addressParam) - } - - addressStr, ok := address.(string) - if !ok { - return errors.New("param is not hex string " + addressParam) - } - - addressTyped, err := getAddressFromHexString(addressStr) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", addressParam, err.Error()) - } - act.From = addressTyped - - if bhi, ok := kwargs[blockHeight]; ok { - bhf, ok := bhi.(float64) - if ok { - act.BlockHeight = uint64(bhf) - } - } - - // Override default timeout param - tdRaw, ok := kwargs[queue.TimeoutParam] - if ok { - td, err := queue.GetDuration(tdRaw) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) - } - act.Timeout = td - } - - return nil -} - -// RunTask calls listens to events from geth related to anchorConfirmationTask#AnchorID and records result. -func (act *anchorConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the anchorID [%x]", act.AnchorID) - if act.EthContext == nil { - act.EthContext, _ = act.EthContextInitializer(act.Timeout) - } - - fOpts := &bind.FilterOpts{ - Context: act.EthContext, - Start: act.BlockHeight, - } - - for { - iter, err := act.AnchorCommittedFilterer.FilterAnchorCommitted( - fOpts, - []common.Address{act.From}, - []*big.Int{act.AnchorID.BigInt()}, - []*big.Int{act.CentrifugeID.BigInt()}, - ) - if err != nil { - return nil, centerrors.Wrap(err, "failed to start filtering anchor event logs") - } - - err = utils.LookForEvent(iter) - if err == nil { - log.Infof("Received filtered event Anchor Confirmation for AnchorID [%x] and CentrifugeID [%s]\n", act.AnchorID.BigInt(), act.CentrifugeID.String()) - return iter.Event, nil - } - - if err != utils.ErrEventNotFound { - return nil, err - } - - time.Sleep(100 * time.Millisecond) - } -} - -func getBytesAnchorID(key interface{}) (AnchorID, error) { - var fixed [AnchorIDLength]byte - b, ok := key.([]interface{}) - if !ok { - return fixed, errors.New("Could not parse interface to []byte") - } - // convert and copy b byte values - for i, v := range b { - fv := v.(float64) - fixed[i] = byte(fv) - } - return fixed, nil -} - -func getBytesCentrifugeID(key interface{}) (identity.CentID, error) { - var fixed [identity.CentIDLength]byte - b, ok := key.([]interface{}) - if !ok { - return fixed, errors.New("Could not parse interface to []byte") - } - // convert and copy b byte values - for i, v := range b { - fv := v.(float64) - fixed[i] = byte(fv) - } - return fixed, nil -} - -func getAddressFromHexString(hex string) (common.Address, error) { - return common.BytesToAddress(common.FromHex(hex)), nil -} diff --git a/anchors/anchor_confirmation_task_test.go b/anchors/anchor_confirmation_task_test.go deleted file mode 100644 index 35f610abd..000000000 --- a/anchors/anchor_confirmation_task_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// +build unit - -package anchors - -import ( - "context" - "math/big" - "testing" - "time" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" -) - -type MockAnchorCommittedFilter struct { - iter *EthereumAnchorRepositoryContractAnchorCommittedIterator - err error -} - -func (m *MockAnchorCommittedFilter) FilterAnchorCommitted( - opts *bind.FilterOpts, - from []common.Address, - anchorID []*big.Int, - centrifugeID []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) { - - return m.iter, m.err -} - -func TestAnchoringConfirmationTask_ParseKwargsHappy(t *testing.T) { - act := anchorConfirmationTask{} - anchorID, _ := ToAnchorID(utils.RandomSlice(AnchorIDLength)) - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - - centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - timeout := float64(5000) - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - anchorIDParam: anchorID, - addressParam: address, - centIDParam: centId, - blockHeight: float64(0), - queue.TimeoutParam: timeout, - }) - err := act.ParseKwargs(kwargs) - if err != nil { - assert.Nil(t, err) - t.Fatalf("Could not parse %s or %s", anchorIDParam, addressParam) - } - - //convert byte 32 to big int - assert.Equal(t, anchorID, anchorID, "Resulting anchor Id should have the same ID as the input") - assert.Equal(t, address, act.From, "Resulting address should have the same ID as the input") - assert.Equal(t, centId, act.CentrifugeID, "Resulting centId should have the same centId as the input") - assert.Equal(t, time.Duration(timeout), act.Timeout, "Resulting timeout should have the same timeout as the input") -} - -func TestAnchoringConfirmationTask_ParseKwargsAnchorNotPassed(t *testing.T) { - act := anchorConfirmationTask{} - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - var centrifugeIdBytes [6]byte - - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - addressParam: address, - centIDParam: centrifugeIdBytes, - }) - err := act.ParseKwargs(kwargs) - assert.NotNil(t, err, "Anchor id should not have been parsed") -} - -func TestAnchoringConfirmationTask_ParseKwargsInvalidAnchor(t *testing.T) { - act := anchorConfirmationTask{} - anchorID := 123 - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - anchorIDParam: anchorID, - addressParam: address, - }) - err := act.ParseKwargs(kwargs) - assert.NotNil(t, err, "Anchor id should not have been parsed because it was of incorrect type") -} - -func TestAnchoringConfirmationTask_ParseKwargsAddressNotPassed(t *testing.T) { - act := anchorConfirmationTask{} - anchorID := [32]byte{1, 2, 3} - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - anchorIDParam: anchorID, - }) - err := act.ParseKwargs(kwargs) - assert.NotNil(t, err, "address should not have been parsed") -} - -func TestAnchoringConfirmationTask_ParseKwargsInvalidAddress(t *testing.T) { - act := anchorConfirmationTask{} - anchorID := [32]byte{1, 2, 3} - address := 123 - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - anchorIDParam: anchorID, - addressParam: address, - }) - err := act.ParseKwargs(kwargs) - assert.NotNil(t, err, "address should not have been parsed because it was of incorrect type") -} - -func TestAnchoringConfirmationTask_ParseKwargsInvalidTimeout(t *testing.T) { - act := anchorConfirmationTask{} - anchorID, _ := ToAnchorID(utils.RandomSlice(AnchorIDLength)) - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - - centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - timeout := "int64" - kwargs, _ := utils.SimulateJSONDecodeForGocelery(map[string]interface{}{ - anchorIDParam: anchorID, - addressParam: address, - centIDParam: centId, - blockHeight: float64(0), - queue.TimeoutParam: timeout, - }) - err := act.ParseKwargs(kwargs) - assert.NotNil(t, err, "timeout should not have been parsed because it was of incorrect type") -} - -func TestAnchoringConfirmationTask_RunTaskIterError(t *testing.T) { - anchorID := [32]byte{1, 2, 3} - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - act := anchorConfirmationTask{ - AnchorID: anchorID, - From: address, - AnchorCommittedFilterer: &MockAnchorCommittedFilter{err: errors.New("failed iterator")}, - EthContext: context.Background(), - } - - _, err := act.RunTask() - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "failed iterator") -} - -func TestAnchoringConfirmationTask_RunTaskWatchError(t *testing.T) { - toBeDone := time.Now().Add(time.Duration(1 * time.Millisecond)) - ctx, _ := context.WithDeadline(context.Background(), toBeDone) - anchorID := [32]byte{1, 2, 3} - address := common.BytesToAddress([]byte{1, 2, 3, 4}) - act := anchorConfirmationTask{ - AnchorID: anchorID, - From: address, - AnchorCommittedFilterer: &MockAnchorCommittedFilter{iter: &EthereumAnchorRepositoryContractAnchorCommittedIterator{ - fail: errors.New("watch error"), - sub: &testingutils.MockSubscription{}, - }}, - EthContext: ctx, - } - - _, err := act.RunTask() - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "watch error") -} diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index 043ca40db..451977663 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -13,7 +13,7 @@ var log = logging.Logger("anchorRepository") // AnchorRepository defines a set of functions that can be // implemented by any type that stores and retrieves the anchoring, and pre anchoring details. type AnchorRepository interface { - PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) - CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) + PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.DID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) + CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, documentProofs [][32]byte) (chan bool, error) GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) } diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index a6a8970e3..d91b98e87 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -11,108 +11,66 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) var ( - identityService identity.Service - anchorRepo anchors.AnchorRepository - cfg config.Configuration + anchorRepo anchors.AnchorRepository + cfg config.Configuration ) func TestMain(m *testing.M) { ctx := cc.TestFunctionalEthereumBootstrap() anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - identityService = ctx[identity.BootstrappedIDService].(identity.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() cc.TestFunctionalEthereumTearDown() os.Exit(result) } -func createIdentityWithKeys(t *testing.T, centrifugeId []byte) []byte { - centIdTyped, _ := identity.ToCentID(centrifugeId) - cfg.Set("identityId", centIdTyped.String()) - id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centIdTyped) - assert.Nil(t, err, "should not error out when creating identity") - watchRegisteredIdentity := <-confirmations - assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - // LookupIdentityForId - id, err = identityService.LookupIdentityForID(centIdTyped) - assert.Nil(t, err, "should not error out when resolving identity") - - pubKey, _ := hexutil.Decode("0xc8dd3d66e112fae5c88fe6a677be24013e53c33e") - - confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, pubKey) - assert.Nil(t, err, "should not error out when adding keys") - assert.NotNil(t, confirmations, "confirmations channel should not be nil") - watchRegisteredIdentityKey := <-confirmations - assert.Nil(t, watchRegisteredIdentityKey.Error, "No error thrown by context") - - return centrifugeId -} - func TestCommitAnchor_Integration(t *testing.T) { - anchorID, _ := hexutil.Decode("0x154cc26833dec2f4ad7ead9d65f9ec968a1aa5efbf6fe762f8f2a67d18a2d9b1") - documentRoot, _ := hexutil.Decode("0x65a35574f70281ae4d1f6c9f3adccd5378743f858c67a802a49a08ce185bc975") - centrifugeId := utils.RandomSlice(identity.CentIDLength) - createIdentityWithKeys(t, centrifugeId) - testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") + anchorID := utils.RandomSlice(32) + documentRoot := utils.RandomSlice(32) + anchorIDTyped, _ := anchors.ToAnchorID(anchorID) - centIdTyped, _ := identity.ToCentID(centrifugeId) docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) - messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) - commitAnchor(t, anchorID, centrifugeId, documentRoot, signature, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) + commitAnchor(t, anchorID, documentRoot, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorIDTyped) assert.Nil(t, err) assert.Equal(t, docRootTyped, gotDocRoot) } -func commitAnchor(t *testing.T, anchorID, centrifugeId, documentRoot, signature []byte, documentProofs [][32]byte) { +func commitAnchor(t *testing.T, anchorID, documentRoot []byte, documentProofs [][32]byte) { anchorIDTyped, _ := anchors.ToAnchorID(anchorID) docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) - centIdFixed, _ := identity.ToCentID(centrifugeId) - cfg.Set("identityId", centIdFixed.String()) ctx := testingconfig.CreateAccountContext(t, cfg) - confirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centIdFixed, documentProofs, signature) - if err != nil { - t.Fatalf("Error commit Anchor %v", err) - } + done, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, documentProofs) + + isDone := <-done + + assert.True(t, isDone, "isDone should be true") + + assert.Nil(t, err) - watchCommittedAnchor := <-confirmations - assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") - assert.Equal(t, watchCommittedAnchor.CommitData.AnchorID, anchorIDTyped, "Resulting anchor should have the same ID as the input") - assert.Equal(t, watchCommittedAnchor.CommitData.DocumentRoot, docRootTyped, "Resulting anchor should have the same document hash as the input") } func TestCommitAnchor_Integration_Concurrent(t *testing.T) { var commitDataList [5]*anchors.CommitData - var confirmationList [5]<-chan *anchors.WatchCommit - testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") - centrifugeId := utils.RandomSlice(identity.CentIDLength) - createIdentityWithKeys(t, centrifugeId) + var doneList [5]chan bool for ix := 0; ix < 5; ix++ { currentAnchorId := utils.RandomByte32() currentDocumentRoot := utils.RandomByte32() - centIdFixed, _ := identity.ToCentID(centrifugeId) - messageToSign := anchors.GenerateCommitHash(currentAnchorId, centIdFixed, currentDocumentRoot) - signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) documentProofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} h, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) assert.Nil(t, err, " error must be nil") - commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) - cfg.Set("identityId", centIdFixed.String()) + commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, documentProofs) ctx := testingconfig.CreateAccountContext(t, cfg) - confirmationList[ix], err = anchorRepo.CommitAnchor(ctx, currentAnchorId, currentDocumentRoot, centIdFixed, documentProofs, signature) + doneList[ix], err = anchorRepo.CommitAnchor(ctx, currentAnchorId, currentDocumentRoot, documentProofs) if err != nil { t.Fatalf("Error commit Anchor %v", err) } @@ -120,10 +78,8 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { } for ix := 0; ix < 5; ix++ { - watchSingleAnchor := <-confirmationList[ix] - assert.Nil(t, watchSingleAnchor.Error, "No error thrown by context") - assert.Equal(t, commitDataList[ix].AnchorID, watchSingleAnchor.CommitData.AnchorID, "Should have the ID that was passed into create function [%v]", watchSingleAnchor.CommitData.AnchorID) - assert.Equal(t, commitDataList[ix].DocumentRoot, watchSingleAnchor.CommitData.DocumentRoot, "Should have the document root that was passed into create function [%v]", watchSingleAnchor.CommitData.DocumentRoot) + isDone := <-doneList[ix] + assert.True(t, isDone) anchorID := commitDataList[ix].AnchorID docRoot := commitDataList[ix].DocumentRoot gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorID) diff --git a/anchors/bootstrapper.go b/anchors/bootstrapper.go index 098f4459e..9116e448f 100644 --- a/anchors/bootstrapper.go +++ b/anchors/bootstrapper.go @@ -1,13 +1,13 @@ package anchors import ( + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" - - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" ) // BootstrappedAnchorRepo is used as a key to map the configured anchor repository through context. @@ -29,26 +29,25 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - repositoryContract, err := NewEthereumAnchorRepositoryContract(cfg.GetContractAddress(config.AnchorRepo), client.GetEthClient()) + anchorContractAddr := cfg.GetContractAddress(config.AnchorRepo) + + repositoryContract, err := NewAnchorContract(anchorContractAddr, client.GetEthClient()) if err != nil { return err } - if _, ok := ctx[bootstrap.BootstrappedQueueServer]; !ok { - return errors.New("queue server hasn't been initialized") + txManager, ok := ctx[transactions.BootstrappedService].(transactions.Manager) + if !ok { + return errors.New("transactions repository not initialised") } - queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) - repo := newEthereumAnchorRepository(cfg, repositoryContract, queueSrv, ethereum.GetClient) - ctx[BootstrappedAnchorRepo] = repo - - task := &anchorConfirmationTask{ - // Passing timeout as a common property for every request, if we need more fine-grain control per request then we will override by invoker - Timeout: cfg.GetEthereumContextWaitTimeout(), - AnchorCommittedFilterer: &repositoryContract.EthereumAnchorRepositoryContractFilterer, - EthContextInitializer: ethereum.DefaultWaitForTransactionMiningContext, + queueSrv, ok := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue hasn't been initialized") } - queueSrv.RegisterTaskType(task.TaskTypeName(), task) + repo := newService(cfg, repositoryContract, queueSrv, client, txManager) + ctx[BootstrappedAnchorRepo] = repo + return nil } diff --git a/anchors/ethereum_anchor_repository.go b/anchors/ethereum_anchor_repository.go deleted file mode 100644 index e4f2a3f15..000000000 --- a/anchors/ethereum_anchor_repository.go +++ /dev/null @@ -1,224 +0,0 @@ -package anchors - -import ( - "context" - "math/big" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "time" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -type anchorRepositoryContract interface { - PreCommit(opts *bind.TransactOpts, anchorID *big.Int, signingRoot [32]byte, centID *big.Int, signature []byte, expirationBlock *big.Int) (*types.Transaction, error) - Commit(opts *bind.TransactOpts, anchorID *big.Int, documentRoot [32]byte, centID *big.Int, documentProofs [][32]byte, signatures []byte) (*types.Transaction, error) - Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) -} - -type watchAnchorPreCommitted interface { - //event name: AnchorPreCommitted - WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *EthereumAnchorRepositoryContractAnchorPreCommitted, - from []common.Address, anchorID []*big.Int) (event.Subscription, error) -} - -type ethereumAnchorRepository struct { - config Config - anchorRepositoryContract anchorRepositoryContract - gethClientFinder func() ethereum.Client - queue *queue.Server -} - -func newEthereumAnchorRepository(config Config, anchorRepositoryContract anchorRepositoryContract, queue *queue.Server, gethClientFinder func() ethereum.Client) AnchorRepository { - return ðereumAnchorRepository{config: config, anchorRepositoryContract: anchorRepositoryContract, gethClientFinder: gethClientFinder, queue: queue} -} - -// GetDocumentRootOf takes an anchorID and returns the corresponding documentRoot from the chain. -func (ethRepository *ethereumAnchorRepository) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethRepository.gethClientFinder().GetGethCallOpts(false) - return ethRepository.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) -} - -// PreCommitAnchor will call the transaction PreCommit on the smart contract -func (ethRepository *ethereumAnchorRepository) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.CentID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { - tc, err := contextutil.Account(ctx) - if err != nil { - return nil, err - } - - ethRepositoryContract := ethRepository.anchorRepositoryContract - opts, err := ethereum.GetClient().GetTxOpts(tc.GetEthereumDefaultAccountName()) - if err != nil { - return confirmations, err - } - - preCommitData := newPreCommitData(anchorID, signingRoot, centID, signature, expirationBlock) - if err != nil { - return confirmations, err - } - - err = sendPreCommitTransaction(ethRepositoryContract, opts, preCommitData) - if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to send Ethereum pre-commit transaction [id: %x, signingRoot: %x, SchemaVersion:%v]: %v", - preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.SchemaVersion, wError) - return confirmations, err - } - - return confirmations, err -} - -// CommitAnchor will send a commit transaction to Ethereum. -func (ethRepository *ethereumAnchorRepository) CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *WatchCommit, err error) { - tc, err := contextutil.Account(ctx) - if err != nil { - return nil, err - } - - conn := ethereum.GetClient() - opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) - if err != nil { - return nil, err - } - - h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) - if err != nil { - return nil, err - } - - cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, centID, documentProofs, signature) - confirmations, err = ethRepository.setUpCommitEventListener(ethRepository.config.GetEthereumContextWaitTimeout(), opts.From, cd) - - if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to set up event listener for commit transaction [id: %x, hash: %x]: %v", - cd.AnchorID, cd.DocumentRoot, wError) - return - } - - err = sendCommitTransaction(ethRepository.anchorRepositoryContract, opts, cd) - if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to send Ethereum commit transaction[id: %x, hash: %x, SchemaVersion:%v]: %v", - cd.AnchorID, cd.DocumentRoot, cd.SchemaVersion, wError) - return - } - return confirmations, err -} - -// sendPreCommitTransaction sends the actual transaction to the ethereum node. -func sendPreCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, preCommitData *PreCommitData) error { - - //preparation of data in specific types for the call to Ethereum - schemaVersion := big.NewInt(int64(preCommitData.SchemaVersion)) - - tx, err := ethereum.GetClient().SubmitTransactionWithRetries(contract.PreCommit, opts, preCommitData.AnchorID, preCommitData.SigningRoot, - preCommitData.CentrifugeID, preCommitData.Signature, preCommitData.ExpirationBlock, schemaVersion) - - if err != nil { - return err - } - - log.Infof("Sent off transaction pre-commit [id: %x, hash: %x, SchemaVersion:%v] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", preCommitData.AnchorID, - preCommitData.SigningRoot, schemaVersion, tx.Hash(), tx.Nonce(), tx.CheckNonce()) - - log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return nil -} - -// sendCommitTransaction sends the actual transaction to register the Anchor on Ethereum registry contract -func sendCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, commitData *CommitData) error { - tx, err := ethereum.GetClient().SubmitTransactionWithRetries(contract.Commit, opts, commitData.AnchorID.BigInt(), commitData.DocumentRoot, - commitData.CentrifugeID.BigInt(), commitData.DocumentProofs, commitData.Signature) - - if err != nil { - return err - } - - log.Infof("Sent off the anchor [id: %x, hash: %x] to registry. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", commitData.AnchorID, - commitData.DocumentRoot, tx.Hash(), tx.Nonce(), tx.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return nil -} - -// TODO: This method is only used by setUpPreCommitEventListener below, it will be changed soon so we can remove the hardcoded `time.Second` and use the global one -func generateEventContext() (*bind.WatchOpts, context.CancelFunc) { - //listen to this particular anchor being mined/event is triggered - ctx, cancelFunc := ethereum.DefaultWaitForTransactionMiningContext(time.Second) - watchOpts := &bind.WatchOpts{Context: ctx} - - return watchOpts, cancelFunc - -} - -// setUpPreCommitEventListener sets up the listened for the "PreCommit" event to notify the upstream code -// about successful mining/creation of a pre-commit. -func setUpPreCommitEventListener(contractEvent watchAnchorPreCommitted, from common.Address, preCommitData *PreCommitData) (confirmations chan *WatchPreCommit, err error) { - watchOpts, cancelFunc := generateEventContext() - - //there should always be only one notification coming for this - //single anchor being registered - anchorPreCommittedEvents := make(chan *EthereumAnchorRepositoryContractAnchorPreCommitted) - confirmations = make(chan *WatchPreCommit) - go waitAndRoutePreCommitEvent(watchOpts.Context, anchorPreCommittedEvents, confirmations, preCommitData) - - // Somehow there are some possible resource leakage situations with this handling but I have to understand - // Subscriptions a bit better before writing this code. - _, err = contractEvent.WatchAnchorPreCommitted(watchOpts, anchorPreCommittedEvents, []common.Address{from}, []*big.Int{preCommitData.AnchorID.BigInt()}) - if err != nil { - wError := errors.New("Could not subscribe to event logs for anchor registration: %v", err) - log.Errorf("Failed to watch anchor registered event: %v", wError.Error()) - cancelFunc() // cancel the event router - return confirmations, wError - } - return confirmations, nil -} - -// setUpCommitEventListener sets up the listened for the "AnchorCommitted" event to notify the upstream code -// about successful mining/creation of a commit -func (ethRepository *ethereumAnchorRepository) setUpCommitEventListener(timeout time.Duration, from common.Address, commitData *CommitData) (confirmations chan *WatchCommit, err error) { - confirmations = make(chan *WatchCommit) - asyncRes, err := ethRepository.queue.EnqueueJob(anchorRepositoryConfirmationTaskName, map[string]interface{}{ - anchorIDParam: commitData.AnchorID, - addressParam: from, - centIDParam: commitData.CentrifugeID, - blockHeight: commitData.BlockHeight, - }) - if err != nil { - return nil, err - } - - go waitAndRouteCommitEvent(timeout, asyncRes, confirmations, commitData) - return confirmations, nil -} - -// waitAndRoutePreCommitEvent notifies the confirmations channel whenever a pre-commit is being noted as Ethereum event -func waitAndRoutePreCommitEvent(ctx context.Context, conf <-chan *EthereumAnchorRepositoryContractAnchorPreCommitted, confirmations chan<- *WatchPreCommit, preCommitData *PreCommitData) { - for { - select { - case <-ctx.Done(): - log.Errorf("Context [%v] closed before receiving AnchorPreCommitted event for anchor ID: %x, DocumentRoot: %x\n", ctx, preCommitData.AnchorID, preCommitData.SigningRoot) - confirmations <- &WatchPreCommit{preCommitData, ctx.Err()} - return - case res := <-conf: - log.Infof("Received AnchorPreCommitted event from: %x\n", res.From) - confirmations <- &WatchPreCommit{preCommitData, nil} - return - } - } -} - -// waitAndRouteCommitEvent notifies the confirmations channel whenever a commit is being noted as Ethereum event -func waitAndRouteCommitEvent(timeout time.Duration, asyncResult queue.TaskResult, confirmations chan<- *WatchCommit, commitData *CommitData) { - _, err := asyncResult.Get(timeout) - confirmations <- &WatchCommit{commitData, err} -} diff --git a/anchors/ethereum_anchor_repository_contract.go b/anchors/ethereum_anchor_repository_contract.go deleted file mode 100644 index 421dac1b9..000000000 --- a/anchors/ethereum_anchor_repository_contract.go +++ /dev/null @@ -1,629 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package anchors - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// EthereumAnchorRepositoryContractABI is the input ABI used to generate the binding from. -const EthereumAnchorRepositoryContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"commits\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preCommits\",\"outputs\":[{\"name\":\"signingRoot\",\"type\":\"bytes32\"},{\"name\":\"centrifugeId\",\"type\":\"uint48\"},{\"name\":\"expirationBlock\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_identityRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"centrifugeId\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_signingRoot\",\"type\":\"bytes32\"},{\"name\":\"_centrifugeId\",\"type\":\"uint48\"},{\"name\":\"_signature\",\"type\":\"bytes\"},{\"name\":\"_expirationBlock\",\"type\":\"uint256\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_documentRoot\",\"type\":\"bytes32\"},{\"name\":\"_centrifugeId\",\"type\":\"uint48\"},{\"name\":\"_documentProofs\",\"type\":\"bytes32[]\"},{\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"name\":\"centrifugeId\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" - -// EthereumAnchorRepositoryContract is an auto generated Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContract struct { - EthereumAnchorRepositoryContractCaller // Read-only binding to the contract - EthereumAnchorRepositoryContractTransactor // Write-only binding to the contract - EthereumAnchorRepositoryContractFilterer // Log filterer for contract events -} - -// EthereumAnchorRepositoryContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumAnchorRepositoryContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumAnchorRepositoryContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type EthereumAnchorRepositoryContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumAnchorRepositoryContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type EthereumAnchorRepositoryContractSession struct { - Contract *EthereumAnchorRepositoryContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumAnchorRepositoryContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type EthereumAnchorRepositoryContractCallerSession struct { - Contract *EthereumAnchorRepositoryContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// EthereumAnchorRepositoryContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type EthereumAnchorRepositoryContractTransactorSession struct { - Contract *EthereumAnchorRepositoryContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumAnchorRepositoryContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContractRaw struct { - Contract *EthereumAnchorRepositoryContract // Generic contract binding to access the raw methods on -} - -// EthereumAnchorRepositoryContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContractCallerRaw struct { - Contract *EthereumAnchorRepositoryContractCaller // Generic read-only contract binding to access the raw methods on -} - -// EthereumAnchorRepositoryContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type EthereumAnchorRepositoryContractTransactorRaw struct { - Contract *EthereumAnchorRepositoryContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewEthereumAnchorRepositoryContract creates a new instance of EthereumAnchorRepositoryContract, bound to a specific deployed contract. -func NewEthereumAnchorRepositoryContract(address common.Address, backend bind.ContractBackend) (*EthereumAnchorRepositoryContract, error) { - contract, err := bindEthereumAnchorRepositoryContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContract{EthereumAnchorRepositoryContractCaller: EthereumAnchorRepositoryContractCaller{contract: contract}, EthereumAnchorRepositoryContractTransactor: EthereumAnchorRepositoryContractTransactor{contract: contract}, EthereumAnchorRepositoryContractFilterer: EthereumAnchorRepositoryContractFilterer{contract: contract}}, nil -} - -// NewEthereumAnchorRepositoryContractCaller creates a new read-only instance of EthereumAnchorRepositoryContract, bound to a specific deployed contract. -func NewEthereumAnchorRepositoryContractCaller(address common.Address, caller bind.ContractCaller) (*EthereumAnchorRepositoryContractCaller, error) { - contract, err := bindEthereumAnchorRepositoryContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContractCaller{contract: contract}, nil -} - -// NewEthereumAnchorRepositoryContractTransactor creates a new write-only instance of EthereumAnchorRepositoryContract, bound to a specific deployed contract. -func NewEthereumAnchorRepositoryContractTransactor(address common.Address, transactor bind.ContractTransactor) (*EthereumAnchorRepositoryContractTransactor, error) { - contract, err := bindEthereumAnchorRepositoryContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContractTransactor{contract: contract}, nil -} - -// NewEthereumAnchorRepositoryContractFilterer creates a new log filterer instance of EthereumAnchorRepositoryContract, bound to a specific deployed contract. -func NewEthereumAnchorRepositoryContractFilterer(address common.Address, filterer bind.ContractFilterer) (*EthereumAnchorRepositoryContractFilterer, error) { - contract, err := bindEthereumAnchorRepositoryContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContractFilterer{contract: contract}, nil -} - -// bindEthereumAnchorRepositoryContract binds a generic wrapper to an already deployed contract. -func bindEthereumAnchorRepositoryContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(EthereumAnchorRepositoryContractABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumAnchorRepositoryContract.Contract.EthereumAnchorRepositoryContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.EthereumAnchorRepositoryContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.EthereumAnchorRepositoryContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumAnchorRepositoryContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.contract.Transact(opts, method, params...) -} - -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCaller) Commits(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { - var ( - ret0 = new([32]byte) - ) - out := ret0 - err := _EthereumAnchorRepositoryContract.contract.Call(opts, out, "commits", arg0) - return *ret0, err -} - -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) Commits(arg0 *big.Int) ([32]byte, error) { - return _EthereumAnchorRepositoryContract.Contract.Commits(&_EthereumAnchorRepositoryContract.CallOpts, arg0) -} - -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCallerSession) Commits(arg0 *big.Int) ([32]byte, error) { - return _EthereumAnchorRepositoryContract.Contract.Commits(&_EthereumAnchorRepositoryContract.CallOpts, arg0) -} - -// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. -// -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32, centrifugeId uint48) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCaller) GetAnchorById(opts *bind.CallOpts, _anchorId *big.Int) (struct { - AnchorId *big.Int - DocumentRoot [32]byte - CentrifugeId *big.Int -}, error) { - ret := new(struct { - AnchorId *big.Int - DocumentRoot [32]byte - CentrifugeId *big.Int - }) - out := ret - err := _EthereumAnchorRepositoryContract.contract.Call(opts, out, "getAnchorById", _anchorId) - return *ret, err -} - -// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. -// -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32, centrifugeId uint48) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) GetAnchorById(_anchorId *big.Int) (struct { - AnchorId *big.Int - DocumentRoot [32]byte - CentrifugeId *big.Int -}, error) { - return _EthereumAnchorRepositoryContract.Contract.GetAnchorById(&_EthereumAnchorRepositoryContract.CallOpts, _anchorId) -} - -// GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. -// -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32, centrifugeId uint48) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCallerSession) GetAnchorById(_anchorId *big.Int) (struct { - AnchorId *big.Int - DocumentRoot [32]byte - CentrifugeId *big.Int -}, error) { - return _EthereumAnchorRepositoryContract.Contract.GetAnchorById(&_EthereumAnchorRepositoryContract.CallOpts, _anchorId) -} - -// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. -// -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCaller) HasValidPreCommit(opts *bind.CallOpts, _anchorId *big.Int) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _EthereumAnchorRepositoryContract.contract.Call(opts, out, "hasValidPreCommit", _anchorId) - return *ret0, err -} - -// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. -// -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { - return _EthereumAnchorRepositoryContract.Contract.HasValidPreCommit(&_EthereumAnchorRepositoryContract.CallOpts, _anchorId) -} - -// HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. -// -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCallerSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { - return _EthereumAnchorRepositoryContract.Contract.HasValidPreCommit(&_EthereumAnchorRepositoryContract.CallOpts, _anchorId) -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, centrifugeId uint48, expirationBlock uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCaller) PreCommits(opts *bind.CallOpts, arg0 *big.Int) (struct { - SigningRoot [32]byte - CentrifugeId *big.Int - ExpirationBlock uint32 -}, error) { - ret := new(struct { - SigningRoot [32]byte - CentrifugeId *big.Int - ExpirationBlock uint32 - }) - out := ret - err := _EthereumAnchorRepositoryContract.contract.Call(opts, out, "preCommits", arg0) - return *ret, err -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, centrifugeId uint48, expirationBlock uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) PreCommits(arg0 *big.Int) (struct { - SigningRoot [32]byte - CentrifugeId *big.Int - ExpirationBlock uint32 -}, error) { - return _EthereumAnchorRepositoryContract.Contract.PreCommits(&_EthereumAnchorRepositoryContract.CallOpts, arg0) -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, centrifugeId uint48, expirationBlock uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractCallerSession) PreCommits(arg0 *big.Int) (struct { - SigningRoot [32]byte - CentrifugeId *big.Int - ExpirationBlock uint32 -}, error) { - return _EthereumAnchorRepositoryContract.Contract.PreCommits(&_EthereumAnchorRepositoryContract.CallOpts, arg0) -} - -// Commit is a paid mutator transaction binding the contract method 0xad90a76b. -// -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _centrifugeId uint48, _documentProofs bytes32[], _signature bytes) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactor) Commit(opts *bind.TransactOpts, _anchorId *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.contract.Transact(opts, "commit", _anchorId, _documentRoot, _centrifugeId, _documentProofs, _signature) -} - -// Commit is a paid mutator transaction binding the contract method 0xad90a76b. -// -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _centrifugeId uint48, _documentProofs bytes32[], _signature bytes) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.Commit(&_EthereumAnchorRepositoryContract.TransactOpts, _anchorId, _documentRoot, _centrifugeId, _documentProofs, _signature) -} - -// Commit is a paid mutator transaction binding the contract method 0xad90a76b. -// -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _centrifugeId uint48, _documentProofs bytes32[], _signature bytes) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactorSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _centrifugeId *big.Int, _documentProofs [][32]byte, _signature []byte) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.Commit(&_EthereumAnchorRepositoryContract.TransactOpts, _anchorId, _documentRoot, _centrifugeId, _documentProofs, _signature) -} - -// PreCommit is a paid mutator transaction binding the contract method 0xf098d34c. -// -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _centrifugeId uint48, _signature bytes, _expirationBlock uint256) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactor) PreCommit(opts *bind.TransactOpts, _anchorId *big.Int, _signingRoot [32]byte, _centrifugeId *big.Int, _signature []byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.contract.Transact(opts, "preCommit", _anchorId, _signingRoot, _centrifugeId, _signature, _expirationBlock) -} - -// PreCommit is a paid mutator transaction binding the contract method 0xf098d34c. -// -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _centrifugeId uint48, _signature bytes, _expirationBlock uint256) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _centrifugeId *big.Int, _signature []byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.PreCommit(&_EthereumAnchorRepositoryContract.TransactOpts, _anchorId, _signingRoot, _centrifugeId, _signature, _expirationBlock) -} - -// PreCommit is a paid mutator transaction binding the contract method 0xf098d34c. -// -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _centrifugeId uint48, _signature bytes, _expirationBlock uint256) returns() -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractTransactorSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _centrifugeId *big.Int, _signature []byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _EthereumAnchorRepositoryContract.Contract.PreCommit(&_EthereumAnchorRepositoryContract.TransactOpts, _anchorId, _signingRoot, _centrifugeId, _signature, _expirationBlock) -} - -// EthereumAnchorRepositoryContractAnchorCommittedIterator is returned from FilterAnchorCommitted and is used to iterate over the raw logs and unpacked data for AnchorCommitted events raised by the EthereumAnchorRepositoryContract contract. -type EthereumAnchorRepositoryContractAnchorCommittedIterator struct { - Event *EthereumAnchorRepositoryContractAnchorCommitted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumAnchorRepositoryContractAnchorCommittedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumAnchorRepositoryContractAnchorCommitted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumAnchorRepositoryContractAnchorCommitted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumAnchorRepositoryContractAnchorCommittedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumAnchorRepositoryContractAnchorCommittedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumAnchorRepositoryContractAnchorCommitted represents a AnchorCommitted event raised by the EthereumAnchorRepositoryContract contract. -type EthereumAnchorRepositoryContractAnchorCommitted struct { - From common.Address - AnchorId *big.Int - CentrifugeId *big.Int - DocumentRoot [32]byte - BlockHeight uint32 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAnchorCommitted is a free log retrieval operation binding the contract event 0x307682cd6852f8e18285627aa89f76c08e16e4978ab1c80dedbc5e1d43ddba66. -// -// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, centrifugeId indexed uint48, documentRoot bytes32, blockHeight uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractFilterer) FilterAnchorCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int, centrifugeId []*big.Int) (*EthereumAnchorRepositoryContractAnchorCommittedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var anchorIdRule []interface{} - for _, anchorIdItem := range anchorId { - anchorIdRule = append(anchorIdRule, anchorIdItem) - } - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumAnchorRepositoryContract.contract.FilterLogs(opts, "AnchorCommitted", fromRule, anchorIdRule, centrifugeIdRule) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContractAnchorCommittedIterator{contract: _EthereumAnchorRepositoryContract.contract, event: "AnchorCommitted", logs: logs, sub: sub}, nil -} - -// WatchAnchorCommitted is a free log subscription operation binding the contract event 0x307682cd6852f8e18285627aa89f76c08e16e4978ab1c80dedbc5e1d43ddba66. -// -// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, centrifugeId indexed uint48, documentRoot bytes32, blockHeight uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractFilterer) WatchAnchorCommitted(opts *bind.WatchOpts, sink chan<- *EthereumAnchorRepositoryContractAnchorCommitted, from []common.Address, anchorId []*big.Int, centrifugeId []*big.Int) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var anchorIdRule []interface{} - for _, anchorIdItem := range anchorId { - anchorIdRule = append(anchorIdRule, anchorIdItem) - } - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumAnchorRepositoryContract.contract.WatchLogs(opts, "AnchorCommitted", fromRule, anchorIdRule, centrifugeIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumAnchorRepositoryContractAnchorCommitted) - if err := _EthereumAnchorRepositoryContract.contract.UnpackLog(event, "AnchorCommitted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// EthereumAnchorRepositoryContractAnchorPreCommittedIterator is returned from FilterAnchorPreCommitted and is used to iterate over the raw logs and unpacked data for AnchorPreCommitted events raised by the EthereumAnchorRepositoryContract contract. -type EthereumAnchorRepositoryContractAnchorPreCommittedIterator struct { - Event *EthereumAnchorRepositoryContractAnchorPreCommitted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumAnchorRepositoryContractAnchorPreCommittedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumAnchorRepositoryContractAnchorPreCommitted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumAnchorRepositoryContractAnchorPreCommitted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumAnchorRepositoryContractAnchorPreCommittedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumAnchorRepositoryContractAnchorPreCommittedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumAnchorRepositoryContractAnchorPreCommitted represents a AnchorPreCommitted event raised by the EthereumAnchorRepositoryContract contract. -type EthereumAnchorRepositoryContractAnchorPreCommitted struct { - From common.Address - AnchorId *big.Int - BlockHeight uint32 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterAnchorPreCommitted is a free log retrieval operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. -// -// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractFilterer) FilterAnchorPreCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*EthereumAnchorRepositoryContractAnchorPreCommittedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var anchorIdRule []interface{} - for _, anchorIdItem := range anchorId { - anchorIdRule = append(anchorIdRule, anchorIdItem) - } - - logs, sub, err := _EthereumAnchorRepositoryContract.contract.FilterLogs(opts, "AnchorPreCommitted", fromRule, anchorIdRule) - if err != nil { - return nil, err - } - return &EthereumAnchorRepositoryContractAnchorPreCommittedIterator{contract: _EthereumAnchorRepositoryContract.contract, event: "AnchorPreCommitted", logs: logs, sub: sub}, nil -} - -// WatchAnchorPreCommitted is a free log subscription operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. -// -// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) -func (_EthereumAnchorRepositoryContract *EthereumAnchorRepositoryContractFilterer) WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *EthereumAnchorRepositoryContractAnchorPreCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var anchorIdRule []interface{} - for _, anchorIdItem := range anchorId { - anchorIdRule = append(anchorIdRule, anchorIdItem) - } - - logs, sub, err := _EthereumAnchorRepositoryContract.contract.WatchLogs(opts, "AnchorPreCommitted", fromRule, anchorIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumAnchorRepositoryContractAnchorPreCommitted) - if err := _EthereumAnchorRepositoryContract.contract.UnpackLog(event, "AnchorPreCommitted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/anchors/service.go b/anchors/service.go new file mode 100644 index 000000000..c83bd74eb --- /dev/null +++ b/anchors/service.go @@ -0,0 +1,157 @@ +package anchors + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/transactions" + + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" +) + +type anchorRepositoryContract interface { + PreCommit(opts *bind.TransactOpts, _anchorID *big.Int, signingRoot [32]byte, expirationBlock *big.Int) (*types.Transaction, error) + Commit(opts *bind.TransactOpts, anchorID *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) + Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) +} + +type service struct { + config Config + anchorRepositoryContract anchorRepositoryContract + client ethereum.Client + queue *queue.Server + txManager transactions.Manager +} + +func newService(config Config, anchorContract anchorRepositoryContract, queue *queue.Server, client ethereum.Client, txManager transactions.Manager) AnchorRepository { + return &service{config: config, anchorRepositoryContract: anchorContract, client: client, queue: queue, txManager: txManager} +} + +// GetDocumentRootOf takes an anchorID and returns the corresponding documentRoot from the chain. +func (s *service) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := s.client.GetGethCallOpts(false) + return s.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) +} + +// PreCommitAnchor will call the transaction PreCommit on the smart contract +func (s *service) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.DID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { + tc, err := contextutil.Account(ctx) + if err != nil { + return nil, err + } + + ethRepositoryContract := s.anchorRepositoryContract + opts, err := ethereum.GetClient().GetTxOpts(tc.GetEthereumDefaultAccountName()) + if err != nil { + return confirmations, err + } + + preCommitData := newPreCommitData(anchorID, signingRoot, centID, signature, expirationBlock) + if err != nil { + return confirmations, err + } + + err = sendPreCommitTransaction(ethRepositoryContract, opts, preCommitData) + if err != nil { + wError := errors.New("%v", err) + log.Errorf("Failed to send Ethereum pre-commit transaction [id: %x, signingRoot: %x, SchemaVersion:%v]: %v", + preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.SchemaVersion, wError) + return confirmations, err + } + + return confirmations, err +} + +// ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result +func (s service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + + ethTX, err := s.client.SubmitTransactionWithRetries(contractMethod, opts, params...) + if err != nil { + errOut <- err + return + } + + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), s.queue) + if err != nil { + errOut <- err + return + } + + _, err = res.Get(txMan.GetDefaultTaskTimeout()) + if err != nil { + errOut <- err + return + } + errOut <- nil + } +} + +// getDID returns DID from context.Account +// TODO use did.NewDIDFromContext as soon as IDConfig is deleted +func getDID(ctx context.Context) (identity.DID, error) { + tc, err := contextutil.Account(ctx) + if err != nil { + return identity.DID{}, err + } + + addressByte, err := tc.GetIdentityID() + if err != nil { + return identity.DID{}, err + } + return identity.NewDID(common.BytesToAddress(addressByte)), nil +} + +// CommitAnchor will send a commit transaction to Ethereum. +func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, documentProofs [][32]byte) (chan bool, error) { + did, err := getDID(ctx) + if err != nil { + return nil, err + } + + tc, err := contextutil.Account(ctx) + if err != nil { + return nil, err + } + + uuid := contextutil.TX(ctx) + + conn := s.client + opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) + if err != nil { + return nil, err + } + + h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) + if err != nil { + return nil, err + } + + cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, documentProofs) + + log.Info("Add Anchor to Commit %s from did:%s", anchorID.BigInt().String(), did.ToAddress().String()) + _, done, err := s.txManager.ExecuteWithinTX(ctx, did, uuid, "Check TX for anchor commit", + s.ethereumTX(opts, s.anchorRepositoryContract.Commit, cd.AnchorID.BigInt(), cd.DocumentRoot, cd.DocumentProofs)) + if err != nil { + return nil, err + } + + return done, nil + +} + +// sendPreCommitTransaction sends the actual transaction to the ethereum node. +func sendPreCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, preCommitData *PreCommitData) error { + + //TODO implement + return nil +} diff --git a/anchors/ethereum_anchor_repository_test.go b/anchors/service_test.go similarity index 70% rename from anchors/ethereum_anchor_repository_test.go rename to anchors/service_test.go index 355181a46..5c7de4e64 100644 --- a/anchors/ethereum_anchor_repository_test.go +++ b/anchors/service_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" @@ -29,15 +28,14 @@ func (m *mockAnchorRepo) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoo } func TestCorrectCommitSignatureGen(t *testing.T) { - // hardcoded values are generated with centrifuge-ethereum-contracts anchorID, _ := hexutil.Decode("0x154cc26833dec2f4ad7ead9d65f9ec968a1aa5efbf6fe762f8f2a67d18a2d9b1") documentRoot, _ := hexutil.Decode("0x65a35574f70281ae4d1f6c9f3adccd5378743f858c67a802a49a08ce185bc975") - centrifugeId, _ := hexutil.Decode("0x1851943e76d2") - correctCommitToSign := "0x15f9cb57608a7ef31428fd6b1cb7ea2002ab032211d882b920c1474334004d6b" - correctCommitSignature := "0xb4051d6d03c3bf39f4ec4ba949a91a358b0cacb4804b82ed2ba978d338f5e747770c00b63c8e50c1a7aa5ba629870b54c2068a56f8b43460aa47891c6635d36d01" + address, _ := hexutil.Decode("0x89b0a86583c4444acfd71b463e0d3c55ae1412a5") + correctCommitToSign := "0x004a050342f1edda2462288b9e0123a2e1bcc4f978efdc08c07bbf0c3ccc8ddd" + correctCommitSignature := "0x4a73286521114f528967674bae4ecdc6cc94789255495429a7f58ca3ef0158ae257dd02a0ccb71d817e480d06f60f640ec021ade2ff90fe601bb7a5f4ddc569700" testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") anchorIDTyped, _ := ToAnchorID(anchorID) - centIdTyped, _ := identity.ToCentID(centrifugeId) + centIdTyped := identity.NewDIDFromByte(address) docRootTyped, _ := ToDocumentRoot(documentRoot) messageToSign := GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) assert.Equal(t, correctCommitToSign, hexutil.Encode(messageToSign), "messageToSign not calculated correctly") @@ -49,28 +47,23 @@ func TestGenerateAnchor(t *testing.T) { currentAnchorID := utils.RandomByte32() currentDocumentRoot := utils.RandomByte32() documentProof := utils.RandomByte32() - centrifugeId := utils.RandomSlice(identity.CentIDLength) - testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") var documentProofs [][32]byte documentProofs = append(documentProofs, documentProof) - centIdTyped, _ := identity.ToCentID(centrifugeId) - messageToSign := GenerateCommitHash(currentAnchorID, centIdTyped, currentDocumentRoot) - signature, _ := secp256k1.SignEthereum(messageToSign, testPrivateKey) var documentRoot32Bytes [32]byte copy(documentRoot32Bytes[:], currentDocumentRoot[:32]) - commitData := NewCommitData(0, currentAnchorID, documentRoot32Bytes, centIdTyped, documentProofs, signature) + commitData := NewCommitData(0, currentAnchorID, documentRoot32Bytes, documentProofs) anchorID, _ := ToAnchorID(currentAnchorID[:]) docRoot, _ := ToDocumentRoot(documentRoot32Bytes[:]) assert.Equal(t, commitData.AnchorID, anchorID, "Anchor should have the passed ID") assert.Equal(t, commitData.DocumentRoot, docRoot, "Anchor should have the passed document root") - assert.Equal(t, commitData.CentrifugeID, centIdTyped, "Anchor should have the centrifuge id") + assert.Equal(t, commitData.DocumentProofs, documentProofs, "Anchor should have the document proofs") - assert.Equal(t, commitData.Signature, signature, "Anchor should have the signature") + } func TestGetDocumentRootOf(t *testing.T) { @@ -80,9 +73,7 @@ func TestGetDocumentRootOf(t *testing.T) { ethClient := &testingcommons.MockEthClient{} ethClient.On("GetGethCallOpts").Return(nil) - ethRepo := newEthereumAnchorRepository(cfg, repo, nil, func() ethereum.Client { - return ethClient - }) + ethRepo := newService(cfg, repo, nil, ethClient, nil) docRoot := utils.RandomByte32() repo.On("Commits", mock.Anything, mock.Anything).Return(docRoot, nil) gotRoot, err := ethRepo.GetDocumentRootOf(anchorID) diff --git a/api/server_test.go b/api/server_test.go index f246de08d..c2b80595e 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -19,7 +21,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" @@ -45,7 +46,7 @@ func TestMain(m *testing.M) { &leveldb.Bootstrapper{}, txv1.Bootstrapper{}, &queue.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 4f6cab3af..6a4d525e3 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -10,8 +10,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/did" - "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/identity/ideth" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/p2p" @@ -38,7 +37,7 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, @@ -60,9 +59,8 @@ func (m *MainBootstrapper) PopulateCommandBootstrappers() { txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - &did.Bootstrapper{}, + &ideth.Bootstrapper{}, &anchors.Bootstrapper{}, - ðid.Bootstrapper{}, } } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 88acb3657..00b3d0661 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -12,7 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/identity/ideth" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" @@ -31,7 +31,7 @@ var bootstappers = []bootstrap.TestBootstrapper{ txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 0a20ccd14..0dae3446a 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -27,10 +27,10 @@ networks: ethereumNetworkId: 4 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x90d294571e73842697a66b7a99a09dd6c73d356d" + identityFactory: "0xF3d98f3f6866E772305504317519A12Dcf8e8e9A" identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" - anchorRepository: "0x7f854dfa98012d7fa55c803bba2260bcdee4b5ed" - paymentObligation: "0xdb0581A9328664855328AdDb0E251184640f9e5D" + anchorRepository: "0x5372Be663ad3FDe0B2F64776081C077C4B5aa457" + paymentObligation: "0x5F029989DE7AA406aD01DD1d25d6f2e021Eee008" # Kovan test network bernalheights: @@ -51,10 +51,10 @@ networks: ethereumNetworkId: 42 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x85b32f7a3f40481f12334041670c8cbe07f7d79c" + identityFactory: "0xC33e46E8f78f42CF041aB9009125F38280E80E3C" identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" - anchorRepository: "0x444f649e307442e76ccf737466e52f1609b98260" - paymentObligation: "0x0417eb37941164368401D666984cED7694ABcBb1" + anchorRepository: "0xcE2a6E242C457Bc7Ecbe0cb9dA8f2FFCA21273c9" + paymentObligation: "0x4922ea1a05c15547eA3f7a3eA9B0fBF2965E466F" # Ropsten test network dogpatch: @@ -68,10 +68,10 @@ networks: ethereumNetworkId: 3 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x546EF82C503ef306e1fA4775f30068b4d9e20814" + identityFactory: "0x47d3194f858d1Fa26C51a93631CEA6eFa570E833" identityRegistry: "0x55160B12091c41E7C41f0BA5Ae925a0426c4aAEA" - anchorRepository: "0x31f760e704F37755d1Ca4fB5eDA6D755E107Ae11" - paymentObligation: "0x3Ea32C24A525E7e8a6191C923793052F77b65936" + anchorRepository: "0xE3228070377Be6DD03f29661AD194Ed038f2830f" + paymentObligation: "0x5820c05E8eE7d63720DF8D5e6C5987Ac6D998C42" # Data Storage storage: diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index 69b15a304..97b2bab30 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -6,7 +6,7 @@ ethereum: password: '' address: 89b0a86583c4444acfd71b463e0d3c55ae1412a5 -identityId: "0x010101010101" +identityId: "0x89b0a86583c4444acfd71b463e0d3c55ae1412a5" # Accounts key storage accounts: diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index fc67a1eba..e75e28239 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -30,7 +30,7 @@ func init() { Short: "Configures Node", Long: ``, Run: func(c *cobra.Command, args []string) { - err := cmd.CreateConfigDeprecated(targetDataDir, + err := cmd.CreateConfig(targetDataDir, ethNodeURL, accountKeyPath, accountPassword, @@ -39,8 +39,7 @@ func init() { p2pPort, bootstraps, txPoolAccess, - "", - nil) + "", nil) if err != nil { log.Info(targetDataDir, accountKeyPath, diff --git a/cmd/centrifuge/manage_identities.go b/cmd/centrifuge/manage_identities.go index 134c7612b..67a24dc5c 100644 --- a/cmd/centrifuge/manage_identities.go +++ b/cmd/centrifuge/manage_identities.go @@ -15,9 +15,6 @@ import ( "github.com/spf13/cobra" ) -var centIDString string -var purpose string - var createIdentityCmd = &cobra.Command{ Use: "createidentity", Short: "creates identity with signing key as p2p id against ethereum", @@ -26,16 +23,8 @@ var createIdentityCmd = &cobra.Command{ //cm requires a config file cfgFile = ensureConfigFile() ctx, canc, _ := cmd.CommandBootstrap(cfgFile) - var centID identity.CentID var err error - if centIDString == "" { - centID = identity.RandomCentID() - } else { - centID, err = identity.CentIDFromString(centIDString) - if err != nil { - panic(err) - } - } + cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) if err != nil { @@ -47,63 +36,24 @@ var createIdentityCmd = &cobra.Command{ panic(err) } - idService := ctx[identity.BootstrappedIDService].(identity.Service) - _, confirmations, err := idService.CreateIdentity(tctx, centID) + idService := ctx[identity.BootstrappedDIDFactory].(identity.Factory) + did, err := idService.CreateIdentity(tctx) if err != nil { panic(err) } - watchIdentity := <-confirmations - log.Infof("Identity created [%s]", watchIdentity.Identity.CentID().String()) + log.Infof("Identity created [%s]", did.String()) // We need a way to return the identity created so it can be read by an automated process as well // when id autogenerated - id := []byte("{\"id\": \"" + centID.String() + "\"}") + id := []byte("{\"id\": \"" + did.String() + "\"}") err = ioutil.WriteFile("newidentity.json", id, 0644) if err != nil { panic(err) } - log.Infof("Identity created [%s]", watchIdentity.Identity.CentID()) - canc() - }, -} - -//We should support multiple types of keys to add, at the moment only keyPurpose 1 - PeerID/Signature/Encryption -var addKeyCmd = &cobra.Command{ - Use: "addkey", - Short: "add a signing key as p2p id against ethereum", - Long: "add a signing key as p2p id against ethereum", - Run: func(cm *cobra.Command, args []string) { - //cm requires a config file - cfgFile = ensureConfigFile() - ctx, canc, _ := cmd.CommandBootstrap(cfgFile) - var purposeInt int - - switch purpose { - case "p2p": - purposeInt = identity.KeyPurposeP2P - case "sign": - purposeInt = identity.KeyPurposeSigning - case "ethauth": - purposeInt = identity.KeyPurposeEthMsgAuth - default: - panic("Option not supported") - } - - cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - idService := ctx[identity.BootstrappedIDService].(identity.Service) - err := idService.AddKeyFromConfig(cfg, purposeInt) - if err != nil { - panic(err) - } - + log.Infof("Identity created [%s]", did.String()) canc() - return }, } func init() { - createIdentityCmd.Flags().StringVarP(¢IDString, "centrifugeid", "i", "", "Centrifuge ID") - addKeyCmd.Flags().StringVarP(¢IDString, "centrifugeid", "i", "", "Centrifuge ID") - addKeyCmd.Flags().StringVarP(&purpose, "purpose", "p", "", "Key Purpose [p2p|sign|ethauth]") rootCmd.AddCommand(createIdentityCmd) - rootCmd.AddCommand(addKeyCmd) } diff --git a/cmd/centrifuge_cmd_test.go b/cmd/centrifuge_cmd_test.go index ee57d47ea..c35c3038e 100644 --- a/cmd/centrifuge_cmd_test.go +++ b/cmd/centrifuge_cmd_test.go @@ -21,14 +21,13 @@ func TestVersion(t *testing.T) { assert.Contains(t, string(o), version.CentrifugeNodeVersion) } -func TestCreateConfigDeprecated(t *testing.T) { +func TestCreateConfigCmd(t *testing.T) { dataDir := path.Join(os.Getenv("HOME"), "datadir") scAddrs := testingutils.GetSmartContractAddresses() keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") cmd := exec.Command(testingutils.GetBinaryPath(), "createconfig", "-n", "testing", "-t", dataDir, "-z", keyPath) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_IDENTITYFACTORY=%s", scAddrs.IdentityFactoryAddr)) - cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_IDENTITYREGISTRY=%s", scAddrs.IdentityRegistryAddr)) cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_ANCHORREPOSITORY=%s", scAddrs.AnchorRepositoryAddr)) cmd.Env = append(cmd.Env, fmt.Sprintf("CENT_NETWORKS_TESTING_CONTRACTADDRESSES_PAYMENTOBLIGATION=%s", scAddrs.PaymentObligationAddr)) o, err := cmd.Output() diff --git a/cmd/common.go b/cmd/common.go index dcb802648..0c154b22d 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -3,11 +3,12 @@ package cmd import ( "context" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/identity/did" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/pkg/errors" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/storage" logging "github.com/ipfs/go-log" @@ -15,25 +16,12 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/queue" ) var log = logging.Logger("centrifuge-cmd") -// Deprecated -func createIdentityDeprecated(ctx context.Context, idService identity.Service) (identity.CentID, error) { - centID := identity.RandomCentID() - _, confirmations, err := idService.CreateIdentity(ctx, centID) - if err != nil { - return [identity.CentIDLength]byte{}, err - } - _ = <-confirmations - - return centID, nil -} - func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetP2PKeyPair() signPub, signPvt := config.GetSigningKeyPair() @@ -43,23 +31,6 @@ func generateKeys(config config.Configuration) { crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") } -// Deprecated -func addKeysDeprecated(config config.Configuration, idService identity.Service) error { - err := idService.AddKeyFromConfig(config, identity.KeyPurposeP2P) - if err != nil { - return err - } - err = idService.AddKeyFromConfig(config, identity.KeyPurposeSigning) - if err != nil { - return err - } - err = idService.AddKeyFromConfig(config, identity.KeyPurposeEthMsgAuth) - if err != nil { - return err - } - return nil -} - // CreateConfig creates a config file using provide parameters and the default config func CreateConfig( targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, @@ -84,6 +55,7 @@ func CreateConfig( if smartContractAddrs != nil { data["smartContractAddresses"] = smartContractAddrs } + configFile, err := config.CreateConfigFile(data) if err != nil { return err @@ -92,104 +64,54 @@ func CreateConfig( ctx, canc, _ := CommandBootstrap(configFile.ConfigFileUsed()) cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) + idService, ok := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + if !ok { + return errors.New("bootstrapped identity service not initialized") + } + idFactory, ok := ctx[identity.BootstrappedDIDFactory].(identity.Factory) + if !ok { + return errors.New("bootstrapped identity factory not initialized") + } + // create keys locally generateKeys(cfg) - id, err := did.CreateIdentity(ctx, cfg) + acc, err := configstore.TempAccount("", cfg) if err != nil { return err } - - configFile.Set("identityId", id.ToAddress().String()) - err = configFile.WriteConfig() + ctxh, err := contextutil.New(context.Background(), acc) if err != nil { return err } - cfg.Set("identityId", id.ToAddress().String()) - log.Infof("Identity created [%s]", id.ToAddress().String()) - - err = did.AddKeysFromConfig(ctx, cfg) + DID, err := idFactory.CreateIdentity(ctxh) if err != nil { return err } - canc() - db := ctx[storage.BootstrappedDB].(storage.Repository) - dbCfg := ctx[storage.BootstrappedConfigDB].(storage.Repository) - db.Close() - dbCfg.Close() - log.Infof("---------Centrifuge node configuration file successfully created!---------") - log.Infof("Please run the Centrifuge node using the following command: centrifuge run -c %s\n", configFile.ConfigFileUsed()) - return nil -} - -// CreateConfigDeprecated creates a config file using provide parameters and the default config -// Deprecated -func CreateConfigDeprecated( - targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, - apiPort, p2pPort int64, - bootstraps []string, - txPoolAccess bool, - p2pConnectionTimeout string, - smartContractAddrs *config.SmartContractAddresses) error { - - data := map[string]interface{}{ - "targetDataDir": targetDataDir, - "accountKeyPath": accountKeyPath, - "accountPassword": accountPassword, - "network": network, - "ethNodeURL": ethNodeURL, - "bootstraps": bootstraps, - "apiPort": apiPort, - "p2pPort": p2pPort, - "p2pConnectTimeout": p2pConnectionTimeout, - "txpoolaccess": txPoolAccess, - } - if smartContractAddrs != nil { - data["smartContractAddresses"] = smartContractAddrs - } - v, err := config.CreateConfigFile(data) - if err != nil { - return err - } - log.Infof("Config File Created: %s\n", v.ConfigFileUsed()) - ctx, canc, _ := CommandBootstrap(v.ConfigFileUsed()) - cfg := ctx[bootstrap.BootstrappedConfig].(config.Configuration) - generateKeys(cfg) + acci := acc.(*configstore.Account) + acci.IdentityID = DID[:] - tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) + configFile.Set("identityId", DID.String()) + err = configFile.WriteConfig() if err != nil { return err } + cfg.Set("identityId", DID.String()) + log.Infof("Identity created [%s]", DID.String()) - tctx, err := contextutil.New(context.Background(), tc) + err = idService.AddKeysForAccount(acci) if err != nil { return err } - idService := ctx[identity.BootstrappedIDService].(identity.Service) - id, err := createIdentityDeprecated(tctx, idService) - if err != nil { - return err - } - v.Set("identityId", id.String()) - err = v.WriteConfig() - if err != nil { - return err - } - cfg.Set("identityId", id.String()) - log.Infof("Identity created [%s] [%x]", id.String(), id) - err = addKeysDeprecated(cfg, idService) - if err != nil { - return err - } canc() db := ctx[storage.BootstrappedDB].(storage.Repository) dbCfg := ctx[storage.BootstrappedConfigDB].(storage.Repository) db.Close() dbCfg.Close() log.Infof("---------Centrifuge node configuration file successfully created!---------") - log.Infof("Please run the Centrifuge node using the following command: centrifuge run -c %s\n", v.ConfigFileUsed()) + log.Infof("Please run the Centrifuge node using the following command: centrifuge run -c %s\n", configFile.ConfigFileUsed()) return nil } diff --git a/cmd/common_test.go b/cmd/common_test.go index 221100b15..40252d2bc 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -10,6 +10,13 @@ import ( "path" "testing" + "github.com/centrifuge/go-centrifuge/identity/ideth" + + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" @@ -17,15 +24,10 @@ import ( "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/did" - "github.com/centrifuge/go-centrifuge/identity/ethid" + "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/transactions/txv1" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" ) @@ -33,23 +35,22 @@ var cfg config.Configuration var ctx = map[string]interface{}{} func TestMain(m *testing.M) { - var bootstappers = []bootstrap.TestBootstrapper{ + var bootstrappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, - &did.Bootstrapper{}, &queue.Starter{}, } - bootstrap.RunTestBootstrappers(bootstappers, ctx) + bootstrap.RunTestBootstrappers(bootstrappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) result := m.Run() - bootstrap.RunTestTeardown(bootstappers) + bootstrap.RunTestTeardown(bootstrappers) os.Exit(result) } @@ -57,7 +58,7 @@ func TestCreateConfig(t *testing.T) { // create config dataDir := "testconfig" keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") - scAddrs := did.GetSmartContractAddresses() + scAddrs := testingutils.GetSmartContractAddresses() err := CreateConfig(dataDir, "http://127.0.0.1:9545", keyPath, "", "russianhill", 8028, 38202, nil, true, "", scAddrs) assert.Nil(t, err, "Create Config should be successful") @@ -67,7 +68,7 @@ func TestCreateConfig(t *testing.T) { // contract exists id, err := cfg.GetIdentityID() - accountId := did.NewDID(common.BytesToAddress(id)) + accountId := identity.NewDID(common.BytesToAddress(id)) assert.Nil(t, err, "did should exists") contractCode, err := client.GetEthClient().CodeAt(context.Background(), common.BytesToAddress(id), nil) @@ -76,7 +77,7 @@ func TestCreateConfig(t *testing.T) { // Keys exists // type KeyPurposeEthMsgAuth - idSrv := ctx[did.BootstrappedDIDService].(did.Service) + idSrv := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) pk, _, err := secp256k1.GetEthAuthKey(cfg.GetEthAuthKeyPair()) assert.Nil(t, err) address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) diff --git a/config/configstore/bootstrapper.go b/config/configstore/bootstrapper.go index 0926df39c..cbe30bcda 100644 --- a/config/configstore/bootstrapper.go +++ b/config/configstore/bootstrapper.go @@ -21,13 +21,17 @@ func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { if !ok { return errors.NewTypedError(config.ErrConfigBootstrap, errors.New("could not find the storage repository")) } - idService, ok := context[identity.BootstrappedIDService].(identity.Service) + idFactory, ok := context[identity.BootstrappedDIDFactory].(identity.Factory) + if !ok { + return errors.New("identity factory service not initialised") + } + idService, ok := context[identity.BootstrappedDIDService].(identity.ServiceDID) if !ok { return errors.New("identity service not initialised") } repo := &repo{configdb} - service := &service{repo, idService, func() ProtocolSetter { + service := &service{repo, idFactory, idService, func() ProtocolSetter { return context[bootstrap.BootstrappedPeer].(ProtocolSetter) }} diff --git a/config/configstore/handler_test.go b/config/configstore/handler_test.go index 1e151532f..0a31185d8 100644 --- a/config/configstore/handler_test.go +++ b/config/configstore/handler_test.go @@ -15,7 +15,7 @@ import ( ) func TestGrpcHandler_GetConfigNoConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) @@ -27,7 +27,7 @@ func TestGrpcHandler_GetConfigNoConfig(t *testing.T) { } func TestGrpcHandler_GetConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) @@ -42,7 +42,7 @@ func TestGrpcHandler_GetConfig(t *testing.T) { } func TestGrpcHandler_GetAccountNotExist(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -54,7 +54,7 @@ func TestGrpcHandler_GetAccountNotExist(t *testing.T) { } func TestGrpcHandler_GetAccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -74,7 +74,7 @@ func TestGrpcHandler_GetAccount(t *testing.T) { } func TestGrpcHandler_deriveAllAccountResponseFailure(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -92,7 +92,7 @@ func TestGrpcHandler_deriveAllAccountResponseFailure(t *testing.T) { } func TestGrpcHandler_GetAllAccounts(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -117,7 +117,7 @@ func TestGrpcHandler_GetAllAccounts(t *testing.T) { } func TestGrpcHandler_CreateAccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -148,7 +148,7 @@ func TestGrpcHandler_GenerateAccount(t *testing.T) { } func TestGrpcHandler_UpdateAccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) diff --git a/config/configstore/model.go b/config/configstore/model.go index fbdc93fcb..fcacb0e7a 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -6,6 +6,13 @@ import ( "reflect" "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" @@ -53,6 +60,7 @@ type NodeConfig struct { BootstrapPeers []string NetworkID uint32 SmartContractAddresses map[config.ContractName]common.Address + SmartContractBytecode map[config.ContractName]string PprofEnabled bool } @@ -291,12 +299,12 @@ func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { return &configpb.ConfigData{ MainIdentity: &accountpb.AccountData{ EthAccount: &accountpb.EthereumAccount{ - Address: nc.MainIdentity.EthereumAccount.Address, + Address: common.BytesToAddress(nc.MainIdentity.IdentityID).Hex(), Key: nc.MainIdentity.EthereumAccount.Key, Password: nc.MainIdentity.EthereumAccount.Password, }, EthDefaultAccountName: nc.MainIdentity.EthereumDefaultAccountName, - IdentityId: hexutil.Encode(nc.MainIdentity.IdentityID), + IdentityId: common.BytesToAddress(nc.MainIdentity.IdentityID).Hex(), ReceiveEventNotificationEndpoint: nc.MainIdentity.ReceiveEventNotificationEndpoint, EthauthKeyPair: &accountpb.KeyPair{ Pub: nc.MainIdentity.EthAuthKeyPair.Pub, @@ -325,6 +333,7 @@ func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { NetworkId: nc.NetworkID, PprofEnabled: nc.PprofEnabled, SmartContractAddresses: convertAddressesToStringMap(nc.SmartContractAddresses), + SmartContractBytecode: convertBytecodeToStringMap(nc.SmartContractBytecode), } } @@ -336,8 +345,16 @@ func convertAddressesToStringMap(addresses map[config.ContractName]common.Addres return m } +func convertBytecodeToStringMap(bcode map[config.ContractName]string) map[string]string { + m := make(map[string]string) + for k, v := range bcode { + m[string(k)] = v + } + return m +} + func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) error { - identityID, _ := hexutil.Decode(data.MainIdentity.IdentityId) + identityID := common.HexToAddress(data.MainIdentity.IdentityId).Bytes() nc.MainIdentity = Account{ EthereumAccount: &config.AccountConfig{ @@ -381,6 +398,10 @@ func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) error { if err != nil { return err } + nc.SmartContractBytecode, err = convertStringMapToSmartContractBytecode(data.SmartContractBytecode) + if err != nil { + return err + } nc.PprofEnabled = data.PprofEnabled return nil } @@ -397,6 +418,14 @@ func convertStringMapToSmartContractAddresses(addrs map[string]string) (map[conf return m, nil } +func convertStringMapToSmartContractBytecode(bcode map[string]string) (map[config.ContractName]string, error) { + m := make(map[config.ContractName]string) + for k, v := range bcode { + m[config.ContractName(k)] = v + } + return m, nil +} + // NewNodeConfig creates a new NodeConfig instance with configs func NewNodeConfig(c config.Configuration) config.Configuration { mainAccount, _ := c.GetEthereumAccount(c.GetEthereumDefaultAccountName()) @@ -472,6 +501,7 @@ type Account struct { SigningKeyPair KeyPair EthAuthKeyPair KeyPair P2PKeyPair KeyPair + keys map[int]config.IDKey } // GetEthereumAccount gets EthereumAccount @@ -514,6 +544,82 @@ func (acc *Account) GetEthereumContextWaitTimeout() time.Duration { return acc.EthereumContextWaitTimeout } +// SignMsg signs a message with the signing key +func (acc *Account) SignMsg(msg []byte) (*coredocumentpb.Signature, error) { + //TODO change signing keys to curve ed25519 + keys, err := acc.GetKeys() + if err != nil { + return nil, err + } + signature, err := crypto.SignMessage(keys[identity.KeyPurposeSigning].PrivateKey, msg, crypto.CurveEd25519, true) + if err != nil { + return nil, err + } + + did, err := acc.GetIdentityID() + if err != nil { + return nil, err + } + + return &coredocumentpb.Signature{ + EntityId: did, + PublicKey: keys[identity.KeyPurposeSigning].PublicKey, + Signature: signature, + Timestamp: utils.ToTimestamp(time.Now().UTC()), + }, nil +} + +// GetKeys returns the keys of an account +// TODO remove GetKeys and add signing methods to account +func (acc *Account) GetKeys() (idKeys map[int]config.IDKey, err error) { + if acc.keys == nil { + acc.keys = map[int]config.IDKey{} + } + + if _, ok := acc.keys[identity.KeyPurposeP2P]; !ok { + pk, sk, err := ed25519.GetSigningKeyPair(acc.GetP2PKeyPair()) + if err != nil { + return idKeys, err + } + + acc.keys[identity.KeyPurposeP2P] = config.IDKey{ + PublicKey: pk, + PrivateKey: sk} + } + + if _, ok := acc.keys[identity.KeyPurposeSigning]; !ok { + pk, sk, err := ed25519.GetSigningKeyPair(acc.GetSigningKeyPair()) + if err != nil { + return idKeys, err + } + acc.keys[identity.KeyPurposeSigning] = config.IDKey{ + PublicKey: pk, + PrivateKey: sk} + } + + //secp256k1 keys + if _, ok := acc.keys[identity.KeyPurposeEthMsgAuth]; !ok { + pk, sk, err := secp256k1.GetEthAuthKey(acc.GetEthAuthKeyPair()) + if err != nil { + return idKeys, err + } + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + + acc.keys[identity.KeyPurposeEthMsgAuth] = config.IDKey{ + PublicKey: address32Bytes[:], + PrivateKey: sk} + } + + id, err := acc.GetIdentityID() + if err != nil { + return idKeys, err + } + acc.IdentityID = id + + return acc.keys, nil + +} + // ID Get the ID of the document represented by this model func (acc *Account) ID() []byte { return acc.IdentityID @@ -547,7 +653,7 @@ func (acc *Account) CreateProtobuf() (*accountpb.AccountData, error) { }, EthDefaultAccountName: acc.EthereumDefaultAccountName, ReceiveEventNotificationEndpoint: acc.ReceiveEventNotificationEndpoint, - IdentityId: hexutil.Encode(acc.IdentityID), + IdentityId: common.BytesToAddress(acc.IdentityID).Hex(), P2PKeyPair: &accountpb.KeyPair{ Pub: acc.P2PKeyPair.Pub, Pvt: acc.P2PKeyPair.Priv, diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 0aa29433c..6dc0c01f9 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -8,12 +8,13 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/config" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -263,7 +264,7 @@ func TestNewAccountConfig(t *testing.T) { c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() @@ -283,14 +284,14 @@ func TestNodeConfigProtobuf(t *testing.T) { assert.Equal(t, nc.GetServerPort(), int(ncpb.ServerPort)) i, err := nc.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, hexutil.Encode(i), ncpb.MainIdentity.IdentityId) + assert.Equal(t, common.BytesToAddress(i).Hex(), common.HexToAddress(ncpb.MainIdentity.IdentityId).Hex()) ncCopy := new(NodeConfig) err = ncCopy.loadFromProtobuf(ncpb) assert.NoError(t, err) assert.Equal(t, ncpb.StoragePath, ncCopy.StoragePath) assert.Equal(t, int(ncpb.ServerPort), ncCopy.ServerPort) - assert.Equal(t, ncpb.MainIdentity.IdentityId, hexutil.Encode(ncCopy.MainIdentity.IdentityID)) + assert.Equal(t, ncpb.MainIdentity.IdentityId, common.HexToAddress(ncpb.MainIdentity.IdentityId).Hex()) } func TestAccountProtobuf_validationFailures(t *testing.T) { @@ -298,7 +299,7 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil) c.On("GetEthereumDefaultAccountName").Return("dummyAcc") c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier") - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil) + c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil) c.On("GetP2PKeyPair").Return("pub", "priv") c.On("GetSigningKeyPair").Return("pub", "priv") c.On("GetEthAuthKeyPair").Return("pub", "priv") @@ -357,7 +358,7 @@ func TestAccountConfigProtobuf(t *testing.T) { c.On("GetEthereumAccount", "name").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() @@ -371,7 +372,8 @@ func TestAccountConfigProtobuf(t *testing.T) { assert.Equal(t, tc.GetReceiveEventNotificationEndpoint(), accpb.ReceiveEventNotificationEndpoint) i, err := tc.GetIdentityID() assert.Nil(t, err) - assert.Equal(t, hexutil.Encode(i), accpb.IdentityId) + + assert.Equal(t, common.BytesToAddress(i).Hex(), common.HexToAddress(accpb.IdentityId).Hex()) _, priv := tc.GetSigningKeyPair() assert.Equal(t, priv, accpb.SigningKeyPair.Pvt) @@ -379,7 +381,7 @@ func TestAccountConfigProtobuf(t *testing.T) { err = tcCopy.loadFromProtobuf(accpb) assert.NoError(t, err) assert.Equal(t, accpb.ReceiveEventNotificationEndpoint, tcCopy.ReceiveEventNotificationEndpoint) - assert.Equal(t, accpb.IdentityId, hexutil.Encode(tcCopy.IdentityID)) + assert.Equal(t, common.HexToAddress(accpb.IdentityId).Hex(), common.BytesToAddress(tcCopy.IdentityID).Hex()) assert.Equal(t, accpb.SigningKeyPair.Pvt, tcCopy.SigningKeyPair.Priv) } @@ -395,7 +397,7 @@ func createMockConfig() *mockConfig { c.On("GetNumWorkers").Return(2).Once() c.On("GetWorkerWaitTimeMS").Return(1).Once() c.On("GetEthereumNodeURL").Return("dummyNode").Once() - c.On("GetIdentityID").Return(utils.RandomSlice(6), nil).Once() + c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() diff --git a/config/configstore/repository_test.go b/config/configstore/repository_test.go index f5164b0d5..42a59f605 100644 --- a/config/configstore/repository_test.go +++ b/config/configstore/repository_test.go @@ -32,7 +32,8 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, } - ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} + ctx[identity.BootstrappedDIDService] = &testingcommons.MockIdentityService{} + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) configdb := ctx[storage.BootstrappedConfigDB].(storage.Repository) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) diff --git a/config/configstore/service.go b/config/configstore/service.go index da2da1776..53bcd8275 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -23,17 +23,18 @@ const ( // ProtocolSetter sets the protocol on host for the centID type ProtocolSetter interface { - InitProtocolForCID(CID identity.CentID) + InitProtocolForDID(DID *identity.DID) } type service struct { repo repository - idService identity.Service + idFactory identity.Factory + idService identity.ServiceDID protocolSetterFinder func() ProtocolSetter } // DefaultService returns an implementation of the config.Service -func DefaultService(repository repository, idService identity.Service) config.Service { +func DefaultService(repository repository, idService identity.ServiceDID) config.Service { return &service{repo: repository, idService: idService} } @@ -81,51 +82,39 @@ func (s service) GenerateAccount() (config.Account, error) { return nil, err } - id, confirmations, err := s.idService.CreateIdentity(ctx, identity.RandomCentID()) + DID, err := s.idFactory.CreateIdentity(ctx) if err != nil { return nil, err } - <-confirmations - CID := id.CentID() - acc, err = generateAccountKeys(nc.GetAccountsKeystore(), acc.(*Account), CID) + acc, err = generateAccountKeys(nc.GetAccountsKeystore(), acc.(*Account), DID) if err != nil { return nil, err } - err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeP2P) + err = s.idService.AddKeysForAccount(acc) if err != nil { return nil, err } - err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeSigning) - if err != nil { - return nil, err - } - - err = s.idService.AddKeyFromConfig(acc, identity.KeyPurposeEthMsgAuth) - if err != nil { - return nil, err - } - - err = s.repo.CreateAccount(CID[:], acc) + err = s.repo.CreateAccount(DID[:], acc) if err != nil { return nil, err } // initiate network handling - s.protocolSetterFinder().InitProtocolForCID(CID) + s.protocolSetterFinder().InitProtocolForDID(DID) return acc, nil } // generateAccountKeys generates signing and ethauth keys -func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*Account, error) { - acc.IdentityID = CID[:] - sPub, err := createKeyPath(keystore, CID, signingPubKeyName) +func generateAccountKeys(keystore string, acc *Account, DID *identity.DID) (*Account, error) { + acc.IdentityID = DID[:] + sPub, err := createKeyPath(keystore, DID, signingPubKeyName) if err != nil { return nil, err } - sPriv, err := createKeyPath(keystore, CID, signingPrivKeyName) + sPriv, err := createKeyPath(keystore, DID, signingPrivKeyName) if err != nil { return nil, err } @@ -133,11 +122,11 @@ func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*A Pub: sPub, Priv: sPriv, } - ePub, err := createKeyPath(keystore, CID, ethAuthPubKeyName) + ePub, err := createKeyPath(keystore, DID, ethAuthPubKeyName) if err != nil { return nil, err } - ePriv, err := createKeyPath(keystore, CID, ethAuthPrivKeyName) + ePriv, err := createKeyPath(keystore, DID, ethAuthPrivKeyName) if err != nil { return nil, err } @@ -156,8 +145,8 @@ func generateAccountKeys(keystore string, acc *Account, CID identity.CentID) (*A return acc, nil } -func createKeyPath(keyStorepath string, CID identity.CentID, keyName string) (string, error) { - tdir := fmt.Sprintf("%s/%s", keyStorepath, CID.String()) +func createKeyPath(keyStorepath string, DID *identity.DID, keyName string) (string, error) { + tdir := fmt.Sprintf("%s/%s", keyStorepath, DID.String()) // create account specific key dir if _, err := os.Stat(tdir); os.IsNotExist(err) { err := os.MkdirAll(tdir, os.ModePerm) diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go index 9bec65a63..a300e74bb 100644 --- a/config/configstore/service_integration_test.go +++ b/config/configstore/service_integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/stretchr/testify/assert" @@ -16,12 +18,13 @@ import ( "github.com/centrifuge/go-centrifuge/identity" ) -var identityService identity.Service -var cfg config.Service +var identityService identity.ServiceDID +var cfgSvc config.Service +var cfg config.Configuration type MockProtocolSetter struct{} -func (MockProtocolSetter) InitProtocolForCID(CID identity.CentID) { +func (MockProtocolSetter) InitProtocolForDID(DID *identity.DID) { // do nothing } @@ -29,32 +32,32 @@ func TestMain(m *testing.M) { // Adding delay to startup (concurrency hack) time.Sleep(time.Second + 2) ctx := testingbootstrap.TestFunctionalEthereumBootstrap() - cfg = ctx[config.BootstrappedConfigStorage].(config.Service) + cfgSvc = ctx[config.BootstrappedConfigStorage].(config.Service) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) ctx[bootstrap.BootstrappedPeer] = &MockProtocolSetter{} - identityService = ctx[identity.BootstrappedIDService].(identity.Service) + identityService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) } func TestService_GenerateAccountHappy(t *testing.T) { - tct, err := cfg.GenerateAccount() + tct, err := cfgSvc.GenerateAccount() assert.NoError(t, err) i, _ := tct.GetIdentityID() - tc, err := cfg.GetAccount(i) + tc, err := cfgSvc.GetAccount(i) assert.NoError(t, err) assert.NotNil(t, tc) i, _ = tc.GetIdentityID() - cid, err := identity.ToCentID(i) - assert.NoError(t, err) + did := identity.NewDIDFromBytes(i) assert.True(t, tc.GetEthereumDefaultAccountName() != "") pb, pv := tc.GetSigningKeyPair() err = checkKeyPair(t, pb, pv) pb, pv = tc.GetEthAuthKeyPair() err = checkKeyPair(t, pb, pv) - exists, err := identityService.CheckIdentityExists(cid) + ctxh := testingconfig.CreateAccountContext(t, cfg) + err = identityService.Exists(ctxh, did) assert.NoError(t, err) - assert.True(t, exists) } func checkKeyPair(t *testing.T, pb string, pv string) error { diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index 22de30e93..4befa4d87 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -14,7 +14,7 @@ import ( ) func TestService_GetConfig_NoConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) @@ -25,7 +25,7 @@ func TestService_GetConfig_NoConfig(t *testing.T) { } func TestService_GetConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) @@ -39,7 +39,7 @@ func TestService_GetConfig(t *testing.T) { } func TestService_GetAccount_NoAccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -50,7 +50,7 @@ func TestService_GetAccount_NoAccount(t *testing.T) { } func TestService_GetAccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -66,7 +66,7 @@ func TestService_GetAccount(t *testing.T) { } func TestService_CreateConfig(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterConfig(&NodeConfig{}) @@ -82,7 +82,7 @@ func TestService_CreateConfig(t *testing.T) { } func TestService_Createaccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -103,7 +103,7 @@ func TestService_Createaccount(t *testing.T) { } func TestService_Updateaccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -130,7 +130,7 @@ func TestService_Updateaccount(t *testing.T) { } func TestService_Deleteaccount(t *testing.T) { - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} repo, _, err := getRandomStorage() assert.Nil(t, err) repo.RegisterAccount(&Account{}) @@ -155,7 +155,9 @@ func TestService_Deleteaccount(t *testing.T) { } func TestGenerateaccountKeys(t *testing.T) { - tc, err := generateAccountKeys("/tmp/accounts/", &Account{}, identity.RandomCentID()) + DID, err := identity.NewDIDFromString("0xDcF1695B8a0df44c60825eCD0A8A833dA3875F13") + assert.NoError(t, err) + tc, err := generateAccountKeys("/tmp/accounts/", &Account{}, &DID) assert.Nil(t, err) assert.NotNil(t, tc.EthAuthKeyPair) _, err = os.Stat(tc.EthAuthKeyPair.Pub) diff --git a/config/configuration.go b/config/configuration.go index 95d1bdd7c..6060408a7 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -16,6 +16,7 @@ import ( "sync" "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/account" @@ -41,6 +42,9 @@ const ( // AnchorRepo is the contract name for AnchorRepo AnchorRepo ContractName = "anchorRepository" + // Identity is the contract name for Identity + Identity ContractName = "identity" + // IdentityFactory is the contract name for IdentityFactory IdentityFactory ContractName = "identityFactory" @@ -52,8 +56,8 @@ const ( ) // ContractNames returns the list of smart contract names currently used in the system, please update this when adding new contracts -func ContractNames() [4]ContractName { - return [4]ContractName{AnchorRepo, IdentityFactory, IdentityRegistry, PaymentObligation} +func ContractNames() [5]ContractName { + return [5]ContractName{AnchorRepo, IdentityFactory, Identity, IdentityRegistry, PaymentObligation} } // Configuration defines the methods that a config type should implement. @@ -116,7 +120,8 @@ type Configuration interface { // Account exposes account options type Account interface { storage.Model - + GetKeys() (map[int]IDKey, error) + SignMsg(msg []byte) (*coredocumentpb.Signature, error) GetEthereumAccount() *AccountConfig GetEthereumDefaultAccountName() string GetReceiveEventNotificationEndpoint() string @@ -142,6 +147,18 @@ type Service interface { DeleteAccount(identifier []byte) error } +// IDKey represents a key pair +type IDKey struct { + PublicKey []byte + PrivateKey []byte +} + +// IDKeys holds key of an identity +type IDKeys struct { + ID []byte + Keys map[int]IDKey +} + // configuration holds the configuration details for the node. type configuration struct { mu sync.RWMutex @@ -460,9 +477,9 @@ func (c *configuration) initializeViper() { c.v.SetEnvPrefix("CENT") } -// SmartContractAddresses encapsulates the smart contract addresses ne +// SmartContractAddresses encapsulates the smart contract addresses type SmartContractAddresses struct { - IdentityFactoryAddr, IdentityRegistryAddr, AnchorRepositoryAddr, PaymentObligationAddr string + IdentityFactoryAddr, AnchorRepositoryAddr, PaymentObligationAddr string } // CreateConfigFile creates minimum config file with arguments @@ -531,7 +548,6 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { if smartContractAddresses, ok := args["smartContractAddresses"].(*SmartContractAddresses); ok { v.Set("networks."+network+".contractAddresses.identityFactory", smartContractAddresses.IdentityFactoryAddr) - v.Set("networks."+network+".contractAddresses.identityRegistry", smartContractAddresses.IdentityRegistryAddr) v.Set("networks."+network+".contractAddresses.anchorRepository", smartContractAddresses.AnchorRepositoryAddr) v.Set("networks."+network+".contractAddresses.paymentObligation", smartContractAddresses.PaymentObligationAddr) } @@ -547,7 +563,6 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { func (c *configuration) SetupSmartContractAddresses(network string, smartContractAddresses *SmartContractAddresses) { c.v.Set("networks."+network+".contractAddresses.identityFactory", smartContractAddresses.IdentityFactoryAddr) - c.v.Set("networks."+network+".contractAddresses.identityRegistry", smartContractAddresses.IdentityRegistryAddr) c.v.Set("networks."+network+".contractAddresses.anchorRepository", smartContractAddresses.AnchorRepositoryAddr) c.v.Set("networks."+network+".contractAddresses.paymentObligation", smartContractAddresses.PaymentObligationAddr) } diff --git a/crypto/sign.go b/crypto/sign.go index d542b147d..d69c408bb 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -23,7 +23,7 @@ func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool return secp256k1.Sign(message, privateKey) case CurveEd25519: - return nil, errors.New("curve ed25519 not supported yet") + return ed25519.Sign(privateKey, message), nil default: return nil, errors.New("curve %s not supported", curveType) } @@ -42,9 +42,10 @@ func VerifySignature(pubKey, message, signature []byte) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated -func Sign(centIDBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { +// Deprecated +func Sign(didBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { return &coredocumentpb.Signature{ - EntityId: centIDBytes, + EntityId: didBytes, PublicKey: pubKey, Signature: ed25519.Sign(privateKey, payload), Timestamp: utils.ToTimestamp(time.Now().UTC()), diff --git a/crypto/verify_test.go b/crypto/verify_test.go index e389c1891..a5e955048 100644 --- a/crypto/verify_test.go +++ b/crypto/verify_test.go @@ -19,8 +19,8 @@ func TestVerifyMessageED25519(t *testing.T) { privateKey, err := utils.ReadKeyFromPemFile(privateKeyFile, utils.PrivateKey) assert.Nil(t, err) signature, err := SignMessage(privateKey, []byte(testMsg), CurveEd25519, false) - assert.NotNil(t, err) + assert.NoError(t, err) os.Remove(publicKeyFile) os.Remove(privateKeyFile) - assert.True(t, len(signature) == 0, "verify ed25519 is not implemented yet and should not work") + assert.Len(t, signature, 64) } diff --git a/documents/anchor.go b/documents/anchor.go index cc43164d7..cb9bc7e08 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -10,7 +10,7 @@ import ( // AnchorProcessor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type AnchorProcessor interface { - Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.CentID) (err error) + Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.DID) (err error) PrepareForSignatureRequests(ctx context.Context, model Model) error RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error diff --git a/documents/anchor_task.go b/documents/anchor_task.go index f8bc5c381..46a0160d2 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -34,7 +34,7 @@ type documentAnchorTask struct { txv1.BaseTask id []byte - accountID identity.CentID + accountID identity.DID // state config config.Service @@ -70,7 +70,7 @@ func (d *documentAnchorTask) ParseKwargs(kwargs map[string]interface{}) error { return errors.New("missing account ID") } - d.accountID, err = identity.CentIDFromString(accountID) + d.accountID, err = identity.NewDIDFromString(accountID) if err != nil { return errors.New("invalid cent ID") } @@ -120,7 +120,7 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { } // InitDocumentAnchorTask enqueues a new document anchor task for a given combination of accountID/modelID/txID. -func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, accountID identity.CentID, modelID []byte, txID transactions.TxID) (queue.TaskResult, error) { +func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, accountID identity.DID, modelID []byte, txID transactions.TxID) (queue.TaskResult, error) { params := map[string]interface{}{ transactions.TxIDParam: txID.String(), DocumentIDParam: hexutil.Encode(modelID), @@ -141,8 +141,8 @@ func InitDocumentAnchorTask(txMan transactions.Manager, tq queue.TaskQueuer, acc } // CreateAnchorTransaction creates a transaction for anchoring a document using transaction manager -func CreateAnchorTransaction(txMan transactions.Manager, tq queue.TaskQueuer, self identity.CentID, txID transactions.TxID, documentID []byte) (transactions.TxID, chan bool, error) { - txID, done, err := txMan.ExecuteWithinTX(context.Background(), self, txID, "anchor document", func(accountID identity.CentID, TID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { +func CreateAnchorTransaction(txMan transactions.Manager, tq queue.TaskQueuer, self identity.DID, txID transactions.TxID, documentID []byte) (transactions.TxID, chan bool, error) { + txID, done, err := txMan.ExecuteWithinTX(context.Background(), self, txID, "anchor document", func(accountID identity.DID, TID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { tr, err := InitDocumentAnchorTask(txMan, tq, accountID, documentID, TID) if err != nil { errChan <- err diff --git a/documents/anchor_task_test.go b/documents/anchor_task_test.go index ccfc00591..615f5bb26 100644 --- a/documents/anchor_task_test.go +++ b/documents/anchor_task_test.go @@ -5,7 +5,7 @@ package documents import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -54,7 +54,7 @@ func TestDocumentAnchorTask_ParseKwargs(t *testing.T) { kwargs: map[string]interface{}{ transactions.TxIDParam: transactions.NewTxID().String(), DocumentIDParam: hexutil.Encode(utils.RandomSlice(32)), - AccountIDParam: identity.RandomCentID().String(), + AccountIDParam: testingidentity.GenerateRandomDID().String(), }, }, } diff --git a/documents/bootstrapper.go b/documents/bootstrapper.go index 73867b25c..8ad66bc6f 100644 --- a/documents/bootstrapper.go +++ b/documents/bootstrapper.go @@ -36,17 +36,18 @@ func (Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } repo := NewDBRepository(ldb) - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) - if !ok { - return errors.New("identity service not initialised") - } anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) if !ok { return errors.New("anchor repository not initialised") } - ctx[BootstrappedDocumentService] = DefaultService(repo, idService, anchorRepo, registry) + didService, ok := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + if !ok { + return errors.New("identity service not initialized") + } + + ctx[BootstrappedDocumentService] = DefaultService(repo, anchorRepo, registry, didService) ctx[BootstrappedRegistry] = registry ctx[BootstrappedDocumentRepository] = repo return nil @@ -77,9 +78,9 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("document repository not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + didService, ok := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) if !ok { - return errors.New("identity service not initialised") + return errors.New("identity service not initialized") } anchorRepo, ok := ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) @@ -98,7 +99,7 @@ func (PostBootstrapper) Bootstrap(ctx map[string]interface{}) error { TxManager: txMan, }, config: cfgService, - processor: DefaultProcessor(idService, p2pClient, anchorRepo, cfg), + processor: DefaultProcessor(didService, p2pClient, anchorRepo, cfg), modelGetFunc: repo.Get, modelSaveFunc: repo.Update, } diff --git a/documents/bootstrapper_test.go b/documents/bootstrapper_test.go index 96fdf2c6e..a69967ad8 100644 --- a/documents/bootstrapper_test.go +++ b/documents/bootstrapper_test.go @@ -5,9 +5,10 @@ package documents import ( "testing" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/anchors" @@ -27,8 +28,9 @@ func TestBootstrapper_Bootstrap(t *testing.T) { ctx[bootstrap.BootstrappedConfig] = &testingconfig.MockConfig{} ctx[storage.BootstrappedDB] = repo ctx[transactions.BootstrappedService] = txv1.NewManager(&testingconfig.MockConfig{}, txv1.NewRepository(repo)) - ctx[identity.BootstrappedIDService] = new(testingcommons.MockIDService) ctx[anchors.BootstrappedAnchorRepo] = new(testinganchors.MockAnchorRepo) + ctx[identity.BootstrappedDIDService] = new(testingcommons.MockIdentityService) + err = Bootstrapper{}.Bootstrap(ctx) assert.Nil(t, err) assert.NotNil(t, ctx[BootstrappedRegistry]) diff --git a/documents/documents_test/anchor_test.go b/documents/documents_test/anchor_test.go index 430ebab29..aac5fa601 100644 --- a/documents/documents_test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -21,7 +21,7 @@ type mockAnchorProcessor struct { mock.Mock } -func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocumentModel *documents.CoreDocumentModel, recipient identity.CentID) (err error) { +func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocumentModel *documents.CoreDocumentModel, recipient identity.DID) (err error) { args := m.Called(coreDocumentModel, ctx, recipient) return args.Error(0) } diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index bb891c68a..6475ffd4e 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -3,10 +3,11 @@ package documents_test import ( - "math/big" "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -17,7 +18,6 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -28,7 +28,7 @@ import ( var testRepoGlobal documents.Repository var ( - cid = identity.RandomCentID() + cid = testingidentity.GenerateRandomDID() centIDBytes = cid[:] tenantID = cid[:] key1Pub = [...]byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} @@ -55,18 +55,18 @@ func TestMain(m *testing.M) { } func TestService_ReceiveAnchoredDocumentFailed(t *testing.T) { - poSrv := documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) + poSrv := documents.DefaultService(nil, nil, documents.NewServiceRegistry(), nil) ctxh := testingconfig.CreateAccountContext(t, cfg) err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) assert.Error(t, err) } -func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIDService) { +func getServiceWithMockedLayers() (documents.Service, testingcommons.MockIdentityService) { repo := testRepo() - idService := testingcommons.MockIDService{} - idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + idService := testingcommons.MockIdentityService{} + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() mockAnchor = &mockAnchorRepo{} - return documents.DefaultService(repo, &idService, mockAnchor, documents.NewServiceRegistry()), idService + return documents.DefaultService(repo, mockAnchor, documents.NewServiceRegistry(), &idService), idService } type mockAnchorRepo struct { @@ -98,21 +98,21 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, if err != nil { return nil, err } + cds, err := documents.GenerateNewSalts(corDocMod.Document, "", nil) assert.Nil(t, err) corDocMod.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cds) + err = corDocMod.CalculateSigningRoot(dataRoot) if err != nil { return nil, err } - centID, err := identity.ToCentID(centIDBytes) - assert.Nil(t, err) signKey := identity.IDKey{ PublicKey: key1Pub[:], PrivateKey: key1, } idConfig := &identity.IDConfig{ - ID: centID, + ID: cid, Keys: map[int]identity.IDKey{ identity.KeyPurposeSigning: signKey, }, @@ -122,6 +122,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = append(cd.Signatures, sig) + err = corDocMod.CalculateDocumentRoot() if err != nil { return nil, err @@ -179,19 +180,10 @@ func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Inv } // Functions returns service mocks -func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIDService, s documents.Service) testingcommons.MockIDService { - idkey := ðid.EthereumIdentityKey{ - Key: key1Pub, - Purposes: []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - RevokedAt: big.NewInt(0), - } +func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIdentityService, s documents.Service) testingcommons.MockIdentityService { anchorID, _ := anchors.ToAnchorID(i.CoreDocumentModel.Document.DocumentIdentifier) docRoot, _ := anchors.ToDocumentRoot(i.CoreDocumentModel.Document.DocumentRoot) mockAnchor.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - id := &testingcommons.MockID{} - centID, _ := identity.ToCentID(centIDBytes) - idService.On("LookupIdentityForID", centID).Return(id, nil).Once() - id.On("FetchKey", key1Pub[:]).Return(idkey, nil).Once() return idService } diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 85a72f77d..a9a60f037 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -41,9 +41,9 @@ type Invoice struct { NetAmount int64 // invoice amount excluding tax TaxAmount int64 TaxRate int64 - Recipient *identity.CentID - Sender *identity.CentID - Payee *identity.CentID + Recipient *identity.DID + Sender *identity.DID + Payee *identity.DID Comment string DueDate *timestamp.Timestamp DateCreated *timestamp.Timestamp @@ -185,16 +185,22 @@ func (i *Invoice) initInvoiceFromData(data *clientinvoicepb.InvoiceData) error { i.DueDate = data.DueDate i.DateCreated = data.DateCreated - if recipient, err := identity.CentIDFromString(data.Recipient); err == nil { - i.Recipient = &recipient + if data.Recipient != "" { + if recipient, err := identity.NewDIDFromString(data.Recipient); err == nil { + i.Recipient = &recipient + } } - if sender, err := identity.CentIDFromString(data.Sender); err == nil { - i.Sender = &sender + if data.Sender != "" { + if sender, err := identity.NewDIDFromString(data.Sender); err == nil { + i.Sender = &sender + } } - if payee, err := identity.CentIDFromString(data.Payee); err == nil { - i.Payee = &payee + if data.Payee != "" { + if payee, err := identity.NewDIDFromString(data.Payee); err == nil { + i.Payee = &payee + } } if data.ExtraData != "" { @@ -228,15 +234,18 @@ func (i *Invoice) loadFromP2PProtobuf(invoiceData *invoicepb.InvoiceData) { i.TaxAmount = invoiceData.TaxAmount i.TaxRate = invoiceData.TaxRate - if recipient, err := identity.ToCentID(invoiceData.Recipient); err == nil { + if invoiceData.Recipient != nil { + recipient := identity.NewDIDFromBytes(invoiceData.Recipient) i.Recipient = &recipient } - if sender, err := identity.ToCentID(invoiceData.Sender); err == nil { + if invoiceData.Sender != nil { + sender := identity.NewDIDFromBytes(invoiceData.Sender) i.Sender = &sender } - if payee, err := identity.ToCentID(invoiceData.Payee); err == nil { + if invoiceData.Payee != nil { + payee := identity.NewDIDFromBytes(invoiceData.Payee) i.Payee = &payee } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index ce6aef0f4..fa38f5f9d 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -8,8 +8,13 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + + "github.com/centrifuge/go-centrifuge/identity/ideth" + + "github.com/stretchr/testify/mock" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -19,7 +24,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" @@ -33,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) var ctx = map[string]interface{}{} @@ -54,7 +57,7 @@ func TestMain(m *testing.M) { &config.Bootstrapper{}, &leveldb.Bootstrapper{}, &queue.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, @@ -105,23 +108,6 @@ func TestInvoice_InitCoreDocument_successful(t *testing.T) { assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") } -func TestInvoice_InitCoreDocument_invalidCentId(t *testing.T) { - invoiceModel := &Invoice{} - - dm := CreateCDWithEmbeddedInvoice(t, invoicepb.InvoiceData{ - Recipient: utils.RandomSlice(identity.CentIDLength + 1), - Sender: utils.RandomSlice(identity.CentIDLength), - Payee: utils.RandomSlice(identity.CentIDLength), - GrossAmount: 42, - }) - invoiceModel.CoreDocumentModel = dm - err := invoiceModel.UnpackCoreDocument(dm) - assert.Nil(t, err) - assert.NotNil(t, invoiceModel.Sender) - assert.NotNil(t, invoiceModel.Payee) - assert.Nil(t, invoiceModel.Recipient) -} - func TestInvoice_CoreDocument_successful(t *testing.T) { invoiceModel := &Invoice{} @@ -227,7 +213,8 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Nil(t, inv.ExtraData) data.ExtraData = "0x010203020301" - data.Recipient = "0x010203040506" + recipientDID := testingidentity.GenerateRandomDID() + data.Recipient = recipientDID.String() err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) @@ -235,7 +222,8 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Nil(t, inv.Sender) assert.Nil(t, inv.Payee) - data.Sender = "0x010203060506" + senderDID := testingidentity.GenerateRandomDID() + data.Sender = senderDID.String() err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) @@ -243,7 +231,8 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.NotNil(t, inv.Sender) assert.Nil(t, inv.Payee) - data.Payee = "0x010203030405" + payeeDID := testingidentity.GenerateRandomDID() + data.Payee = payeeDID.String() err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) @@ -256,14 +245,18 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") - collabs = []string{"0x010102040506", "0x010203020302"} + collab1, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + collab2, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF3") + assert.NoError(t, err) + collabs = []string{collab1.String(), collab2.String()} err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Nil(t, err, "must be nil") - assert.Equal(t, inv.Sender[:], []byte{1, 2, 3, 6, 5, 6}) - assert.Equal(t, inv.Payee[:], []byte{1, 2, 3, 3, 4, 5}) - assert.Equal(t, inv.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) + assert.Equal(t, inv.Sender[:], senderDID[:]) + assert.Equal(t, inv.Payee[:], payeeDID[:]) + assert.Equal(t, inv.Recipient[:], recipientDID[:]) assert.Equal(t, inv.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - assert.Equal(t, inv.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + assert.Equal(t, inv.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], collab1[:], collab2[:]}) } func TestInvoiceModel_calculateDataRoot(t *testing.T) { diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 6534f7223..70aa89c55 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -131,8 +131,9 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod return nil, transactions.NilTxID(), nil, err } + DID := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, DID, txID, dm.Document.CurrentVersion) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -160,8 +161,9 @@ func (s service) Update(ctx context.Context, inv documents.Model) (documents.Mod return nil, transactions.NilTxID(), nil, err } + did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -177,10 +179,7 @@ func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.In cd := dm.Document collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { - cid, err := identity.ToCentID(c) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentCollaborator, err) - } + cid := identity.NewDIDFromBytes(c) collaborators[i] = cid.String() } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 7c2f5ca12..48bd29cbe 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -5,17 +5,18 @@ package invoice import ( "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -27,7 +28,7 @@ import ( ) var ( - cid = identity.RandomCentID() + cid = testingidentity.GenerateRandomDID() centIDBytes = cid[:] accountID = cid[:] ) @@ -50,17 +51,17 @@ func TestDefaultService(t *testing.T) { assert.NotNil(t, srv, "must be non-nil") } -func getServiceWithMockedLayers() (testingcommons.MockIDService, Service) { +func getServiceWithMockedLayers() (testingcommons.MockIdentityService, Service) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) - idService := testingcommons.MockIDService{} - idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + idService := testingcommons.MockIdentityService{} + idService.On("IsSignedWithPurpose", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil).Once() queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) repo := testRepo() mockAnchor := &mockAnchorRepo{} - docSrv := documents.DefaultService(repo, &idService, mockAnchor, documents.NewServiceRegistry()) + docSrv := documents.DefaultService(repo, mockAnchor, documents.NewServiceRegistry(), &idService) return idService, DefaultService( docSrv, repo, @@ -354,9 +355,9 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ - Sender: "0x010101010101", - Recipient: "0x010203040506", - Payee: "0x010203020406", + Sender: "0xed03fa80291ff5ddc284de6b51e716b130b05e20", + Recipient: "0xea939d5c0494b072c51565b191ee59b5d34fbf79", + Payee: "0x087d8ca6a16e6ce8d9ff55672e551a2828ab8e8c", GrossAmount: 42, ExtraData: "some data", Currency: "EUR", @@ -375,14 +376,14 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // success - wantCollab := utils.RandomSlice(6) - payload.Collaborators = []string{hexutil.Encode(wantCollab)} + wantCollab := testingidentity.GenerateRandomDID() + payload.Collaborators = []string{wantCollab.String()} doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) dm, err := doc.PackCoreDocument() assert.Nil(t, err) - assert.Equal(t, wantCollab, dm.Document.Collaborators[2]) + assert.Equal(t, wantCollab[:], dm.Document.Collaborators[2]) assert.Len(t, dm.Document.Collaborators, 3) oldDM, err := old.PackCoreDocument() assert.Nil(t, err) @@ -417,7 +418,7 @@ func TestService_Update(t *testing.T) { assert.Contains(t, err.Error(), "document not found") payload := testingdocuments.CreateInvoicePayload() - payload.Collaborators = []string{"0x010203040506"} + payload.Collaborators = []string{testingidentity.GenerateRandomDID().String()} inv, err := invSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) dm, err = inv.PackCoreDocument() @@ -439,7 +440,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) data.GrossAmount = 100 data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) - collab := hexutil.Encode(utils.RandomSlice(6)) + collab := testingidentity.GenerateRandomDID().String() newInv, err := invSrv.DeriveFromUpdatePayload(ctxh, &clientinvoicepb.InvoiceUpdatePayload{ Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), Collaborators: []string{collab}, diff --git a/documents/invoice/utils_test.go b/documents/invoice/utils_test.go index fe008c48b..eeb3709eb 100644 --- a/documents/invoice/utils_test.go +++ b/documents/invoice/utils_test.go @@ -1,3 +1,5 @@ +// +build unit + package invoice import ( diff --git a/documents/model.go b/documents/model.go index f485dbfe6..ccabc86a6 100644 --- a/documents/model.go +++ b/documents/model.go @@ -191,7 +191,7 @@ func (m *CoreDocumentModel) prepareNewVersion(collaborators []string) (*CoreDocu // NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts func (m *CoreDocumentModel) NewWithCollaborators(collaborators []string) (*CoreDocumentModel, error) { dm := NewCoreDocModel() - ids, err := identity.CentIDsFromStrings(collaborators) + ids, err := identity.NewDIDsFromStrings(collaborators) if err != nil { return nil, errors.New("failed to decode collaborator: %v", err) } @@ -440,7 +440,7 @@ func (m *CoreDocumentModel) CalculateSigningRoot(dataRoot []byte) error { // AccountCanRead validate if the core document can be read by the account . // Returns an error if not. -func (m *CoreDocumentModel) AccountCanRead(account identity.CentID) bool { +func (m *CoreDocumentModel) AccountCanRead(account identity.DID) bool { // loop though read rules, check all the rules return m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { _, found := isAccountInRole(role, account) @@ -518,7 +518,7 @@ func (m *CoreDocumentModel) UnpackCoreDocument() error { // initReadRules initiates the read rules for a given CoreDocumentModel. // Collaborators are given Read_Sign action. // if the rules are created already, this is a no-op. -func (m *CoreDocumentModel) initReadRules(collabs []identity.CentID) error { +func (m *CoreDocumentModel) initReadRules(collabs []identity.DID) error { cd := m.Document if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { return nil @@ -574,7 +574,7 @@ func (m *CoreDocumentModel) findRole(onRole func(rridx, ridx int, role *coredocu } // isAccountInRole returns the index of the collaborator and true if account is in the given role as collaborators. -func isAccountInRole(role *coredocumentpb.Role, account identity.CentID) (idx int, found bool) { +func isAccountInRole(role *coredocumentpb.Role, account identity.DID) (idx int, found bool) { for i, id := range role.Collaborators { if bytes.Equal(id, account[:]) { return i, true @@ -594,7 +594,7 @@ func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, er return nil, errors.New("role %d not found", key) } -func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.CentID) error { +func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.DID) error { if len(collabs) == 0 { return nil } @@ -616,15 +616,17 @@ func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.C return nil } -func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.CentID, err error) { +func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.DID, err error) { ocsm := make(map[string]struct{}) for _, c := range oldCollabs { - ocsm[hexutil.Encode(c)] = struct{}{} + cs := strings.ToLower(hexutil.Encode(c)) + ocsm[cs] = struct{}{} } var uc []string for _, c := range newCollabs { - if _, ok := ocsm[c]; ok { + cs := strings.ToLower(c) + if _, ok := ocsm[cs]; ok { continue } @@ -632,7 +634,7 @@ func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []i } for _, c := range uc { - id, err := identity.CentIDFromString(c) + id, err := identity.NewDIDFromString(c) if err != nil { return nil, err } @@ -644,14 +646,11 @@ func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []i } // GetExternalCollaborators returns collaborators of a document without the own centID. -func (m *CoreDocumentModel) GetExternalCollaborators(selfCentID identity.CentID) ([][]byte, error) { +func (m *CoreDocumentModel) GetExternalCollaborators(selfCentID identity.DID) ([][]byte, error) { var collabs [][]byte for _, collab := range m.Document.Collaborators { - collabID, err := identity.ToCentID(collab) - if err != nil { - return nil, errors.New("failed to convert to CentID: %v", err) - } + collabID := identity.NewDIDFromBytes(collab) if !selfCentID.Equal(collabID) { collabs = append(collabs, collab) } @@ -661,7 +660,7 @@ func (m *CoreDocumentModel) GetExternalCollaborators(selfCentID identity.CentID) } // NFTOwnerCanRead checks if the nft owner/account can read the document -func (m *CoreDocumentModel) NFTOwnerCanRead(registry common.Address, tokenID []byte, account identity.CentID) error { +func (m *CoreDocumentModel) NFTOwnerCanRead(registry common.Address, tokenID []byte, account identity.DID) error { // check if the account can read the doc if m.AccountCanRead(account) { return nil @@ -730,7 +729,7 @@ func (m *CoreDocumentModel) AddNFTToReadRules(registry common.Address, tokenID [ } //ValidateDocumentAccess validates the GetDocument request against the AccessType indicated in the request -func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) error { +func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, requesterCentID identity.DID) error { // checks which access type is relevant for the request switch docReq.GetAccessType() { case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: @@ -822,7 +821,7 @@ func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.N } // IsAccountInRole checks if the the account exists in the role provided -func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.CentID) bool { +func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.DID) bool { role, err := getRole(roleKey, m.Document.Roles) if err != nil { return false @@ -835,7 +834,7 @@ func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.Cen // GetNFTProofs generate proofs required to mint an NFT func (m *CoreDocumentModel) GetNFTProofs( dataRoot []byte, - account identity.CentID, + account identity.DID, registry common.Address, tokenID []byte, nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { @@ -922,7 +921,7 @@ func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) ( return fmt.Sprintf("nfts[%s]", key), nil } -func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.CentID) (pk string, err error) { +func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.DID) (pk string, err error) { role, err := getRole(roleKey, roles) if err != nil { return pk, err diff --git a/documents/model_test.go b/documents/model_test.go index 3c5e8a574..28979141b 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -8,19 +8,23 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/utils" @@ -51,10 +55,12 @@ func TestMain(m *testing.M) { &anchors.Bootstrapper{}, &Bootstrapper{}, } - ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} + ctx[identity.BootstrappedDIDService] = &testingcommons.MockIdentityService{} + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") @@ -67,36 +73,38 @@ func TestMain(m *testing.M) { } func Test_fetchUniqueCollaborators(t *testing.T) { - + o1 := testingidentity.GenerateRandomDID() + o2 := testingidentity.GenerateRandomDID() + n1 := testingidentity.GenerateRandomDID() tests := []struct { old [][]byte new []string - result []identity.CentID + result []identity.DID err bool }{ { - new: []string{"0x010203040506"}, - result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + new: []string{n1.String()}, + result: []identity.DID{n1}, }, { - old: [][]byte{{1, 2, 3, 2, 3, 1}}, - new: []string{"0x010203040506"}, - result: []identity.CentID{{1, 2, 3, 4, 5, 6}}, + old: [][]byte{o1[:]}, + new: []string{n1.String()}, + result: []identity.DID{n1}, }, { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, - new: []string{"0x010203040506"}, + old: [][]byte{o1[:], n1[:]}, + new: []string{n1.String()}, }, { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + old: [][]byte{o1[:], o2[:]}, }, // new collaborator with wrong format { - old: [][]byte{{1, 2, 3, 2, 3, 1}, {1, 2, 3, 4, 5, 6}}, + old: [][]byte{o1[:], o2[:]}, new: []string{"0x0102030405"}, err: true, }, @@ -128,9 +136,9 @@ func TestCoreDocumentModel_PrepareNewVersion(t *testing.T) { assert.Nil(t, newDocModel) // missing DocumentRoot - c1 := utils.RandomSlice(6) - c2 := utils.RandomSlice(6) - c := []string{hexutil.Encode(c1), hexutil.Encode(c2)} + c1 := testingidentity.GenerateRandomDID() + c2 := testingidentity.GenerateRandomDID() + c := []string{c1.String(), c2.String()} ndm, err := dm.PrepareNewVersion(c) assert.NotNil(t, err) assert.Nil(t, ndm) @@ -164,7 +172,7 @@ func TestReadACLs_initReadRules(t *testing.T) { assert.Error(t, err) assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) - cs := []identity.CentID{identity.RandomCentID()} + cs := []identity.DID{testingidentity.GenerateRandomDID()} err = dm.initReadRules(cs) assert.NoError(t, err) assert.Len(t, cd.ReadRules, 1) @@ -178,8 +186,7 @@ func TestReadACLs_initReadRules(t *testing.T) { func TestReadAccessValidator_AccountCanRead(t *testing.T) { dm := NewCoreDocModel() - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) + account := testingidentity.GenerateRandomDID() dm.Document.DocumentRoot = utils.RandomSlice(32) ndm, err := dm.PrepareNewVersion([]string{account.String()}) @@ -189,7 +196,7 @@ func TestReadAccessValidator_AccountCanRead(t *testing.T) { assert.NotNil(t, cd.Roles) // account who cant access - rcid := identity.RandomCentID() + rcid := testingidentity.GenerateRandomDID() assert.False(t, ndm.AccountCanRead(rcid)) // account can access @@ -386,7 +393,8 @@ func Test_addNFTToReadRules(t *testing.T) { assert.Error(t, err) dm.Document.DocumentRoot = utils.RandomSlice(32) - dm, err = dm.PrepareNewVersion([]string{"0x010203040506"}) + dm, err = dm.PrepareNewVersion([]string{testingidentity.GenerateRandomDID().String()}) + assert.NoError(t, err) cd := dm.Document assert.NoError(t, err) assert.Len(t, cd.ReadRules, 1) @@ -404,10 +412,9 @@ func Test_addNFTToReadRules(t *testing.T) { func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { dm := NewCoreDocModel() dm.Document.DocumentRoot = utils.RandomSlice(32) - account, err := identity.CentIDFromString("0x010203040506") - assert.NoError(t, err) + account := testingidentity.GenerateRandomDID() - dm, err = dm.PrepareNewVersion([]string{account.String()}) + dm, err := dm.PrepareNewVersion([]string{account.String()}) assert.NoError(t, err) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") @@ -417,7 +424,7 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { assert.NoError(t, err) // account not in read rules and nft missing - account, err = identity.CentIDFromString("0x010203040505") + account = testingidentity.GenerateRandomDID() assert.NoError(t, err) tokenID := utils.RandomSlice(32) err = dm.NFTOwnerCanRead(registry, tokenID, account) @@ -542,11 +549,11 @@ func TestCoreDocumentModel_IsNFTMinted(t *testing.T) { func TestCoreDocumentModel_IsAccountInRole(t *testing.T) { dm := NewCoreDocModel() - account := identity.RandomCentID() + account := testingidentity.GenerateRandomDID() roleKey := make([]byte, 32, 32) assert.False(t, dm.IsAccountInRole(roleKey, account)) - err := dm.initReadRules([]identity.CentID{account}) + err := dm.initReadRules([]identity.DID{account}) assert.NoError(t, err) assert.True(t, dm.IsAccountInRole(roleKey, account)) } @@ -594,15 +601,15 @@ func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { func TestCoreDocument_getRoleProofKey(t *testing.T) { dm := NewCoreDocModel() roleKey := make([]byte, 32, 32) - account := identity.RandomCentID() + account := testingidentity.GenerateRandomDID() pf, err := getRoleProofKey(dm.Document.Roles, roleKey, account) assert.Error(t, err) assert.Empty(t, pf) - err = dm.initReadRules([]identity.CentID{account}) + err = dm.initReadRules([]identity.DID{account}) assert.NoError(t, err) - pf, err = getRoleProofKey(dm.Document.Roles, roleKey, identity.RandomCentID()) + pf, err = getRoleProofKey(dm.Document.Roles, roleKey, testingidentity.GenerateRandomDID()) assert.Error(t, err) assert.True(t, errors.IsOfType(ErrNFTRoleMissing, err)) assert.Empty(t, pf) @@ -620,8 +627,8 @@ func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { assert.NoError(t, err) dm.Document.EmbeddedData = &any.Any{Value: utils.RandomSlice(32), TypeUrl: documenttypes.InvoiceDataTypeUrl} - account := identity.RandomCentID() - assert.NoError(t, dm.initReadRules([]identity.CentID{account})) + account := testingidentity.GenerateRandomDID() + assert.NoError(t, dm.initReadRules([]identity.DID{account})) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") tokenID := utils.RandomSlice(32) diff --git a/documents/processor.go b/documents/processor.go index 1463eeb3c..ef433c193 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -7,7 +7,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" @@ -27,19 +26,19 @@ type Client interface { GetSignaturesForDocument(ctx context.Context, model *CoreDocumentModel) error // after all signatures are collected the sender sends the document including the signatures - SendAnchoredDocument(ctx context.Context, receiverID identity.CentID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) + SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) } // defaultProcessor implements AnchorProcessor interface type defaultProcessor struct { - identityService identity.Service + identityService identity.ServiceDID p2pClient Client anchorRepository anchors.AnchorRepository config Config } // DefaultProcessor returns the default implementation of CoreDocument AnchorProcessor -func DefaultProcessor(idService identity.Service, p2pClient Client, repository anchors.AnchorRepository, config Config) AnchorProcessor { +func DefaultProcessor(idService identity.ServiceDID, p2pClient Client, repository anchors.AnchorRepository, config Config) AnchorProcessor { return defaultProcessor{ identityService: idService, p2pClient: p2pClient, @@ -49,7 +48,7 @@ func DefaultProcessor(idService identity.Service, p2pClient Client, repository a } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.CentID) (err error) { +func (dp defaultProcessor) Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.DID) (err error) { if coreDocModel == nil { return errors.New("passed coreDocModel is nil") } @@ -192,24 +191,19 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("failed to get anchor ID: %v", err) } - self, err := contextutil.Self(ctx) - if err != nil { - return err - } - - // generate message authentication code for the anchor call - mac, err := secp256k1.SignEthereum(anchors.GenerateCommitHash(anchorID, self.ID, rootHash), self.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) if err != nil { return errors.New("failed to generate ethereum MAC: %v", err) } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) - confirmations, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, self.ID, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, mac) - if err != nil { + done, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) + + isDone := <-done + + if !isDone { return errors.New("failed to commit anchor: %v", err) } - <-confirmations log.Infof("Anchored document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) return nil } @@ -238,13 +232,8 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error } for _, c := range extCollaborators { - cID, erri := identity.ToCentID(c) - if erri != nil { - err = errors.AppendError(err, erri) - continue - } - - erri = dp.Send(ctx, dm, cID) + DID := identity.NewDIDFromBytes(c) + erri := dp.Send(ctx, dm, DID) if erri != nil { err = errors.AppendError(err, erri) } diff --git a/documents/processor_test.go b/documents/processor_test.go index fbcfe8960..3271bc5ed 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" @@ -22,7 +24,7 @@ import ( func TestCoreDocumentProcessor_SendNilDocument(t *testing.T) { dp := DefaultProcessor(nil, nil, nil, cfg) - err := dp.Send(nil, nil, [identity.CentIDLength]byte{}) + err := dp.Send(nil, nil, identity.DID{}) assert.Error(t, err, "should have thrown an error") } @@ -48,7 +50,7 @@ func (m mockModel) CalculateDataRoot() ([]byte, error) { } func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { - srv := &testingcommons.MockIDService{} + srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed @@ -114,8 +116,14 @@ func (p p2pClient) GetSignaturesForDocument(ctx context.Context, model *CoreDocu return args.Error(0) } +func (p p2pClient) SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { + args := p.Called(ctx, receiverID, in) + resp, _ := args.Get(0).(*p2ppb.AnchorDocumentResponse) + return resp, args.Get(1).(error) +} + func TestDefaultProcessor_RequestSignatures(t *testing.T) { - srv := &testingcommons.MockIDService{} + srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed @@ -192,7 +200,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { } func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { - srv := &testingcommons.MockIDService{} + srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) // pack failed model := mockModel{} @@ -257,9 +265,9 @@ type mockRepo struct { anchors.AnchorRepository } -func (m mockRepo) CommitAnchor(ctx context.Context, anchorID anchors.AnchorID, documentRoot anchors.DocumentRoot, centID identity.CentID, documentProofs [][32]byte, signature []byte) (confirmations <-chan *anchors.WatchCommit, err error) { - args := m.Called(anchorID, documentRoot, centID, documentProofs, signature) - c, _ := args.Get(0).(chan *anchors.WatchCommit) +func (m mockRepo) CommitAnchor(ctx context.Context, anchorID anchors.AnchorID, documentRoot anchors.DocumentRoot, documentProofs [][32]byte) (done chan bool, err error) { + args := m.Called(anchorID, documentRoot, documentProofs) + c, _ := args.Get(0).(chan bool) return c, args.Error(1) } @@ -270,7 +278,7 @@ func (m mockRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.Document } func TestDefaultProcessor_AnchorDocument(t *testing.T) { - srv := &testingcommons.MockIDService{} + srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) @@ -291,7 +299,7 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "pre anchor validation failed") - // get ID failed + // success dm = NewCoreDocModel() cd := dm.Document cd.DataRoot = utils.RandomSlice(32) @@ -301,32 +309,22 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { } dm.setCoreDocumentSalts() assert.Nil(t, dm.CalculateSigningRoot(cd.DataRoot)) - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(5) - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) cd.Signatures = []*coredocumentpb.Signature{s} assert.Nil(t, dm.CalculateDocumentRoot()) assert.Nil(t, err) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - err = dp.AnchorDocument(context.Background(), model) - model.AssertExpectations(t) - srv.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "self value not found in the context") - // success model = mockModel{} model.On("PackCoreDocument").Return(dm, nil).Times(5) model.On("CalculateDataRoot").Return(cd.DataRoot, nil) srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() repo := mockRepo{} - ch := make(chan *anchors.WatchCommit, 1) - ch <- new(anchors.WatchCommit) - repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ch, nil).Once() + ch := make(chan bool, 1) + ch <- true + repo.On("CommitAnchor", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ch, nil).Once() dp.anchorRepository = repo err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) @@ -336,8 +334,8 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { } func TestDefaultProcessor_SendDocument(t *testing.T) { - srv := &testingcommons.MockIDService{} - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + srv := &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) // pack failed @@ -382,10 +380,13 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { repo := mockRepo{} repo.On("GetDocumentRootOf", mock.Anything).Return(docRoot, nil).Once() dp.anchorRepository = repo + p2pc := p2pClient{} + p2pc.On("SendAnchoredDocument", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("not found")).Once() + dp.p2pClient = p2pc err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) repo.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") + assert.Contains(t, err.Error(), "failed to send document to the node") } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index 7c14d091a..ed36845b5 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -43,7 +43,7 @@ type PurchaseOrder struct { NetAmount int64 // invoice amount excluding tax TaxAmount int64 TaxRate int64 - Recipient *identity.CentID + Recipient *identity.DID Order []byte OrderContact string Comment string @@ -200,8 +200,10 @@ func (p *PurchaseOrder) initPurchaseOrderFromData(data *clientpurchaseorderpb.Pu p.DeliveryDate = data.DeliveryDate p.DateCreated = data.DateCreated - if recipient, err := identity.CentIDFromString(data.Recipient); err == nil { - p.Recipient = &recipient + if data.Recipient != "" { + if recipient, err := identity.NewDIDFromString(data.Recipient); err == nil { + p.Recipient = &recipient + } } if data.ExtraData != "" { @@ -242,7 +244,8 @@ func (p *PurchaseOrder) loadFromP2PProtobuf(data *purchaseorderpb.PurchaseOrderD p.DateCreated = data.DateCreated p.ExtraData = data.ExtraData - if recipient, err := identity.ToCentID(data.Recipient); err == nil { + if data.Recipient != nil { + recipient := identity.NewDIDFromBytes(data.Recipient) p.Recipient = &recipient } } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 15fcd4180..fb8d109cc 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -8,8 +8,9 @@ import ( "reflect" "testing" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -19,12 +20,11 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" @@ -49,12 +49,12 @@ func TestMain(m *testing.M) { done := make(chan bool) txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(transactions.NilTxID(), done, nil) - ibootstappers := []bootstrap.TestBootstrapper{ + ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, &queue.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, @@ -63,12 +63,12 @@ func TestMain(m *testing.M) { &Bootstrapper{}, &queue.Starter{}, } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) + bootstrap.RunTestBootstrappers(ibootstrappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfg.Set("identityId", cid.String()) configService = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) + bootstrap.RunTestTeardown(ibootstrappers) os.Exit(result) } @@ -107,17 +107,6 @@ func TestPO_InitCoreDocument_successful(t *testing.T) { assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") } -func TestPO_InitCoreDocument_invalidCentId(t *testing.T) { - poModel := &PurchaseOrder{} - - coreDocumentModel := CreateCDWithEmbeddedPO(t, purchaseorderpb.PurchaseOrderData{ - Recipient: utils.RandomSlice(identity.CentIDLength + 1)}) - poModel.CoreDocumentModel = coreDocumentModel - err := poModel.UnpackCoreDocument(coreDocumentModel) - assert.Nil(t, err) - assert.Nil(t, poModel.Recipient) -} - func TestPO_CoreDocument_successful(t *testing.T) { poModel := &PurchaseOrder{} @@ -217,7 +206,7 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { assert.Nil(t, poModel.ExtraData) data.ExtraData = "0x010203020301" - data.Recipient = "0x010203040506" + data.Recipient = "0xed03fa80291ff5ddc284de6b51e716b130b05e20" err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) assert.Nil(t, err) @@ -229,14 +218,20 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") - collabs = []string{"0x010102040506", "0x010203020302"} + collab1, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + collab2, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF3") + assert.NoError(t, err) + collabs = []string{collab1.String(), collab2.String()} err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) assert.Nil(t, err, "must be nil") - assert.Equal(t, poModel.Recipient[:], []byte{1, 2, 3, 4, 5, 6}) + did, err := identity.NewDIDFromString("0xed03fa80291ff5ddc284de6b51e716b130b05e20") + assert.NoError(t, err) + assert.Equal(t, poModel.Recipient[:], did[:]) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], {1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}}) + assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], collab1[:], collab2[:]}) } func TestPOModel_calculateDataRoot(t *testing.T) { diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 4efaa9f9f..dbe43c251 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -111,8 +111,9 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, transactions.NilTxID(), nil, err } + did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) if err != nil { return nil, transactions.NilTxID(), nil, nil } @@ -141,8 +142,9 @@ func (s service) Update(ctx context.Context, po documents.Model) (documents.Mode return nil, transactions.NilTxID(), nil, err } + did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -232,11 +234,8 @@ func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.P cd := dm.Document collaborators := make([]string, len(cd.Collaborators)) for i, c := range cd.Collaborators { - cid, err := identity.ToCentID(c) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentCollaborator, err) - } - collaborators[i] = cid.String() + DID := identity.NewDIDFromBytes(c) + collaborators[i] = DID.String() } h := &clientpopb.ResponseHeader{ diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 8fc71e3be..75721e37c 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -5,18 +5,19 @@ package purchaseorder import ( "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions" @@ -28,7 +29,7 @@ import ( ) var ( - cid = identity.RandomCentID() + cid = testingidentity.GenerateRandomDID() accountID = cid[:] centIDBytes = cid[:] ) @@ -44,15 +45,15 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D return docRoot, args.Error(1) } -func getServiceWithMockedLayers() (*testingcommons.MockIDService, Service) { - idService := &testingcommons.MockIDService{} - idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) +func getServiceWithMockedLayers() (*testingcommons.MockIdentityService, Service) { + idService := &testingcommons.MockIdentityService{} + idService.On("IsSignedWithPurpose", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(true, nil).Once() queueSrv := new(testingutils.MockQueue) queueSrv.On("EnqueueJob", mock.Anything, mock.Anything).Return(&gocelery.AsyncResult{}, nil) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) repo := testRepo() mockAnchor := &mockAnchorRepo{} - docSrv := documents.DefaultService(repo, idService, mockAnchor, documents.NewServiceRegistry()) + docSrv := documents.DefaultService(repo, mockAnchor, documents.NewServiceRegistry(), idService) return idService, DefaultService(docSrv, repo, queueSrv, txManager) } @@ -80,7 +81,7 @@ func TestService_Update(t *testing.T) { assert.Contains(t, err.Error(), "document not found") payload := testingdocuments.CreatePOPayload() - payload.Collaborators = []string{"0x010203040506"} + payload.Collaborators = []string{testingidentity.GenerateRandomDID().String()} po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) dm, err = po.PackCoreDocument() @@ -102,7 +103,7 @@ func TestService_Update(t *testing.T) { assert.Nil(t, err) data.OrderAmount = 100 data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) - collab := hexutil.Encode(utils.RandomSlice(6)) + collab := testingidentity.GenerateRandomDID().String() newPO, err := poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{ Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), Collaborators: []string{collab}, @@ -174,7 +175,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { err = testRepo().Create(accountID, id, old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ - Recipient: "0x010203040506", + Recipient: "0xea939d5c0494b072c51565b191ee59b5d34fbf79", ExtraData: "some data", Currency: "EUR", } @@ -193,15 +194,15 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // success - wantCollab := utils.RandomSlice(6) - payload.Collaborators = []string{hexutil.Encode(wantCollab)} + wantCollab := testingidentity.GenerateRandomDID() + payload.Collaborators = []string{wantCollab.String()} doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) dm, err := doc.PackCoreDocument() cd := dm.Document assert.Nil(t, err) - assert.Equal(t, wantCollab, cd.Collaborators[2]) + assert.Equal(t, wantCollab[:], cd.Collaborators[2]) assert.Len(t, cd.Collaborators, 3) oldDM, err := old.PackCoreDocument() oldCD = oldDM.Document @@ -337,10 +338,11 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { m.AssertExpectations(t) assert.Nil(t, r) assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") + assert.Contains(t, err.Error(), "document is of invalid type") // derive data failed - cd.Collaborators = [][]byte{{1, 2, 3, 4, 5, 6}} + collab := testingidentity.GenerateRandomDID() + cd.Collaborators = [][]byte{collab[:]} m = &testingdocuments.MockModel{} m.On("PackCoreDocument").Return(dm, nil).Once() r, err = poSrv.DerivePurchaseOrderResponse(m) @@ -356,7 +358,7 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { r, err = poSrv.DerivePurchaseOrderResponse(po) assert.Nil(t, err) assert.Equal(t, payload.Data, r.Data) - assert.Equal(t, []string{cid.String(), "0x010101010101"}, r.Header.Collaborators) + assert.Equal(t, []string{cid.String(), payload.Collaborators[0]}, r.Header.Collaborators) } func createMockDocument() (*PurchaseOrder, error) { diff --git a/documents/purchaseorder/utils_test.go b/documents/purchaseorder/utils_test.go index 27560c5a9..88d9281ac 100644 --- a/documents/purchaseorder/utils_test.go +++ b/documents/purchaseorder/utils_test.go @@ -1,3 +1,5 @@ +// +build unit + package purchaseorder import ( diff --git a/documents/service.go b/documents/service.go index 4df28202a..3735f5c4a 100644 --- a/documents/service.go +++ b/documents/service.go @@ -67,10 +67,10 @@ type Service interface { // service implements Service type service struct { repo Repository - identityService identity.Service notifier notification.Sender anchorRepository anchors.AnchorRepository registry *ServiceRegistry + idService identity.ServiceDID } var srvLog = logging.Logger("document-service") @@ -78,15 +78,15 @@ var srvLog = logging.Logger("document-service") // DefaultService returns the default implementation of the service func DefaultService( repo Repository, - idService identity.Service, anchorRepo anchors.AnchorRepository, - registry *ServiceRegistry) Service { + registry *ServiceRegistry, + idService identity.ServiceDID) Service { return service{ repo: repo, anchorRepository: anchorRepo, notifier: notification.NewWebhookSender(), - identityService: idService, registry: registry, + idService: idService, } } @@ -142,7 +142,7 @@ func (s service) CreateProofs(ctx context.Context, documentID []byte, fields []s } func (s service) createProofs(model Model, fields []string) (*DocumentProof, error) { - if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + if err := PostAnchoredValidator(s.idService, s.anchorRepository).Validate(nil, model); err != nil { return nil, errors.NewTypedError(ErrDocumentInvalid, err) } proofs, err := model.CreateProofs(fields) @@ -175,7 +175,7 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co return nil, ErrDocumentConfigAccountID } - if err := SignatureRequestValidator(s.identityService).Validate(nil, model); err != nil { + if err := SignatureRequestValidator(s.idService).Validate(nil, model); err != nil { return nil, errors.NewTypedError(ErrDocumentInvalid, err) } @@ -227,7 +227,7 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende return errors.New("no model given") } - if err := PostAnchoredValidator(s.identityService, s.anchorRepository).Validate(nil, model); err != nil { + if err := PostAnchoredValidator(s.idService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(ErrDocumentInvalid, err) } diff --git a/documents/validator.go b/documents/validator.go index 05bb61b38..2f150111c 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -238,7 +238,7 @@ func documentRootValidator() Validator { // re-calculates the signature and compares with existing one // assumes signing_root is already generated and verified // Note: this needs to used only before document is sent for signatures from the collaborators -func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { +func readyForSignaturesValidator(didBytes, priv, pub []byte) Validator { return ValidatorFunc(func(_, model Model) error { dm, err := model.PackCoreDocument() if err != nil { @@ -250,7 +250,7 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { return errors.New("expecting only one signature") } - s := crypto.Sign(centIDBytes, priv, pub, cd.SigningRoot) + s := crypto.Sign(didBytes, priv, pub, cd.SigningRoot) sh := cd.Signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { err = errors.AppendError(err, NewError("cd_entity_id", "entity ID mismatch")) @@ -272,7 +272,7 @@ func readyForSignaturesValidator(centIDBytes, priv, pub []byte) Validator { // assumes signing root is verified // Note: can be used when during the signature request on collaborator side and post signature collection on sender side // Note: this will break the current flow where we proceed to anchor even signatures verification fails -func signaturesValidator(idService identity.Service) Validator { +func signaturesValidator(idService identity.ServiceDID) Validator { return ValidatorFunc(func(_, model Model) error { dm, err := model.PackCoreDocument() if err != nil { @@ -285,15 +285,13 @@ func signaturesValidator(idService identity.Service) Validator { } for _, sig := range cd.Signatures { - if erri := idService.ValidateSignature(sig, cd.SigningRoot); erri != nil { + erri := idService.ValidateSignature(sig, cd.SigningRoot) + if erri != nil { err = errors.AppendError( - err, - NewError( - fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), - fmt.Sprintf("signature verification failed: %v", erri))) + erri, + errors.New(fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), fmt.Sprintf("signature verification failed: %v", err))) } } - return err }) } @@ -336,7 +334,7 @@ func anchoredValidator(repo anchors.AnchorRepository) Validator { // signing root validator // signatures validator // should be used when node receives a document requesting for signature -func SignatureRequestValidator(idService identity.Service) ValidatorGroup { +func SignatureRequestValidator(idService identity.ServiceDID) ValidatorGroup { return PostSignatureRequestValidator(idService) } @@ -346,7 +344,7 @@ func SignatureRequestValidator(idService identity.Service) ValidatorGroup { // document root validator // signatures validator // should be called before pre anchoring -func PreAnchorValidator(idService identity.Service) ValidatorGroup { +func PreAnchorValidator(idService identity.ServiceDID) ValidatorGroup { return ValidatorGroup{ PostSignatureRequestValidator(idService), documentRootValidator(), @@ -357,7 +355,7 @@ func PreAnchorValidator(idService identity.Service) ValidatorGroup { // PreAnchorValidator // anchoredValidator // should be called after anchoring the document/when received anchored document -func PostAnchoredValidator(idService identity.Service, repo anchors.AnchorRepository) ValidatorGroup { +func PostAnchoredValidator(idService identity.ServiceDID, repo anchors.AnchorRepository) ValidatorGroup { return ValidatorGroup{ PreAnchorValidator(idService), anchoredValidator(repo), @@ -382,7 +380,7 @@ func PreSignatureRequestValidator(centIDBytes, priv, pub []byte) ValidatorGroup // signingRootValidator // signaturesValidator // should be called after the signature collection/before preparing for anchoring -func PostSignatureRequestValidator(idService identity.Service) ValidatorGroup { +func PostSignatureRequestValidator(idService identity.ServiceDID) ValidatorGroup { return ValidatorGroup{ baseValidator(), signingRootValidator(), diff --git a/documents/validator_test.go b/documents/validator_test.go index 4ffadab8f..b69bd6e41 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -294,14 +294,17 @@ func TestValidator_documentRootValidator(t *testing.T) { } func TestValidator_selfSignatureValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) - idKeys := self.Keys[identity.KeyPurposeSigning] - rfsv := readyForSignaturesValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) + account, _ := contextutil.Account(testingconfig.CreateAccountContext(t, cfg)) + keys, err := account.GetKeys() + assert.Nil(t, err) + accID, err := account.GetIdentityID() + assert.NoError(t, err) + rfsv := readyForSignaturesValidator(accID, keys[identity.KeyPurposeSigning].PrivateKey, keys[identity.KeyPurposeSigning].PublicKey) // fail getCoreDoc model := mockModel{} model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() - err := rfsv.Validate(nil, model) + err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -334,10 +337,11 @@ func TestValidator_selfSignatureValidator(t *testing.T) { // success cd.SigningRoot = utils.RandomSlice(32) - c, err := identity.GetIdentityConfig(cfg) + + signature, err := account.SignMsg(cd.SigningRoot) assert.Nil(t, err) - s = identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} + + cd.Signatures = []*coredocumentpb.Signature{signature} model = mockModel{} model.On("PackCoreDocument").Return(dm, nil).Once() err = rfsv.Validate(nil, model) @@ -346,7 +350,7 @@ func TestValidator_selfSignatureValidator(t *testing.T) { } func TestValidator_signatureValidator(t *testing.T) { - srv := &testingcommons.MockIDService{} + srv := &testingcommons.MockIdentityService{} ssv := signaturesValidator(srv) // fail getCoreDoc diff --git a/ethereum/geth_client.go b/ethereum/geth_client.go index 7ef4f6079..6cc0c4513 100644 --- a/ethereum/geth_client.go +++ b/ethereum/geth_client.go @@ -199,7 +199,7 @@ func (gc *gethClient) getGethTxOpts(accountName string) (*bind.TransactOpts, err // QueueEthTXStatusTask starts a new queuing transaction check task. func QueueEthTXStatusTask( - accountID identity.CentID, + accountID identity.DID, txID transactions.TxID, txHash common.Hash, queuer queue.TaskQueuer) (res queue.TaskResult, err error) { diff --git a/ethereum/geth_client_integration_test.go b/ethereum/geth_client_integration_test.go index ede20a595..1b654d8c3 100644 --- a/ethereum/geth_client_integration_test.go +++ b/ethereum/geth_client_integration_test.go @@ -7,14 +7,15 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/identity/ideth" "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -58,7 +59,7 @@ func TestMain(m *testing.M) { txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, } diff --git a/ethereum/transaction_status_task.go b/ethereum/transaction_status_task.go index 81d8f9873..7bf6bc418 100644 --- a/ethereum/transaction_status_task.go +++ b/ethereum/transaction_status_task.go @@ -51,7 +51,7 @@ type TransactionStatusTask struct { //txHash is the id of an Ethereum transaction txHash string - accountID identity.CentID + accountID identity.DID } // NewTransactionStatusTask returns a the struct for the task @@ -102,7 +102,7 @@ func (tst *TransactionStatusTask) ParseKwargs(kwargs map[string]interface{}) (er return errors.New("missing account ID") } - tst.accountID, err = identity.CentIDFromString(accountID) + tst.accountID, err = identity.NewDIDFromString(accountID) if err != nil { return err } diff --git a/ethereum/transaction_status_task_integration_test.go b/ethereum/transaction_status_task_integration_test.go index 3b636a3c9..681d0afc3 100644 --- a/ethereum/transaction_status_task_integration_test.go +++ b/ethereum/transaction_status_task_integration_test.go @@ -6,6 +6,8 @@ import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" @@ -14,12 +16,12 @@ import ( "github.com/stretchr/testify/assert" ) -func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.CentID, transactions.TxID, chan bool) { +func enqueueJob(t *testing.T, txHash string) (transactions.Manager, identity.DID, transactions.TxID, chan bool) { queueSrv := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) - cid := identity.RandomCentID() - tx, done, err := txManager.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "Check TX status", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { + cid := testingidentity.GenerateRandomDID() + tx, done, err := txManager.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "Check TX status", func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, errChan chan<- error) { result, err := queueSrv.EnqueueJob(ethereum.EthTXStatusTaskName, map[string]interface{}{ transactions.TxIDParam: txID.String(), ethereum.TransactionAccountParam: cid.String(), diff --git a/ethereum/transaction_status_task_test.go b/ethereum/transaction_status_task_test.go index 6cd75df20..9c071b1e3 100644 --- a/ethereum/transaction_status_task_test.go +++ b/ethereum/transaction_status_task_test.go @@ -5,7 +5,8 @@ package ethereum import ( "testing" - "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" @@ -15,7 +16,7 @@ func TestMintingConfirmationTask_ParseKwargs_success(t *testing.T) { task := TransactionStatusTask{} txHash := "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515" txID := transactions.NewTxID().String() - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() kwargs := map[string]interface{}{ transactions.TxIDParam: txID, @@ -39,10 +40,10 @@ func TestMintingConfirmationTask_ParseKwargs_fail(t *testing.T) { tests := []map[string]interface{}{ { transactions.TxIDParam: transactions.NewTxID().String(), - TransactionAccountParam: identity.RandomCentID().String(), + TransactionAccountParam: testingidentity.GenerateRandomDID().String(), }, { - TransactionAccountParam: identity.RandomCentID().String(), + TransactionAccountParam: testingidentity.GenerateRandomDID().String(), TransactionTxHashParam: "0xd18036d7c1fe109af377e8ce1d9096e69a5df0741fba7e4f3507f8e6aa573515", }, { diff --git a/identity/did.go b/identity/did.go new file mode 100644 index 000000000..9fe0fc0f0 --- /dev/null +++ b/identity/did.go @@ -0,0 +1,312 @@ +package identity + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/utils" + + "github.com/centrifuge/go-centrifuge/crypto/ed25519" + "github.com/ethereum/go-ethereum/common" +) + +const ( + + // ErrMalformedAddress standard error for malformed address + ErrMalformedAddress = errors.Error("malformed address provided") + + // BootstrappedDIDFactory stores the id of the factory + BootstrappedDIDFactory string = "BootstrappedDIDFactory" + + // BootstrappedDIDService stores the id of the service + BootstrappedDIDService string = "BootstrappedDIDService" + + // CentIDLength is the length in bytes of the DID + CentIDLength = 6 + + // KeyPurposeP2P represents a key used for p2p txns + KeyPurposeP2P = 1 + + // KeyPurposeSigning represents a key used for signing + KeyPurposeSigning = 2 + + // KeyPurposeEthMsgAuth represents a key used for ethereum txns + KeyPurposeEthMsgAuth = 3 + + // KeyTypeECDSA has the value one in the ERC725 identity contract + KeyTypeECDSA = 1 +) + +// DID stores the identity address of the user +type DID common.Address + +// DIDLength contains the length of a DID +const DIDLength = common.AddressLength + +// ToAddress returns the DID as common.Address +func (d DID) ToAddress() common.Address { + return common.Address(d) +} + +// String returns the DID as HEX String +func (d DID) String() string { + return d.ToAddress().String() +} + +// BigInt returns DID in bigInt +func (d DID) BigInt() *big.Int { + return utils.ByteSliceToBigInt(d[:]) +} + +// Equal checks if d == other +func (d DID) Equal(other DID) bool { + for i := range d { + if d[i] != other[i] { + return false + } + } + return true +} + +// NewDID returns a DID based on a common.Address +func NewDID(address common.Address) DID { + return DID(address) +} + +// NewDIDFromString returns a DID based on a hex string +func NewDIDFromString(address string) (DID, error) { + if !common.IsHexAddress(address) { + return DID{}, ErrMalformedAddress + } + return DID(common.HexToAddress(address)), nil +} + +// NewDIDsFromStrings converts hex ids to DIDs +func NewDIDsFromStrings(ids []string) ([]DID, error) { + var cids []DID + for _, id := range ids { + cid, err := NewDIDFromString(id) + if err != nil { + return nil, err + } + + cids = append(cids, cid) + } + + return cids, nil +} + +// NewDIDFromBytes returns a DID based on a bytes input +func NewDIDFromBytes(bAddr []byte) DID { + return DID(common.BytesToAddress(bAddr)) +} + +//// NewDIDFromContext returns DID from context.Account +//func NewDIDFromContext(ctx context.Context) (DID, error) { +// tc, err := contextutil.Account(ctx) +// if err != nil { +// return DID{}, err +// } +// +// addressByte, err := tc.GetIdentityID() +// if err != nil { +// return DID{}, err +// } +// return NewDID(common.BytesToAddress(addressByte)), nil +//} + +// Factory is the interface for factory related interactions +type Factory interface { + CreateIdentity(ctx context.Context) (id *DID, err error) + CalculateIdentityAddress(ctx context.Context) (*common.Address, error) +} + +// NewDIDFromByte returns a DID based on a byte slice +func NewDIDFromByte(did []byte) DID { + return DID(common.BytesToAddress(did)) +} + +// ServiceDID interface contains the methods to interact with the identity contract +type ServiceDID interface { + // AddKey adds a key to identity contract + AddKey(ctx context.Context, key KeyDID) error + + // AddKeysForAccount adds key from configuration + AddKeysForAccount(acc config.Account) error + + // GetKey return a key from the identity contract + GetKey(did DID, key [32]byte) (*KeyResponse, error) + + // RawExecute calls the execute method on the identity contract + RawExecute(ctx context.Context, to common.Address, data []byte) error + + // Execute creates the abi encoding an calls the execute method on the identity contract + Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error + + // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys + IsSignedWithPurpose(did DID, message [32]byte, signature []byte, purpose *big.Int) (bool, error) + + // AddMultiPurposeKey adds a key with multiple purposes + AddMultiPurposeKey(context context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error + + // RevokeKey revokes an existing key in the smart contract + RevokeKey(ctx context.Context, key [32]byte) error + + // GetClientP2PURL returns the p2p url associated with the did + GetClientP2PURL(did DID) (string, error) + + //Exists checks if an identity contract exists + Exists(ctx context.Context, did DID) error + + // ValidateKey checks if a given key is valid for the given centrifugeID. + ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error + + // ValidateSignature checks if signature is valid for given identity + ValidateSignature(signature *coredocumentpb.Signature, message []byte) error + + // CurrentP2PKey retrieves the last P2P key stored in the identity + CurrentP2PKey(did DID) (ret string, err error) + + // GetClientsP2PURLs returns p2p urls associated with each centIDs + // will error out at first failure + GetClientsP2PURLs(dids []*DID) ([]string, error) + + // GetKeysByPurpose returns keys grouped by purpose from the identity contract. + GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) +} + +// KeyDID defines a single ERC725 identity key +type KeyDID interface { + GetKey() [32]byte + GetPurpose() *big.Int + GetRevokedAt() *big.Int + GetType() *big.Int +} + +// KeyResponse contains the needed fields of the GetKey response +type KeyResponse struct { + Key [32]byte + Purposes []*big.Int + RevokedAt *big.Int +} + +// Key holds the identity related details +type key struct { + Key [32]byte + Purpose *big.Int + RevokedAt *big.Int + Type *big.Int +} + +//NewKey returns a new key struct +func NewKey(pk [32]byte, purpose *big.Int, keyType *big.Int) KeyDID { + return &key{pk, purpose, big.NewInt(0), keyType} +} + +// GetKey returns the public key +func (idk *key) GetKey() [32]byte { + return idk.Key +} + +// GetPurposes returns the purposes intended for the key +func (idk *key) GetPurpose() *big.Int { + return idk.Purpose +} + +// GetRevokedAt returns the block at which the identity is revoked +func (idk *key) GetRevokedAt() *big.Int { + return idk.RevokedAt +} + +// GetType returns the type of the key +func (idk *key) GetType() *big.Int { + return idk.Type +} + +// String prints the peerID extracted from the key +func (idk *key) String() string { + peerID, _ := ed25519.PublicKeyToP2PKey(idk.Key) + return fmt.Sprintf("%s", peerID.Pretty()) +} + +// IDKey represents a key pair +type IDKey struct { + PublicKey []byte + PrivateKey []byte +} + +// IDKeys holds key of an identity +type IDKeys struct { + ID []byte + Keys map[int]IDKey +} + +// Config defines methods required for the package identity. +type Config interface { + GetEthereumDefaultAccountName() string + GetIdentityID() ([]byte, error) + GetP2PKeyPair() (pub, priv string) + GetSigningKeyPair() (pub, priv string) + GetEthAuthKeyPair() (pub, priv string) + GetEthereumContextWaitTimeout() time.Duration +} + +// IDConfig holds information about the identity +// Deprecated +type IDConfig struct { + ID DID + Keys map[int]IDKey +} + +// GetIdentityConfig returns the identity and keys associated with the node. +func GetIdentityConfig(config Config) (*IDConfig, error) { + centIDBytes, err := config.GetIdentityID() + if err != nil { + return nil, err + } + centID := NewDIDFromBytes(centIDBytes) + + //ed25519 keys + keys := map[int]IDKey{} + + pk, sk, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) + if err != nil { + return nil, err + } + keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} + + pk, sk, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + if err != nil { + return nil, err + } + keys[KeyPurposeSigning] = IDKey{PublicKey: pk, PrivateKey: sk} + + //secp256k1 keys + pk, sk, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) + if err != nil { + return nil, err + } + pubKey, err := hexutil.Decode(secp256k1.GetAddress(pk)) + if err != nil { + return nil, err + } + keys[KeyPurposeEthMsgAuth] = IDKey{PublicKey: pubKey, PrivateKey: sk} + + return &IDConfig{ID: centID, Keys: keys}, nil +} + +// Sign the document with the private key and return the signature along with the public key for the verification +// assumes that signing root for the document is generated +// Deprecated +func Sign(idConfig *IDConfig, purpose int, payload []byte) *coredocumentpb.Signature { + return crypto.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) +} diff --git a/identity/did/bootstrapper.go b/identity/did/bootstrapper.go deleted file mode 100644 index 5ee3e08ad..000000000 --- a/identity/did/bootstrapper.go +++ /dev/null @@ -1,179 +0,0 @@ -package did - -import ( - "io/ioutil" - "os" - "os/exec" - "path" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/savaki/jq" -) - -// Bootstrapper implements bootstrap.Bootstrapper. -type Bootstrapper struct{} - -// BootstrappedDIDFactory stores the id of the factory -const BootstrappedDIDFactory string = "BootstrappedDIDFactory" - -// BootstrappedDIDService stores the id of the service -const BootstrappedDIDService string = "BootstrappedDIDService" - -var smartContractAddresses *config.SmartContractAddresses - -// Bootstrap initializes the factory contract -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { - return errors.New("ethereum client hasn't been initialized") - } - client := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) - - // TODO line will be removed after migration - migrateNewIdentityContracts() - - factoryContract, err := bindFactory(getFactoryAddress(), client) - if err != nil { - return err - } - - txManager, ok := context[transactions.BootstrappedService].(transactions.Manager) - if !ok { - return errors.New("transactions repository not initialised") - } - - queueSrv, ok := context[bootstrap.BootstrappedQueueServer].(*queue.Server) - if !ok { - return errors.New("queue hasn't been initialized") - } - - factory := NewFactory(factoryContract, client, txManager, queueSrv) - context[BootstrappedDIDFactory] = factory - - service := NewService(client, txManager, queueSrv) - context[BootstrappedDIDService] = service - - return nil -} - -func bindFactory(factoryAddress common.Address, client ethereum.Client) (*FactoryContract, error) { - return NewFactoryContract(factoryAddress, client.GetEthClient()) -} - -func getFactoryAddress() common.Address { - return common.HexToAddress(smartContractAddresses.IdentityFactoryAddr) - -} - -func getAnchorAddress() common.Address { - return common.HexToAddress(smartContractAddresses.AnchorRepositoryAddr) -} - -// Note: this block will be removed after the identity migration is done -// currently we are using two versions of centrifuge contracts to not break the compatiblitiy -// --------------------------------------------------------------------------------------------------------------------- -func migrateNewIdentityContracts() { - runNewSmartContractMigrations() - smartContractAddresses = GetSmartContractAddresses() - -} - -// RunNewSmartContractMigrations migrates smart contracts to localgeth -// TODO: func will be removed after migration -func runNewSmartContractMigrations() { - - gp := os.Getenv("GOPATH") - projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") - - smartContractDir := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts") - smartContractDirStandard := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts") - - os.Setenv("CENT_ETHEREUM_CONTRACTS_DIR", smartContractDir) - - migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") - _, err := exec.Command(migrationScript, projDir).Output() - if err != nil { - log.Fatal(err) - } - os.Setenv("CENT_ETHEREUM_CONTRACTS_DIR", smartContractDirStandard) - -} - -// GetSmartContractAddresses finds migrated smart contract addresses for localgeth -// TODO: func will be removed after migration -func GetSmartContractAddresses() *config.SmartContractAddresses { - dat, err := findContractDeployJSON() - if err != nil { - panic(err) - } - idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") - anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") - payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") - return &config.SmartContractAddresses{ - IdentityFactoryAddr: getOpField(idFactoryAddrOp, dat), - AnchorRepositoryAddr: getOpField(anchorRepoAddrOp, dat), - PaymentObligationAddr: getOpField(payObAddrOp, dat), - } -} -func getFileFromContractRepo(filePath string) ([]byte, error) { - gp := os.Getenv("GOPATH") - projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") - deployJSONFile := path.Join(projDir, "vendor", "github.com", "manuelpolzhofer", "centrifuge-ethereum-contracts", filePath) - dat, err := ioutil.ReadFile(deployJSONFile) - if err != nil { - return nil, err - } - return dat, nil -} - -// TODO: func will be refactored after migration -func getIdentityByteCode() string { - dat, err := findContractDeployJSON() - if err != nil { - panic(err) - } - optByte := getOpForContract(".contracts.Identity.bytecode") - byteCodeHex := getOpField(optByte, dat) - return byteCodeHex - -} - -// TODO: func will be removed after migration -func findContractDeployJSON() ([]byte, error) { - return getFileFromContractRepo(path.Join("deployments", "localgeth.json")) -} - -// TODO: func will be removed after migration -func getOpForContract(selector string) jq.Op { - addrOp, err := jq.Parse(selector) - if err != nil { - panic(err) - } - return addrOp -} - -// TODO: func will be removed after migration -func getOpField(addrOp jq.Op, dat []byte) string { - addr, err := addrOp.Apply(dat) - if err != nil { - panic(err) - } - - // remove extra quotes inside the string - addrStr := string(addr) - if len(addrStr) > 0 && addrStr[0] == '"' { - addrStr = addrStr[1:] - } - if len(addrStr) > 0 && addrStr[len(addrStr)-1] == '"' { - addrStr = addrStr[:len(addrStr)-1] - } - return addrStr -} - -// --------------------------------------------------------------------------------------------------------------------- diff --git a/identity/did/key.go b/identity/did/key.go deleted file mode 100644 index 8372099e9..000000000 --- a/identity/did/key.go +++ /dev/null @@ -1,62 +0,0 @@ -package did - -import ( - "fmt" - "math/big" - - "github.com/centrifuge/go-centrifuge/crypto/ed25519" -) - -// Key defines a single ERC725 identity key -type Key interface { - GetKey() [32]byte - GetPurpose() *big.Int - GetRevokedAt() *big.Int - GetType() *big.Int -} - -// KeyResponse contains the needed fields of the GetKey response -type KeyResponse struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -} - -// Key holds the identity related details -type key struct { - Key [32]byte - Purpose *big.Int - RevokedAt *big.Int - Type *big.Int -} - -//NewKey returns a new key struct -func NewKey(pk [32]byte, purpose *big.Int, keyType *big.Int) Key { - return &key{pk, purpose, big.NewInt(0), keyType} -} - -// GetKey returns the public key -func (idk *key) GetKey() [32]byte { - return idk.Key -} - -// GetPurposes returns the purposes intended for the key -func (idk *key) GetPurpose() *big.Int { - return idk.Purpose -} - -// GetRevokedAt returns the block at which the identity is revoked -func (idk *key) GetRevokedAt() *big.Int { - return idk.RevokedAt -} - -// GetType returns the type of the key -func (idk *key) GetType() *big.Int { - return idk.Type -} - -// String prints the peerID extracted from the key -func (idk *key) String() string { - peerID, _ := ed25519.PublicKeyToP2PKey(idk.Key) - return fmt.Sprintf("%s", peerID.Pretty()) -} diff --git a/identity/ethid/bootstrapper.go b/identity/ethid/bootstrapper.go deleted file mode 100644 index 61aa69bbd..000000000 --- a/identity/ethid/bootstrapper.go +++ /dev/null @@ -1,69 +0,0 @@ -package ethid - -import ( - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -// Bootstrapper implements bootstrap.Bootstrapper. -type Bootstrapper struct{} - -// Bootstrap initializes the IdentityFactoryContract as well as the idRegistrationConfirmationTask that depends on it. -// the idRegistrationConfirmationTask is added to be registered on the queue at queue.Bootstrapper -func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { - // we have to allow loading from file in case this is coming from create config cmd where we don't add configs to db - cfg, err := configstore.RetrieveConfig(false, context) - if err != nil { - return err - } - - if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { - return errors.New("ethereum client hasn't been initialized") - } - gethClient := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) - - idFactory, err := getIdentityFactoryContract(cfg.GetContractAddress(config.IdentityFactory), gethClient) - if err != nil { - return err - } - - registryContract, err := getIdentityRegistryContract(cfg.GetContractAddress(config.IdentityRegistry), gethClient) - if err != nil { - return err - } - - if _, ok := context[bootstrap.BootstrappedQueueServer]; !ok { - return errors.New("queue hasn't been initialized") - } - queueSrv := context[bootstrap.BootstrappedQueueServer].(*queue.Server) - - context[identity.BootstrappedIDService] = NewEthereumIdentityService(cfg, idFactory, registryContract, queueSrv, ethereum.GetClient, - func(address common.Address, backend bind.ContractBackend) (contract, error) { - return NewEthereumIdentityContract(address, backend) - }) - - idRegTask := newIDRegistrationConfirmationTask(cfg.GetEthereumContextWaitTimeout(), &idFactory.EthereumIdentityFactoryContractFilterer, ethereum.DefaultWaitForTransactionMiningContext) - keyRegTask := newKeyRegistrationConfirmationTask(ethereum.DefaultWaitForTransactionMiningContext, registryContract, cfg, queueSrv, ethereum.GetClient, - func(address common.Address, backend bind.ContractBackend) (contract, error) { - return NewEthereumIdentityContract(address, backend) - }) - queueSrv.RegisterTaskType(idRegTask.TaskTypeName(), idRegTask) - queueSrv.RegisterTaskType(keyRegTask.TaskTypeName(), keyRegTask) - return nil -} - -func getIdentityFactoryContract(factoryAddress common.Address, ethClient ethereum.Client) (identityFactoryContract *EthereumIdentityFactoryContract, err error) { - return NewEthereumIdentityFactoryContract(factoryAddress, ethClient.GetEthClient()) -} - -func getIdentityRegistryContract(registryAddress common.Address, ethClient ethereum.Client) (identityRegistryContract *EthereumIdentityRegistryContract, err error) { - return NewEthereumIdentityRegistryContract(registryAddress, ethClient.GetEthClient()) -} diff --git a/identity/ethid/bootstrapper_test.go b/identity/ethid/bootstrapper_test.go deleted file mode 100644 index a227d3cb5..000000000 --- a/identity/ethid/bootstrapper_test.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build unit - -package ethid - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBootstrapper_Bootstrap(t *testing.T) { - err := (&Bootstrapper{}).Bootstrap(map[string]interface{}{}) - assert.Error(t, err, "Should throw an error because of empty context") -} diff --git a/identity/ethid/ethereum_identity.go b/identity/ethid/ethereum_identity.go deleted file mode 100644 index a35295fb3..000000000 --- a/identity/ethid/ethereum_identity.go +++ /dev/null @@ -1,573 +0,0 @@ -package ethid - -import ( - "context" - "fmt" - "math/big" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/identity" - - "bytes" - - "time" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - logging "github.com/ipfs/go-log" -) - -var log = logging.Logger("identity") - -type factory interface { - CreateIdentity(opts *bind.TransactOpts, centID *big.Int) (*types.Transaction, error) -} - -type registry interface { - GetIdentityByCentrifugeId(opts *bind.CallOpts, bigInt *big.Int) (common.Address, error) -} - -type contract interface { - AddKey(opts *bind.TransactOpts, _key [32]byte, _kPurpose *big.Int) (*types.Transaction, error) - - GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) - - GetKey(opts *bind.CallOpts, _key [32]byte) (struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }, error) - - FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) -} - -// EthereumIdentityKey holds the identity related details -type EthereumIdentityKey struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -} - -// GetKey returns the public key -func (idk *EthereumIdentityKey) GetKey() [32]byte { - return idk.Key -} - -// GetPurposes returns the purposes intended for the key -func (idk *EthereumIdentityKey) GetPurposes() []*big.Int { - return idk.Purposes -} - -// GetRevokedAt returns the block at which the identity is revoked -func (idk *EthereumIdentityKey) GetRevokedAt() *big.Int { - return idk.RevokedAt -} - -// String prints the peerID extracted from the key -func (idk *EthereumIdentityKey) String() string { - peerID, _ := ed25519.PublicKeyToP2PKey(idk.Key) - return fmt.Sprintf("%s", peerID.Pretty()) -} - -type ethereumIdentity struct { - centID identity.CentID - contract contract - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) - registryContract registry - config identity.Config - gethClientFinder func() ethereum.Client - queue *queue.Server -} - -func newEthereumIdentity(id identity.CentID, registryContract registry, config identity.Config, - queue *queue.Server, - gethClientFinder func() ethereum.Client, - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) *ethereumIdentity { - return ðereumIdentity{centID: id, registryContract: registryContract, config: config, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} -} - -// CentrifugeID sets the CentID to the Identity -func (id *ethereumIdentity) SetCentrifugeID(centID identity.CentID) { - id.centID = centID -} - -// String returns CentrifugeID -func (id *ethereumIdentity) String() string { - return fmt.Sprintf("CentrifugeID [%s]", id.centID) -} - -// CentrifugeID returns the CentrifugeID -func (id *ethereumIdentity) CentID() identity.CentID { - return id.centID -} - -// LastKeyForPurpose returns the latest key for given purpose -func (id *ethereumIdentity) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { - idKeys, err := id.fetchKeysByPurpose(keyPurpose) - if err != nil { - return []byte{}, err - } - - if len(idKeys) == 0 { - return []byte{}, errors.New("no key found for type [%d] in ID [%s]", keyPurpose, id.centID) - } - - return idKeys[len(idKeys)-1].Key[:32], nil -} - -// FetchKey fetches the Key from the chain -func (id *ethereumIdentity) FetchKey(key []byte) (identity.Key, error) { - contract, err := id.getContract() - if err != nil { - return nil, err - } - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := id.gethClientFinder().GetGethCallOpts(false) - key32, _ := utils.SliceToByte32(key) - keyInstance, err := contract.GetKey(opts, key32) - if err != nil { - return nil, err - } - - return &EthereumIdentityKey{ - Key: keyInstance.Key, - Purposes: keyInstance.Purposes, - RevokedAt: keyInstance.RevokedAt, - }, nil - -} - -// CurrentP2PKey returns the latest P2P key -func (id *ethereumIdentity) CurrentP2PKey() (ret string, err error) { - key, err := id.LastKeyForPurpose(identity.KeyPurposeP2P) - if err != nil { - return ret, err - } - key32, _ := utils.SliceToByte32(key) - p2pID, err := ed25519.PublicKeyToP2PKey(key32) - if err != nil { - return ret, err - } - - return p2pID.Pretty(), nil -} - -func (id *ethereumIdentity) findContract() (exists bool, err error) { - if id.contract != nil { - return true, nil - } - - client := id.gethClientFinder() - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := client.GetGethCallOpts(false) - idAddress, err := id.registryContract.GetIdentityByCentrifugeId(opts, id.centID.BigInt()) - if err != nil { - return false, err - } - if utils.IsEmptyByteSlice(idAddress.Bytes()) { - return false, errors.New("Identity not found by address provided") - } - - idContract, err := id.contractProvider(idAddress, client.GetEthClient()) - if err == bind.ErrNoCode { - return false, err - } - if err != nil { - log.Errorf("Failed to instantiate the identity contract: %v", err) - return false, err - } - id.contract = idContract - return true, nil -} - -func (id *ethereumIdentity) getContract() (contract contract, err error) { - if id.contract == nil { - _, err := id.findContract() - if err != nil { - return nil, err - } - return id.contract, nil - } - return id.contract, nil -} - -// AddKeyToIdentity adds key to the purpose on chain -func (id *ethereumIdentity) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *identity.WatchIdentity, err error) { - if utils.IsEmptyByteSlice(key) || len(key) > 32 { - log.Errorf("Can't add key to identity: empty or invalid length(>32) key for [id: %s]: %x", id, key) - return confirmations, errors.New("Can't add key to identity: Invalid key") - } - - ethIdentityContract, err := id.getContract() - if err != nil { - log.Errorf("Failed to set up event listener for identity [id: %s]: %v", id, err) - return confirmations, err - } - - conn := id.gethClientFinder() - opts, err := ethereum.GetClient().GetTxOpts(id.config.GetEthereumDefaultAccountName()) - if err != nil { - return confirmations, err - } - - h, err := conn.GetEthClient().HeaderByNumber(ctx, nil) - if err != nil { - return confirmations, err - } - - var keyFixed [32]byte - copy(keyFixed[:], key) - confirmations, err = id.setUpKeyRegisteredEventListener(id.config, id, keyPurpose, keyFixed, h.Number.Uint64()) - if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to set up event listener for identity [id: %s]: %v", id, wError) - return confirmations, wError - } - - err = sendKeyRegistrationTransaction(ethIdentityContract, opts, id, keyPurpose, key) - if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to create transaction for identity [id: %s]: %v", id, wError) - return confirmations, wError - } - return confirmations, nil -} - -// fetchKeysByPurpose fetches keys from chain matching purpose -func (id *ethereumIdentity) fetchKeysByPurpose(keyPurpose int) ([]EthereumIdentityKey, error) { - contract, err := id.getContract() - if err != nil { - return nil, err - } - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := id.gethClientFinder().GetGethCallOpts(false) - bigInt := big.NewInt(int64(keyPurpose)) - keys, err := contract.GetKeysByPurpose(opts, bigInt) - if err != nil { - return nil, err - } - log.Infof("fetched keys: %d %x\n", keyPurpose, keys) - - var ids []EthereumIdentityKey - for _, key := range keys { - ids = append(ids, EthereumIdentityKey{Key: key}) - } - - return ids, nil -} - -// sendRegistrationTransaction sends the actual transaction to add a Key on Ethereum registry contract -func sendKeyRegistrationTransaction(identityContract contract, opts *bind.TransactOpts, identity *ethereumIdentity, keyPurpose int, key []byte) error { - - //preparation of data in specific types for the call to Ethereum - bigInt := big.NewInt(int64(keyPurpose)) - bKey, err := utils.SliceToByte32(key) - if err != nil { - return err - } - - tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityContract.AddKey, opts, bKey, bigInt) - if err != nil { - log.Infof("Failed to send key [%v:%x] to add to CentrifugeID [%x]: %v", keyPurpose, bKey, identity.CentID, err) - return err - } - - log.Infof("Sent off key [%v:%x] to add to CentrifugeID [%s]. Ethereum transaction hash [%x]", keyPurpose, bKey, identity, tx.Hash()) - return nil -} - -// sendIdentityCreationTransaction sends the actual transaction to create identity on Ethereum registry contract -func sendIdentityCreationTransaction(identityFactory factory, opts *bind.TransactOpts, identityToBeCreated identity.Identity) error { - //preparation of data in specific types for the call to Ethereum - tx, err := ethereum.GetClient().SubmitTransactionWithRetries(identityFactory.CreateIdentity, opts, identityToBeCreated.CentID().BigInt()) - if err != nil { - log.Infof("Failed to send identity for creation [CentrifugeID: %s] : %v", identityToBeCreated, err) - return err - } - - log.Infof("Sent off identity creation [%s]. Ethereum transaction hash [%x] and Nonce [%v] and Check [%v]", identityToBeCreated, tx.Hash(), tx.Nonce(), tx.CheckNonce()) - log.Infof("Transfer pending: 0x%x\n", tx.Hash()) - return err -} - -// setUpKeyRegisteredEventListener listens for Identity creation -func (id *ethereumIdentity) setUpKeyRegisteredEventListener(config identity.Config, i identity.Identity, keyPurpose int, key [32]byte, bh uint64) (confirmations chan *identity.WatchIdentity, err error) { - confirmations = make(chan *identity.WatchIdentity) - centID := i.CentID() - if err != nil { - return nil, err - } - asyncRes, err := id.queue.EnqueueJob(keyRegistrationConfirmationTaskName, - map[string]interface{}{ - centIDParam: centID, - keyParam: key, - keyPurposeParam: keyPurpose, - queue.BlockHeightParam: bh, - }) - if err != nil { - return nil, err - } - go waitAndRouteKeyRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, i) - return confirmations, nil -} - -// setUpRegistrationEventListener sets up the listened for the "IdentityCreated" event to notify the upstream code about successful mining/creation -// of the identity. -func (ids *ethereumIdentityService) setUpRegistrationEventListener(config identity.Config, identityToBeCreated identity.Identity, blockHeight uint64) (confirmations chan *identity.WatchIdentity, err error) { - confirmations = make(chan *identity.WatchIdentity) - centID := identityToBeCreated.CentID() - if err != nil { - return nil, err - } - - asyncRes, err := ids.queue.EnqueueJob(idRegistrationConfirmationTaskName, map[string]interface{}{centIDParam: centID, queue.BlockHeightParam: blockHeight}) - if err != nil { - return nil, err - } - go waitAndRouteIdentityRegistrationEvent(config.GetEthereumContextWaitTimeout(), asyncRes, confirmations, identityToBeCreated) - return confirmations, nil -} - -// waitAndRouteKeyRegistrationEvent notifies the confirmations channel whenever the key has been added to the identity and has been noted as Ethereum event -func waitAndRouteKeyRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *identity.WatchIdentity, pushThisIdentity identity.Identity) { - _, err := asyncRes.Get(timeout) - confirmations <- &identity.WatchIdentity{Identity: pushThisIdentity, Error: err} -} - -// waitAndRouteIdentityRegistrationEvent notifies the confirmations channel whenever the identity creation is being noted as Ethereum event -func waitAndRouteIdentityRegistrationEvent(timeout time.Duration, asyncRes queue.TaskResult, confirmations chan<- *identity.WatchIdentity, pushThisIdentity identity.Identity) { - _, err := asyncRes.Get(timeout) - confirmations <- &identity.WatchIdentity{pushThisIdentity, err} -} - -// ethereumIdentityService implements `Service` -type ethereumIdentityService struct { - config identity.Config - factoryContract factory - registryContract registry - gethClientFinder func() ethereum.Client - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) - queue *queue.Server -} - -// NewEthereumIdentityService creates a new NewEthereumIdentityService given the config and the smart contracts -func NewEthereumIdentityService(config identity.Config, factoryContract factory, registryContract registry, - queue *queue.Server, - gethClientFinder func() ethereum.Client, - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error)) identity.Service { - return ðereumIdentityService{config: config, factoryContract: factoryContract, registryContract: registryContract, gethClientFinder: gethClientFinder, contractProvider: contractProvider, queue: queue} -} - -// CheckIdentityExists checks if the identity represented by id actually exists on ethereum -func (ids *ethereumIdentityService) CheckIdentityExists(centrifugeID identity.CentID) (exists bool, err error) { - client := ids.gethClientFinder() - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := client.GetGethCallOpts(false) - idAddress, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centrifugeID.BigInt()) - if err != nil { - return false, err - } - if utils.IsEmptyByteSlice(idAddress.Bytes()) { - return false, errors.New("Identity not found by address provided") - } - - _, err = NewEthereumIdentityContract(idAddress, client.GetEthClient()) - if err == bind.ErrNoCode { - return false, err - } - if err != nil { - log.Errorf("Failed to instantiate the identity contract: %v", err) - return false, err - } - return true, nil -} - -// CreateIdentity creates an identity representing the id on ethereum -func (ids *ethereumIdentityService) CreateIdentity(ctx context.Context, centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { - log.Infof("Creating Identity [%x]", centrifugeID) - tc, err := contextutil.Account(ctx) - if err != nil { - return nil, confirmations, err - } - - id = newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider) - conn := ids.gethClientFinder() - opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) - if err != nil { - return nil, confirmations, err - } - - h, err := conn.GetEthClient().HeaderByNumber(context.Background(), nil) - if err != nil { - return nil, confirmations, err - } - - confirmations, err = ids.setUpRegistrationEventListener(ids.config, id, h.Number.Uint64()) - if err != nil { - wError := errors.New("%v", err) - log.Infof("Failed to set up event listener for identity [mockID: %s]: %v", id, wError) - return nil, confirmations, wError - } - - err = sendIdentityCreationTransaction(ids.factoryContract, opts, id) - if err != nil { - wError := errors.New("%v", err) - log.Infof("Failed to create transaction for identity [mockID: %s]: %v", id, wError) - return nil, confirmations, wError - } - return id, confirmations, nil -} - -// GetIdentityAddress gets the address of the ethereum identity contract for the given CentID -func (ids *ethereumIdentityService) GetIdentityAddress(centID identity.CentID) (common.Address, error) { - // Ignoring cancelFunc as code will block until response or timeout is triggered - opts, _ := ethereum.GetClient().GetGethCallOpts(false) - address, err := ids.registryContract.GetIdentityByCentrifugeId(opts, centID.BigInt()) - if err != nil { - return common.Address{}, err - } - - if utils.IsEmptyAddress(address) { - return common.Address{}, errors.New("No address found for centID") - } - return address, nil -} - -// LookupIdentityForID looks up if the identity for given CentID exists on ethereum -func (ids *ethereumIdentityService) LookupIdentityForID(centrifugeID identity.CentID) (identity.Identity, error) { - exists, err := ids.CheckIdentityExists(centrifugeID) - if !exists { - return nil, errors.New("identity [%s] does not exist with err [%v]", centrifugeID, err) - } - - if err != nil { - return nil, err - } - return newEthereumIdentity(centrifugeID, ids.registryContract, ids.config, ids.queue, ids.gethClientFinder, ids.contractProvider), nil -} - -// GetClientP2PURL returns the p2p url associated with the centID -func (ids *ethereumIdentityService) GetClientP2PURL(centID identity.CentID) (url string, err error) { - target, err := ids.LookupIdentityForID(centID) - if err != nil { - return url, errors.New("error fetching receiver identity: %v", err) - } - - p2pKey, err := target.CurrentP2PKey() - if err != nil { - return url, errors.New("error fetching p2p key: %v", err) - } - - return fmt.Sprintf("/ipfs/%s", p2pKey), nil -} - -// GetClientsP2PURLs returns p2p urls associated with each centIDs -// will error out at first failure -func (ids *ethereumIdentityService) GetClientsP2PURLs(centIDs []identity.CentID) ([]string, error) { - var p2pURLs []string - for _, id := range centIDs { - url, err := ids.GetClientP2PURL(id) - if err != nil { - return nil, err - } - - p2pURLs = append(p2pURLs, url) - } - - return p2pURLs, nil -} - -// GetIdentityKey returns the key for provided identity -func (ids *ethereumIdentityService) GetIdentityKey(identity identity.CentID, pubKey []byte) (keyInfo identity.Key, err error) { - id, err := ids.LookupIdentityForID(identity) - if err != nil { - return keyInfo, err - } - - key, err := id.FetchKey(pubKey) - if err != nil { - return keyInfo, err - } - - if utils.IsEmptyByte32(key.GetKey()) { - return keyInfo, errors.New("key not found for identity: %x", identity) - } - - return key, nil -} - -// ValidateKey checks if a given key is valid for the given centrifugeID. -func (ids *ethereumIdentityService) ValidateKey(centID identity.CentID, key []byte, purpose int) error { - idKey, err := ids.GetIdentityKey(centID, key) - if err != nil { - return err - } - - if !bytes.Equal(key, utils.Byte32ToSlice(idKey.GetKey())) { - return errors.New("[Key: %x] Key doesn't match", idKey.GetKey()) - } - - if !utils.ContainsBigIntInSlice(big.NewInt(int64(purpose)), idKey.GetPurposes()) { - return errors.New("[Key: %x] Key doesn't have purpose [%d]", idKey.GetKey(), purpose) - } - - if idKey.GetRevokedAt().Cmp(big.NewInt(0)) != 0 { - return errors.New("[Key: %x] Key is currently revoked since block [%d]", idKey.GetKey(), idKey.GetRevokedAt()) - } - - return nil -} - -// AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file -func (ids *ethereumIdentityService) AddKeyFromConfig(config identity.Config, purpose int) error { - identityConfig, err := identity.GetIdentityConfig(config) - if err != nil { - return err - } - - id, err := ids.LookupIdentityForID(identityConfig.ID) - if err != nil { - return err - } - - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(config.GetEthereumContextWaitTimeout()) - defer cancel() - confirmations, err := id.AddKeyToIdentity(ctx, purpose, identityConfig.Keys[purpose].PublicKey) - if err != nil { - return err - } - watchAddedToIdentity := <-confirmations - - lastKey, errLocal := watchAddedToIdentity.Identity.LastKeyForPurpose(purpose) - if errLocal != nil { - return err - } - - log.Infof("Key [%v] with type [%d] Added to Identity [%s]", lastKey, purpose, watchAddedToIdentity.Identity) - - return nil -} - -// ValidateSignature validates a signature on a message based on identity data -func (ids *ethereumIdentityService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { - centID, err := identity.ToCentID(signature.EntityId) - if err != nil { - return err - } - - err = ids.ValidateKey(centID, signature.PublicKey, identity.KeyPurposeSigning) - if err != nil { - return err - } - - return crypto.VerifySignature(signature.PublicKey, message, signature.Signature) -} diff --git a/identity/ethid/ethereum_identity_contract.go b/identity/ethid/ethereum_identity_contract.go deleted file mode 100644 index 1481fa50f..000000000 --- a/identity/ethid/ethereum_identity_contract.go +++ /dev/null @@ -1,991 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethid - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// EthereumIdentityContractABI is the input ABI used to generate the binding from. -const EthereumIdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"centrifugeId\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purposes\",\"type\":\"uint256[]\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_centrifugeId\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"}],\"name\":\"OwnershipRenounced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"name\":\"_toSign\",\"type\":\"bytes32\"},{\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"isSignatureValid\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" - -// EthereumIdentityContract is an auto generated Go binding around an Ethereum contract. -type EthereumIdentityContract struct { - EthereumIdentityContractCaller // Read-only binding to the contract - EthereumIdentityContractTransactor // Write-only binding to the contract - EthereumIdentityContractFilterer // Log filterer for contract events -} - -// EthereumIdentityContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type EthereumIdentityContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type EthereumIdentityContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type EthereumIdentityContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type EthereumIdentityContractSession struct { - Contract *EthereumIdentityContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type EthereumIdentityContractCallerSession struct { - Contract *EthereumIdentityContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// EthereumIdentityContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type EthereumIdentityContractTransactorSession struct { - Contract *EthereumIdentityContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type EthereumIdentityContractRaw struct { - Contract *EthereumIdentityContract // Generic contract binding to access the raw methods on -} - -// EthereumIdentityContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type EthereumIdentityContractCallerRaw struct { - Contract *EthereumIdentityContractCaller // Generic read-only contract binding to access the raw methods on -} - -// EthereumIdentityContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type EthereumIdentityContractTransactorRaw struct { - Contract *EthereumIdentityContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewEthereumIdentityContract creates a new instance of EthereumIdentityContract, bound to a specific deployed contract. -func NewEthereumIdentityContract(address common.Address, backend bind.ContractBackend) (*EthereumIdentityContract, error) { - contract, err := bindEthereumIdentityContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &EthereumIdentityContract{EthereumIdentityContractCaller: EthereumIdentityContractCaller{contract: contract}, EthereumIdentityContractTransactor: EthereumIdentityContractTransactor{contract: contract}, EthereumIdentityContractFilterer: EthereumIdentityContractFilterer{contract: contract}}, nil -} - -// NewEthereumIdentityContractCaller creates a new read-only instance of EthereumIdentityContract, bound to a specific deployed contract. -func NewEthereumIdentityContractCaller(address common.Address, caller bind.ContractCaller) (*EthereumIdentityContractCaller, error) { - contract, err := bindEthereumIdentityContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityContractCaller{contract: contract}, nil -} - -// NewEthereumIdentityContractTransactor creates a new write-only instance of EthereumIdentityContract, bound to a specific deployed contract. -func NewEthereumIdentityContractTransactor(address common.Address, transactor bind.ContractTransactor) (*EthereumIdentityContractTransactor, error) { - contract, err := bindEthereumIdentityContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityContractTransactor{contract: contract}, nil -} - -// NewEthereumIdentityContractFilterer creates a new log filterer instance of EthereumIdentityContract, bound to a specific deployed contract. -func NewEthereumIdentityContractFilterer(address common.Address, filterer bind.ContractFilterer) (*EthereumIdentityContractFilterer, error) { - contract, err := bindEthereumIdentityContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &EthereumIdentityContractFilterer{contract: contract}, nil -} - -// bindEthereumIdentityContract binds a generic wrapper to an already deployed contract. -func bindEthereumIdentityContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(EthereumIdentityContractABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityContract *EthereumIdentityContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityContract.Contract.EthereumIdentityContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityContract *EthereumIdentityContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.EthereumIdentityContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityContract *EthereumIdentityContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.EthereumIdentityContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityContract *EthereumIdentityContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityContract *EthereumIdentityContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityContract *EthereumIdentityContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.contract.Transact(opts, method, params...) -} - -// CentrifugeID is a free data retrieval call binding the contract method 0x41a43c38. -// -// Solidity: function centrifugeId() constant returns(uint48) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) CentrifugeId(opts *bind.CallOpts) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _EthereumIdentityContract.contract.Call(opts, out, "centrifugeId") - return *ret0, err -} - -// CentrifugeID is a free data retrieval call binding the contract method 0x41a43c38. -// -// Solidity: function centrifugeId() constant returns(uint48) -func (_EthereumIdentityContract *EthereumIdentityContractSession) CentrifugeId() (*big.Int, error) { - return _EthereumIdentityContract.Contract.CentrifugeId(&_EthereumIdentityContract.CallOpts) -} - -// CentrifugeID is a free data retrieval call binding the contract method 0x41a43c38. -// -// Solidity: function centrifugeId() constant returns(uint48) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) CentrifugeId() (*big.Int, error) { - return _EthereumIdentityContract.Contract.CentrifugeId(&_EthereumIdentityContract.CallOpts) -} - -// GetKey is a free data retrieval call binding the contract method 0x12aaac70. -// -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) GetKey(opts *bind.CallOpts, _key [32]byte) (struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -}, error) { - ret := new(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }) - out := ret - err := _EthereumIdentityContract.contract.Call(opts, out, "getKey", _key) - return *ret, err -} - -// GetKey is a free data retrieval call binding the contract method 0x12aaac70. -// -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_EthereumIdentityContract *EthereumIdentityContractSession) GetKey(_key [32]byte) (struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -}, error) { - return _EthereumIdentityContract.Contract.GetKey(&_EthereumIdentityContract.CallOpts, _key) -} - -// GetKey is a free data retrieval call binding the contract method 0x12aaac70. -// -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) GetKey(_key [32]byte) (struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -}, error) { - return _EthereumIdentityContract.Contract.GetKey(&_EthereumIdentityContract.CallOpts, _key) -} - -// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. -// -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) { - var ( - ret0 = new([][32]byte) - ) - out := ret0 - err := _EthereumIdentityContract.contract.Call(opts, out, "getKeysByPurpose", _purpose) - return *ret0, err -} - -// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. -// -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_EthereumIdentityContract *EthereumIdentityContractSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { - return _EthereumIdentityContract.Contract.GetKeysByPurpose(&_EthereumIdentityContract.CallOpts, _purpose) -} - -// GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. -// -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { - return _EthereumIdentityContract.Contract.GetKeysByPurpose(&_EthereumIdentityContract.CallOpts, _purpose) -} - -// IsSignatureValid is a free data retrieval call binding the contract method 0x0892beb7. -// -// Solidity: function isSignatureValid(_toSign bytes32, _signature bytes) constant returns(valid bool) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) IsSignatureValid(opts *bind.CallOpts, _toSign [32]byte, _signature []byte) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _EthereumIdentityContract.contract.Call(opts, out, "isSignatureValid", _toSign, _signature) - return *ret0, err -} - -// IsSignatureValid is a free data retrieval call binding the contract method 0x0892beb7. -// -// Solidity: function isSignatureValid(_toSign bytes32, _signature bytes) constant returns(valid bool) -func (_EthereumIdentityContract *EthereumIdentityContractSession) IsSignatureValid(_toSign [32]byte, _signature []byte) (bool, error) { - return _EthereumIdentityContract.Contract.IsSignatureValid(&_EthereumIdentityContract.CallOpts, _toSign, _signature) -} - -// IsSignatureValid is a free data retrieval call binding the contract method 0x0892beb7. -// -// Solidity: function isSignatureValid(_toSign bytes32, _signature bytes) constant returns(valid bool) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) IsSignatureValid(_toSign [32]byte, _signature []byte) (bool, error) { - return _EthereumIdentityContract.Contract.IsSignatureValid(&_EthereumIdentityContract.CallOpts, _toSign, _signature) -} - -// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. -// -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) KeyHasPurpose(opts *bind.CallOpts, _key [32]byte, _purpose *big.Int) (bool, error) { - var ( - ret0 = new(bool) - ) - out := ret0 - err := _EthereumIdentityContract.contract.Call(opts, out, "keyHasPurpose", _key, _purpose) - return *ret0, err -} - -// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. -// -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_EthereumIdentityContract *EthereumIdentityContractSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { - return _EthereumIdentityContract.Contract.KeyHasPurpose(&_EthereumIdentityContract.CallOpts, _key, _purpose) -} - -// KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. -// -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { - return _EthereumIdentityContract.Contract.KeyHasPurpose(&_EthereumIdentityContract.CallOpts, _key, _purpose) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() constant returns(address) -func (_EthereumIdentityContract *EthereumIdentityContractCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _EthereumIdentityContract.contract.Call(opts, out, "owner") - return *ret0, err -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() constant returns(address) -func (_EthereumIdentityContract *EthereumIdentityContractSession) Owner() (common.Address, error) { - return _EthereumIdentityContract.Contract.Owner(&_EthereumIdentityContract.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() constant returns(address) -func (_EthereumIdentityContract *EthereumIdentityContractCallerSession) Owner() (common.Address, error) { - return _EthereumIdentityContract.Contract.Owner(&_EthereumIdentityContract.CallOpts) -} - -// AddKey is a paid mutator transaction binding the contract method 0x4103ef4c. -// -// Solidity: function addKey(_key bytes32, _purpose uint256) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactor) AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.contract.Transact(opts, "addKey", _key, _purpose) -} - -// AddKey is a paid mutator transaction binding the contract method 0x4103ef4c. -// -// Solidity: function addKey(_key bytes32, _purpose uint256) returns() -func (_EthereumIdentityContract *EthereumIdentityContractSession) AddKey(_key [32]byte, _purpose *big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.AddKey(&_EthereumIdentityContract.TransactOpts, _key, _purpose) -} - -// AddKey is a paid mutator transaction binding the contract method 0x4103ef4c. -// -// Solidity: function addKey(_key bytes32, _purpose uint256) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactorSession) AddKey(_key [32]byte, _purpose *big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.AddKey(&_EthereumIdentityContract.TransactOpts, _key, _purpose) -} - -// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0xcb757f7f. -// -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[]) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactor) AddMultiPurposeKey(opts *bind.TransactOpts, _key [32]byte, _purposes []*big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.contract.Transact(opts, "addMultiPurposeKey", _key, _purposes) -} - -// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0xcb757f7f. -// -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[]) returns() -func (_EthereumIdentityContract *EthereumIdentityContractSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.AddMultiPurposeKey(&_EthereumIdentityContract.TransactOpts, _key, _purposes) -} - -// AddMultiPurposeKey is a paid mutator transaction binding the contract method 0xcb757f7f. -// -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[]) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactorSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.AddMultiPurposeKey(&_EthereumIdentityContract.TransactOpts, _key, _purposes) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityContract.contract.Transact(opts, "renounceOwnership") -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_EthereumIdentityContract *EthereumIdentityContractSession) RenounceOwnership() (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.RenounceOwnership(&_EthereumIdentityContract.TransactOpts) -} - -// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. -// -// Solidity: function renounceOwnership() returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactorSession) RenounceOwnership() (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.RenounceOwnership(&_EthereumIdentityContract.TransactOpts) -} - -// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. -// -// Solidity: function revokeKey(_key bytes32) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactor) RevokeKey(opts *bind.TransactOpts, _key [32]byte) (*types.Transaction, error) { - return _EthereumIdentityContract.contract.Transact(opts, "revokeKey", _key) -} - -// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. -// -// Solidity: function revokeKey(_key bytes32) returns() -func (_EthereumIdentityContract *EthereumIdentityContractSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.RevokeKey(&_EthereumIdentityContract.TransactOpts, _key) -} - -// RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. -// -// Solidity: function revokeKey(_key bytes32) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactorSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.RevokeKey(&_EthereumIdentityContract.TransactOpts, _key) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(_newOwner address) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactor) TransferOwnership(opts *bind.TransactOpts, _newOwner common.Address) (*types.Transaction, error) { - return _EthereumIdentityContract.contract.Transact(opts, "transferOwnership", _newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(_newOwner address) returns() -func (_EthereumIdentityContract *EthereumIdentityContractSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.TransferOwnership(&_EthereumIdentityContract.TransactOpts, _newOwner) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(_newOwner address) returns() -func (_EthereumIdentityContract *EthereumIdentityContractTransactorSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { - return _EthereumIdentityContract.Contract.TransferOwnership(&_EthereumIdentityContract.TransactOpts, _newOwner) -} - -// EthereumIdentityContractKeyAddedIterator is returned from FilterKeyAdded and is used to iterate over the raw logs and unpacked data for KeyAdded events raised by the EthereumIdentityContract contract. -type EthereumIdentityContractKeyAddedIterator struct { - Event *EthereumIdentityContractKeyAdded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityContractKeyAddedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractKeyAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractKeyAdded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityContractKeyAddedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityContractKeyAddedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityContractKeyAdded represents a KeyAdded event raised by the EthereumIdentityContract contract. -type EthereumIdentityContractKeyAdded struct { - Key [32]byte - Purpose *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterKeyAdded is a free log retrieval operation binding the contract event 0x90cf26894583787fe4a16185f0128c58652d10939f4b0185a951efc8452bcaa8. -// -// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) { - - var keyRule []interface{} - for _, keyItem := range key { - keyRule = append(keyRule, keyItem) - } - var purposeRule []interface{} - for _, purposeItem := range purpose { - purposeRule = append(purposeRule, purposeItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.FilterLogs(opts, "KeyAdded", keyRule, purposeRule) - if err != nil { - return nil, err - } - return &EthereumIdentityContractKeyAddedIterator{contract: _EthereumIdentityContract.contract, event: "KeyAdded", logs: logs, sub: sub}, nil -} - -// WatchKeyAdded is a free log subscription operation binding the contract event 0x90cf26894583787fe4a16185f0128c58652d10939f4b0185a951efc8452bcaa8. -// -// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) WatchKeyAdded(opts *bind.WatchOpts, sink chan<- *EthereumIdentityContractKeyAdded, key [][32]byte, purpose []*big.Int) (event.Subscription, error) { - - var keyRule []interface{} - for _, keyItem := range key { - keyRule = append(keyRule, keyItem) - } - var purposeRule []interface{} - for _, purposeItem := range purpose { - purposeRule = append(purposeRule, purposeItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.WatchLogs(opts, "KeyAdded", keyRule, purposeRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityContractKeyAdded) - if err := _EthereumIdentityContract.contract.UnpackLog(event, "KeyAdded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// EthereumIdentityContractKeyRevokedIterator is returned from FilterKeyRevoked and is used to iterate over the raw logs and unpacked data for KeyRevoked events raised by the EthereumIdentityContract contract. -type EthereumIdentityContractKeyRevokedIterator struct { - Event *EthereumIdentityContractKeyRevoked // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityContractKeyRevokedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractKeyRevoked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractKeyRevoked) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityContractKeyRevokedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityContractKeyRevokedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityContractKeyRevoked represents a KeyRevoked event raised by the EthereumIdentityContract contract. -type EthereumIdentityContractKeyRevoked struct { - Key [32]byte - RevokedAt *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterKeyRevoked is a free log retrieval operation binding the contract event 0x3aa2212f5d3ddf6cf452b1611d7ea62ac572afe7d5e4310c09185edd915c686e. -// -// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) FilterKeyRevoked(opts *bind.FilterOpts, key [][32]byte, revokedAt []*big.Int) (*EthereumIdentityContractKeyRevokedIterator, error) { - - var keyRule []interface{} - for _, keyItem := range key { - keyRule = append(keyRule, keyItem) - } - var revokedAtRule []interface{} - for _, revokedAtItem := range revokedAt { - revokedAtRule = append(revokedAtRule, revokedAtItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.FilterLogs(opts, "KeyRevoked", keyRule, revokedAtRule) - if err != nil { - return nil, err - } - return &EthereumIdentityContractKeyRevokedIterator{contract: _EthereumIdentityContract.contract, event: "KeyRevoked", logs: logs, sub: sub}, nil -} - -// WatchKeyRevoked is a free log subscription operation binding the contract event 0x3aa2212f5d3ddf6cf452b1611d7ea62ac572afe7d5e4310c09185edd915c686e. -// -// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) WatchKeyRevoked(opts *bind.WatchOpts, sink chan<- *EthereumIdentityContractKeyRevoked, key [][32]byte, revokedAt []*big.Int) (event.Subscription, error) { - - var keyRule []interface{} - for _, keyItem := range key { - keyRule = append(keyRule, keyItem) - } - var revokedAtRule []interface{} - for _, revokedAtItem := range revokedAt { - revokedAtRule = append(revokedAtRule, revokedAtItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.WatchLogs(opts, "KeyRevoked", keyRule, revokedAtRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityContractKeyRevoked) - if err := _EthereumIdentityContract.contract.UnpackLog(event, "KeyRevoked", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// EthereumIdentityContractOwnershipRenouncedIterator is returned from FilterOwnershipRenounced and is used to iterate over the raw logs and unpacked data for OwnershipRenounced events raised by the EthereumIdentityContract contract. -type EthereumIdentityContractOwnershipRenouncedIterator struct { - Event *EthereumIdentityContractOwnershipRenounced // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityContractOwnershipRenouncedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractOwnershipRenounced) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractOwnershipRenounced) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityContractOwnershipRenouncedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityContractOwnershipRenouncedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityContractOwnershipRenounced represents a OwnershipRenounced event raised by the EthereumIdentityContract contract. -type EthereumIdentityContractOwnershipRenounced struct { - PreviousOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipRenounced is a free log retrieval operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. -// -// Solidity: e OwnershipRenounced(previousOwner indexed address) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) FilterOwnershipRenounced(opts *bind.FilterOpts, previousOwner []common.Address) (*EthereumIdentityContractOwnershipRenouncedIterator, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.FilterLogs(opts, "OwnershipRenounced", previousOwnerRule) - if err != nil { - return nil, err - } - return &EthereumIdentityContractOwnershipRenouncedIterator{contract: _EthereumIdentityContract.contract, event: "OwnershipRenounced", logs: logs, sub: sub}, nil -} - -// WatchOwnershipRenounced is a free log subscription operation binding the contract event 0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820. -// -// Solidity: e OwnershipRenounced(previousOwner indexed address) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) WatchOwnershipRenounced(opts *bind.WatchOpts, sink chan<- *EthereumIdentityContractOwnershipRenounced, previousOwner []common.Address) (event.Subscription, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.WatchLogs(opts, "OwnershipRenounced", previousOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityContractOwnershipRenounced) - if err := _EthereumIdentityContract.contract.UnpackLog(event, "OwnershipRenounced", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// EthereumIdentityContractOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the EthereumIdentityContract contract. -type EthereumIdentityContractOwnershipTransferredIterator struct { - Event *EthereumIdentityContractOwnershipTransferred // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityContractOwnershipTransferredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityContractOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityContractOwnershipTransferredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityContractOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityContractOwnershipTransferred represents a OwnershipTransferred event raised by the EthereumIdentityContract contract. -type EthereumIdentityContractOwnershipTransferred struct { - PreviousOwner common.Address - NewOwner common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*EthereumIdentityContractOwnershipTransferredIterator, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return &EthereumIdentityContractOwnershipTransferredIterator{contract: _EthereumIdentityContract.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: e OwnershipTransferred(previousOwner indexed address, newOwner indexed address) -func (_EthereumIdentityContract *EthereumIdentityContractFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EthereumIdentityContractOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { - - var previousOwnerRule []interface{} - for _, previousOwnerItem := range previousOwner { - previousOwnerRule = append(previousOwnerRule, previousOwnerItem) - } - var newOwnerRule []interface{} - for _, newOwnerItem := range newOwner { - newOwnerRule = append(newOwnerRule, newOwnerItem) - } - - logs, sub, err := _EthereumIdentityContract.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityContractOwnershipTransferred) - if err := _EthereumIdentityContract.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/identity/ethid/ethereum_identity_factory_contract.go b/identity/ethid/ethereum_identity_factory_contract.go deleted file mode 100644 index aaa0025e0..000000000 --- a/identity/ethid/ethereum_identity_factory_contract.go +++ /dev/null @@ -1,315 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethid - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// EthereumIdentityFactoryContractABI is the input ABI used to generate the binding from. -const EthereumIdentityFactoryContractABI = "[{\"inputs\":[{\"name\":\"_registry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"centrifugeId\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_centrifugeId\",\"type\":\"uint48\"}],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" - -// EthereumIdentityFactoryContract is an auto generated Go binding around an Ethereum contract. -type EthereumIdentityFactoryContract struct { - EthereumIdentityFactoryContractCaller // Read-only binding to the contract - EthereumIdentityFactoryContractTransactor // Write-only binding to the contract - EthereumIdentityFactoryContractFilterer // Log filterer for contract events -} - -// EthereumIdentityFactoryContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type EthereumIdentityFactoryContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityFactoryContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type EthereumIdentityFactoryContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityFactoryContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type EthereumIdentityFactoryContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityFactoryContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type EthereumIdentityFactoryContractSession struct { - Contract *EthereumIdentityFactoryContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityFactoryContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type EthereumIdentityFactoryContractCallerSession struct { - Contract *EthereumIdentityFactoryContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// EthereumIdentityFactoryContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type EthereumIdentityFactoryContractTransactorSession struct { - Contract *EthereumIdentityFactoryContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityFactoryContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type EthereumIdentityFactoryContractRaw struct { - Contract *EthereumIdentityFactoryContract // Generic contract binding to access the raw methods on -} - -// EthereumIdentityFactoryContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type EthereumIdentityFactoryContractCallerRaw struct { - Contract *EthereumIdentityFactoryContractCaller // Generic read-only contract binding to access the raw methods on -} - -// EthereumIdentityFactoryContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type EthereumIdentityFactoryContractTransactorRaw struct { - Contract *EthereumIdentityFactoryContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewEthereumIdentityFactoryContract creates a new instance of EthereumIdentityFactoryContract, bound to a specific deployed contract. -func NewEthereumIdentityFactoryContract(address common.Address, backend bind.ContractBackend) (*EthereumIdentityFactoryContract, error) { - contract, err := bindEthereumIdentityFactoryContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &EthereumIdentityFactoryContract{EthereumIdentityFactoryContractCaller: EthereumIdentityFactoryContractCaller{contract: contract}, EthereumIdentityFactoryContractTransactor: EthereumIdentityFactoryContractTransactor{contract: contract}, EthereumIdentityFactoryContractFilterer: EthereumIdentityFactoryContractFilterer{contract: contract}}, nil -} - -// NewEthereumIdentityFactoryContractCaller creates a new read-only instance of EthereumIdentityFactoryContract, bound to a specific deployed contract. -func NewEthereumIdentityFactoryContractCaller(address common.Address, caller bind.ContractCaller) (*EthereumIdentityFactoryContractCaller, error) { - contract, err := bindEthereumIdentityFactoryContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityFactoryContractCaller{contract: contract}, nil -} - -// NewEthereumIdentityFactoryContractTransactor creates a new write-only instance of EthereumIdentityFactoryContract, bound to a specific deployed contract. -func NewEthereumIdentityFactoryContractTransactor(address common.Address, transactor bind.ContractTransactor) (*EthereumIdentityFactoryContractTransactor, error) { - contract, err := bindEthereumIdentityFactoryContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityFactoryContractTransactor{contract: contract}, nil -} - -// NewEthereumIdentityFactoryContractFilterer creates a new log filterer instance of EthereumIdentityFactoryContract, bound to a specific deployed contract. -func NewEthereumIdentityFactoryContractFilterer(address common.Address, filterer bind.ContractFilterer) (*EthereumIdentityFactoryContractFilterer, error) { - contract, err := bindEthereumIdentityFactoryContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &EthereumIdentityFactoryContractFilterer{contract: contract}, nil -} - -// bindEthereumIdentityFactoryContract binds a generic wrapper to an already deployed contract. -func bindEthereumIdentityFactoryContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(EthereumIdentityFactoryContractABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityFactoryContract.Contract.EthereumIdentityFactoryContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.EthereumIdentityFactoryContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.EthereumIdentityFactoryContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityFactoryContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.contract.Transact(opts, method, params...) -} - -// CreateIdentity is a paid mutator transaction binding the contract method 0x340e963a. -// -// Solidity: function createIdentity(_centrifugeId uint48) returns() -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractTransactor) CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.contract.Transact(opts, "createIdentity", _centrifugeId) -} - -// CreateIdentity is a paid mutator transaction binding the contract method 0x340e963a. -// -// Solidity: function createIdentity(_centrifugeId uint48) returns() -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractSession) CreateIdentity(_centrifugeId *big.Int) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.CreateIdentity(&_EthereumIdentityFactoryContract.TransactOpts, _centrifugeId) -} - -// CreateIdentity is a paid mutator transaction binding the contract method 0x340e963a. -// -// Solidity: function createIdentity(_centrifugeId uint48) returns() -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractTransactorSession) CreateIdentity(_centrifugeId *big.Int) (*types.Transaction, error) { - return _EthereumIdentityFactoryContract.Contract.CreateIdentity(&_EthereumIdentityFactoryContract.TransactOpts, _centrifugeId) -} - -// EthereumIdentityFactoryContractIdentityCreatedIterator is returned from FilterIdentityCreated and is used to iterate over the raw logs and unpacked data for IdentityCreated events raised by the EthereumIdentityFactoryContract contract. -type EthereumIdentityFactoryContractIdentityCreatedIterator struct { - Event *EthereumIdentityFactoryContractIdentityCreated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityFactoryContractIdentityCreatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityFactoryContractIdentityCreated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityFactoryContractIdentityCreated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityFactoryContractIdentityCreatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityFactoryContractIdentityCreatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityFactoryContractIdentityCreated represents a IdentityCreated event raised by the EthereumIdentityFactoryContract contract. -type EthereumIdentityFactoryContractIdentityCreated struct { - CentrifugeId *big.Int - Identity common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIdentityCreated is a free log retrieval operation binding the contract event 0x66c4bdc16b835463ee3a16003a3d42b54e9ead21ac72ebc421bb07afd19d4a68. -// -// Solidity: e IdentityCreated(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractFilterer) FilterIdentityCreated(opts *bind.FilterOpts, centrifugeId []*big.Int) (*EthereumIdentityFactoryContractIdentityCreatedIterator, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityFactoryContract.contract.FilterLogs(opts, "IdentityCreated", centrifugeIdRule) - if err != nil { - return nil, err - } - return &EthereumIdentityFactoryContractIdentityCreatedIterator{contract: _EthereumIdentityFactoryContract.contract, event: "IdentityCreated", logs: logs, sub: sub}, nil -} - -// WatchIdentityCreated is a free log subscription operation binding the contract event 0x66c4bdc16b835463ee3a16003a3d42b54e9ead21ac72ebc421bb07afd19d4a68. -// -// Solidity: e IdentityCreated(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityFactoryContract *EthereumIdentityFactoryContractFilterer) WatchIdentityCreated(opts *bind.WatchOpts, sink chan<- *EthereumIdentityFactoryContractIdentityCreated, centrifugeId []*big.Int) (event.Subscription, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityFactoryContract.contract.WatchLogs(opts, "IdentityCreated", centrifugeIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityFactoryContractIdentityCreated) - if err := _EthereumIdentityFactoryContract.contract.UnpackLog(event, "IdentityCreated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/identity/ethid/ethereum_identity_integration_test.go b/identity/ethid/ethereum_identity_integration_test.go deleted file mode 100644 index 2f54c27a4..000000000 --- a/identity/ethid/ethereum_identity_integration_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// +build integration - -package ethid_test - -import ( - "context" - "os" - "testing" - "time" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" -) - -var identityService identity.Service -var cfg config.Configuration - -func TestMain(m *testing.M) { - // Adding delay to startup (concurrency hack) - time.Sleep(time.Second + 2) - ctx := testingbootstrap.TestFunctionalEthereumBootstrap() - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - identityService = ctx[identity.BootstrappedIDService].(identity.Service) - result := m.Run() - testingbootstrap.TestFunctionalEthereumTearDown() - os.Exit(result) -} - -func TestCreateAndLookupIdentity_Integration(t *testing.T) { - centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - wrongCentrifugeId := utils.RandomSlice(identity.CentIDLength) - wrongCentrifugeId[0] = 0x0 - wrongCentrifugeId[1] = 0x0 - wrongCentrifugeId[2] = 0x0 - wrongCentrifugeId[3] = 0x0 - wrongCentrifugeIdTyped, _ := identity.ToCentID(wrongCentrifugeId) - - cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) - assert.Nil(t, err, "should not error out when creating identity") - - watchRegisteredIdentity := <-confirmations - assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - - // LookupIdentityForID - id, err = identityService.LookupIdentityForID(centrifugeId) - assert.Nil(t, err, "should not error out when resolving identity") - assert.Equal(t, centrifugeId, id.CentID(), "CentrifugeID Should match provided one") - - _, err = identityService.LookupIdentityForID(wrongCentrifugeIdTyped) - assert.NotNil(t, err, "should error out when resolving wrong identity") - - exists, err := identityService.CheckIdentityExists(wrongCentrifugeIdTyped) - assert.NotNil(t, err, "should err when looking for incorrect identity") - assert.False(t, exists) - - // Add Key - key := utils.RandomSlice(32) - confirmations, err = id.AddKeyToIdentity(context.Background(), 1, key) - assert.Nil(t, err, "should not error out when adding key to identity") - assert.NotNil(t, confirmations, "confirmations channel should not be nil") - watchReceivedIdentity := <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - - recKey, err := id.LastKeyForPurpose(1) - assert.Nil(t, err) - assert.Equal(t, key, recKey) - - _, err = id.LastKeyForPurpose(2) - assert.NotNil(t, err) - -} - -func TestAddKeyFromConfig(t *testing.T) { - centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := cfg.GetString("identityId") - cfg.Set("identityId", centrifugeId.String()) - cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) - assert.Nil(t, err, "should not error out when creating identity") - - watchRegisteredIdentity := <-confirmations - assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - - err = identityService.AddKeyFromConfig(cfg, identity.KeyPurposeEthMsgAuth) - assert.Nil(t, err, "should not error out") - - cfg.Set("identityId", defaultCentrifugeId) -} - -func TestAddKeyFromConfig_IdentityDoesNotExist(t *testing.T) { - centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - defaultCentrifugeId := cfg.GetString("identityId") - cfg.Set("identityId", centrifugeId.String()) - cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") - - err := identityService.AddKeyFromConfig(cfg, identity.KeyPurposeEthMsgAuth) - assert.NotNil(t, err, "should error out") - - cfg.Set("identityId", defaultCentrifugeId) -} - -func TestCreateAndLookupIdentity_Integration_Concurrent(t *testing.T) { - var centIds [5]identity.CentID - var identityConfirmations [5]<-chan *identity.WatchIdentity - var err error - for ix := 0; ix < 5; ix++ { - centId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - cfg.Set("identityId", centId.String()) - centIds[ix] = centId - _, identityConfirmations[ix], err = identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centId) - assert.Nil(t, err, "should not error out upon identity creation") - } - - for ix := 0; ix < 5; ix++ { - watchSingleIdentity := <-identityConfirmations[ix] - id, err := identityService.LookupIdentityForID(watchSingleIdentity.Identity.CentID()) - assert.Nil(t, err, "should not error out upon identity resolution") - assert.Equal(t, centIds[ix], id.CentID(), "Should have the ID that was passed into create function [%v]", id.CentID()) - } -} - -func TestEthereumIdentityService_GetIdentityAddress(t *testing.T) { - centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - cfg.Set("identityId", centrifugeId.String()) - _, confirmations, err := identityService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) - assert.Nil(t, err, "should not error out when creating identity") - <-confirmations - addr, err := identityService.GetIdentityAddress(centrifugeId) - assert.Nil(t, err) - assert.True(t, len(addr) == common.AddressLength) -} - -func TestEthereumIdentityService_GetIdentityAddressNonExistingID(t *testing.T) { - _, err := identityService.GetIdentityAddress(identity.RandomCentID()) - assert.NotNil(t, err) -} diff --git a/identity/ethid/ethereum_identity_registry_contract.go b/identity/ethid/ethereum_identity_registry_contract.go deleted file mode 100644 index 10e96b744..000000000 --- a/identity/ethid/ethereum_identity_registry_contract.go +++ /dev/null @@ -1,495 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethid - -import ( - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// EthereumIdentityRegistryContractABI is the input ABI used to generate the binding from. -const EthereumIdentityRegistryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"centrifugeId\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"centrifugeId\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityUpdated\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_centrifugeId\",\"type\":\"uint48\"},{\"name\":\"_identity\",\"type\":\"address\"}],\"name\":\"registerIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_centrifugeId\",\"type\":\"uint48\"},{\"name\":\"_identity\",\"type\":\"address\"}],\"name\":\"updateIdentityAddress\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_centrifugeId\",\"type\":\"uint48\"}],\"name\":\"getIdentityByCentrifugeId\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" - -// EthereumIdentityRegistryContract is an auto generated Go binding around an Ethereum contract. -type EthereumIdentityRegistryContract struct { - EthereumIdentityRegistryContractCaller // Read-only binding to the contract - EthereumIdentityRegistryContractTransactor // Write-only binding to the contract - EthereumIdentityRegistryContractFilterer // Log filterer for contract events -} - -// EthereumIdentityRegistryContractCaller is an auto generated read-only Go binding around an Ethereum contract. -type EthereumIdentityRegistryContractCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityRegistryContractTransactor is an auto generated write-only Go binding around an Ethereum contract. -type EthereumIdentityRegistryContractTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityRegistryContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type EthereumIdentityRegistryContractFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// EthereumIdentityRegistryContractSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type EthereumIdentityRegistryContractSession struct { - Contract *EthereumIdentityRegistryContract // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityRegistryContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type EthereumIdentityRegistryContractCallerSession struct { - Contract *EthereumIdentityRegistryContractCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// EthereumIdentityRegistryContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type EthereumIdentityRegistryContractTransactorSession struct { - Contract *EthereumIdentityRegistryContractTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// EthereumIdentityRegistryContractRaw is an auto generated low-level Go binding around an Ethereum contract. -type EthereumIdentityRegistryContractRaw struct { - Contract *EthereumIdentityRegistryContract // Generic contract binding to access the raw methods on -} - -// EthereumIdentityRegistryContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type EthereumIdentityRegistryContractCallerRaw struct { - Contract *EthereumIdentityRegistryContractCaller // Generic read-only contract binding to access the raw methods on -} - -// EthereumIdentityRegistryContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type EthereumIdentityRegistryContractTransactorRaw struct { - Contract *EthereumIdentityRegistryContractTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewEthereumIdentityRegistryContract creates a new instance of EthereumIdentityRegistryContract, bound to a specific deployed contract. -func NewEthereumIdentityRegistryContract(address common.Address, backend bind.ContractBackend) (*EthereumIdentityRegistryContract, error) { - contract, err := bindEthereumIdentityRegistryContract(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContract{EthereumIdentityRegistryContractCaller: EthereumIdentityRegistryContractCaller{contract: contract}, EthereumIdentityRegistryContractTransactor: EthereumIdentityRegistryContractTransactor{contract: contract}, EthereumIdentityRegistryContractFilterer: EthereumIdentityRegistryContractFilterer{contract: contract}}, nil -} - -// NewEthereumIdentityRegistryContractCaller creates a new read-only instance of EthereumIdentityRegistryContract, bound to a specific deployed contract. -func NewEthereumIdentityRegistryContractCaller(address common.Address, caller bind.ContractCaller) (*EthereumIdentityRegistryContractCaller, error) { - contract, err := bindEthereumIdentityRegistryContract(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContractCaller{contract: contract}, nil -} - -// NewEthereumIdentityRegistryContractTransactor creates a new write-only instance of EthereumIdentityRegistryContract, bound to a specific deployed contract. -func NewEthereumIdentityRegistryContractTransactor(address common.Address, transactor bind.ContractTransactor) (*EthereumIdentityRegistryContractTransactor, error) { - contract, err := bindEthereumIdentityRegistryContract(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContractTransactor{contract: contract}, nil -} - -// NewEthereumIdentityRegistryContractFilterer creates a new log filterer instance of EthereumIdentityRegistryContract, bound to a specific deployed contract. -func NewEthereumIdentityRegistryContractFilterer(address common.Address, filterer bind.ContractFilterer) (*EthereumIdentityRegistryContractFilterer, error) { - contract, err := bindEthereumIdentityRegistryContract(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContractFilterer{contract: contract}, nil -} - -// bindEthereumIdentityRegistryContract binds a generic wrapper to an already deployed contract. -func bindEthereumIdentityRegistryContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(EthereumIdentityRegistryContractABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityRegistryContract.Contract.EthereumIdentityRegistryContractCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.EthereumIdentityRegistryContractTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.EthereumIdentityRegistryContractTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _EthereumIdentityRegistryContract.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.contract.Transact(opts, method, params...) -} - -// GetIdentityByCentrifugeId is a free data retrieval call binding the contract method 0x5c7bf661. -// -// Solidity: function getIdentityByCentrifugeId(_centrifugeId uint48) constant returns(address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractCaller) GetIdentityByCentrifugeId(opts *bind.CallOpts, _centrifugeId *big.Int) (common.Address, error) { - var ( - ret0 = new(common.Address) - ) - out := ret0 - err := _EthereumIdentityRegistryContract.contract.Call(opts, out, "getIdentityByCentrifugeId", _centrifugeId) - return *ret0, err -} - -// GetIdentityByCentrifugeId is a free data retrieval call binding the contract method 0x5c7bf661. -// -// Solidity: function getIdentityByCentrifugeId(_centrifugeId uint48) constant returns(address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractSession) GetIdentityByCentrifugeId(_centrifugeId *big.Int) (common.Address, error) { - return _EthereumIdentityRegistryContract.Contract.GetIdentityByCentrifugeId(&_EthereumIdentityRegistryContract.CallOpts, _centrifugeId) -} - -// GetIdentityByCentrifugeId is a free data retrieval call binding the contract method 0x5c7bf661. -// -// Solidity: function getIdentityByCentrifugeId(_centrifugeId uint48) constant returns(address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractCallerSession) GetIdentityByCentrifugeId(_centrifugeId *big.Int) (common.Address, error) { - return _EthereumIdentityRegistryContract.Contract.GetIdentityByCentrifugeId(&_EthereumIdentityRegistryContract.CallOpts, _centrifugeId) -} - -// RegisterIdentity is a paid mutator transaction binding the contract method 0xfa3a3106. -// -// Solidity: function registerIdentity(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactor) RegisterIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.contract.Transact(opts, "registerIdentity", _centrifugeId, _identity) -} - -// RegisterIdentity is a paid mutator transaction binding the contract method 0xfa3a3106. -// -// Solidity: function registerIdentity(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractSession) RegisterIdentity(_centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.RegisterIdentity(&_EthereumIdentityRegistryContract.TransactOpts, _centrifugeId, _identity) -} - -// RegisterIdentity is a paid mutator transaction binding the contract method 0xfa3a3106. -// -// Solidity: function registerIdentity(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactorSession) RegisterIdentity(_centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.RegisterIdentity(&_EthereumIdentityRegistryContract.TransactOpts, _centrifugeId, _identity) -} - -// UpdateIdentityAddress is a paid mutator transaction binding the contract method 0xc3e82b06. -// -// Solidity: function updateIdentityAddress(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactor) UpdateIdentityAddress(opts *bind.TransactOpts, _centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.contract.Transact(opts, "updateIdentityAddress", _centrifugeId, _identity) -} - -// UpdateIdentityAddress is a paid mutator transaction binding the contract method 0xc3e82b06. -// -// Solidity: function updateIdentityAddress(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractSession) UpdateIdentityAddress(_centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.UpdateIdentityAddress(&_EthereumIdentityRegistryContract.TransactOpts, _centrifugeId, _identity) -} - -// UpdateIdentityAddress is a paid mutator transaction binding the contract method 0xc3e82b06. -// -// Solidity: function updateIdentityAddress(_centrifugeId uint48, _identity address) returns() -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractTransactorSession) UpdateIdentityAddress(_centrifugeId *big.Int, _identity common.Address) (*types.Transaction, error) { - return _EthereumIdentityRegistryContract.Contract.UpdateIdentityAddress(&_EthereumIdentityRegistryContract.TransactOpts, _centrifugeId, _identity) -} - -// EthereumIdentityRegistryContractIdentityRegisteredIterator is returned from FilterIdentityRegistered and is used to iterate over the raw logs and unpacked data for IdentityRegistered events raised by the EthereumIdentityRegistryContract contract. -type EthereumIdentityRegistryContractIdentityRegisteredIterator struct { - Event *EthereumIdentityRegistryContractIdentityRegistered // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityRegistryContractIdentityRegisteredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityRegistryContractIdentityRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityRegistryContractIdentityRegistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityRegistryContractIdentityRegisteredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityRegistryContractIdentityRegisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityRegistryContractIdentityRegistered represents a IdentityRegistered event raised by the EthereumIdentityRegistryContract contract. -type EthereumIdentityRegistryContractIdentityRegistered struct { - CentrifugeId *big.Int - Identity common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIdentityRegistered is a free log retrieval operation binding the contract event 0xdce3b1d0a5d5575f7d94c88f0300b0af4cbe28c211f11c315cbac957b32ddb49. -// -// Solidity: e IdentityRegistered(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractFilterer) FilterIdentityRegistered(opts *bind.FilterOpts, centrifugeId []*big.Int) (*EthereumIdentityRegistryContractIdentityRegisteredIterator, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityRegistryContract.contract.FilterLogs(opts, "IdentityRegistered", centrifugeIdRule) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContractIdentityRegisteredIterator{contract: _EthereumIdentityRegistryContract.contract, event: "IdentityRegistered", logs: logs, sub: sub}, nil -} - -// WatchIdentityRegistered is a free log subscription operation binding the contract event 0xdce3b1d0a5d5575f7d94c88f0300b0af4cbe28c211f11c315cbac957b32ddb49. -// -// Solidity: e IdentityRegistered(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractFilterer) WatchIdentityRegistered(opts *bind.WatchOpts, sink chan<- *EthereumIdentityRegistryContractIdentityRegistered, centrifugeId []*big.Int) (event.Subscription, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityRegistryContract.contract.WatchLogs(opts, "IdentityRegistered", centrifugeIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityRegistryContractIdentityRegistered) - if err := _EthereumIdentityRegistryContract.contract.UnpackLog(event, "IdentityRegistered", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// EthereumIdentityRegistryContractIdentityUpdatedIterator is returned from FilterIdentityUpdated and is used to iterate over the raw logs and unpacked data for IdentityUpdated events raised by the EthereumIdentityRegistryContract contract. -type EthereumIdentityRegistryContractIdentityUpdatedIterator struct { - Event *EthereumIdentityRegistryContractIdentityUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *EthereumIdentityRegistryContractIdentityUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityRegistryContractIdentityUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(EthereumIdentityRegistryContractIdentityUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *EthereumIdentityRegistryContractIdentityUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *EthereumIdentityRegistryContractIdentityUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// EthereumIdentityRegistryContractIdentityUpdated represents a IdentityUpdated event raised by the EthereumIdentityRegistryContract contract. -type EthereumIdentityRegistryContractIdentityUpdated struct { - CentrifugeId *big.Int - Identity common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterIdentityUpdated is a free log retrieval operation binding the contract event 0xb0eb267eb8047ce01327cdd07db5733b07c2d488cb922b20b723a596b53b659c. -// -// Solidity: e IdentityUpdated(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractFilterer) FilterIdentityUpdated(opts *bind.FilterOpts, centrifugeId []*big.Int) (*EthereumIdentityRegistryContractIdentityUpdatedIterator, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityRegistryContract.contract.FilterLogs(opts, "IdentityUpdated", centrifugeIdRule) - if err != nil { - return nil, err - } - return &EthereumIdentityRegistryContractIdentityUpdatedIterator{contract: _EthereumIdentityRegistryContract.contract, event: "IdentityUpdated", logs: logs, sub: sub}, nil -} - -// WatchIdentityUpdated is a free log subscription operation binding the contract event 0xb0eb267eb8047ce01327cdd07db5733b07c2d488cb922b20b723a596b53b659c. -// -// Solidity: e IdentityUpdated(centrifugeId indexed uint48, identity address) -func (_EthereumIdentityRegistryContract *EthereumIdentityRegistryContractFilterer) WatchIdentityUpdated(opts *bind.WatchOpts, sink chan<- *EthereumIdentityRegistryContractIdentityUpdated, centrifugeId []*big.Int) (event.Subscription, error) { - - var centrifugeIdRule []interface{} - for _, centrifugeIdItem := range centrifugeId { - centrifugeIdRule = append(centrifugeIdRule, centrifugeIdItem) - } - - logs, sub, err := _EthereumIdentityRegistryContract.contract.WatchLogs(opts, "IdentityUpdated", centrifugeIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(EthereumIdentityRegistryContractIdentityUpdated) - if err := _EthereumIdentityRegistryContract.contract.UnpackLog(event, "IdentityUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} diff --git a/identity/ethid/ethereum_identity_test.go b/identity/ethid/ethereum_identity_test.go deleted file mode 100644 index 9399ebaa7..000000000 --- a/identity/ethid/ethereum_identity_test.go +++ /dev/null @@ -1,423 +0,0 @@ -// +build unit - -package ethid - -import ( - "math/big" - "testing" - - "github.com/centrifuge/go-centrifuge/testingutils/commons" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -type MockIDFactory struct { - mock.Mock -} - -func (f MockIDFactory) CreateIdentity(opts *bind.TransactOpts, _centrifugeId *big.Int) (*types.Transaction, error) { - args := f.Called(opts, _centrifugeId) - id := args.Get(0).(*types.Transaction) - return id, args.Error(1) -} - -type MockIDRegistry struct { - mock.Mock -} - -func (r MockIDRegistry) GetIdentityByCentrifugeId(opts *bind.CallOpts, bigInt *big.Int) (common.Address, error) { - args := r.Called(opts, bigInt) - id := args.Get(0).(common.Address) - return id, args.Error(1) -} - -type MockIDContract struct { - mock.Mock -} - -func (mic MockIDContract) AddKey(opts *bind.TransactOpts, _key [32]byte, _kPurpose *big.Int) (*types.Transaction, error) { - args := mic.Called(opts, _key, _kPurpose) - return args.Get(0).(*types.Transaction), args.Error(1) -} - -func (mic MockIDContract) GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) { - args := mic.Called(opts, _purpose) - return args.Get(0).([][32]byte), args.Error(1) -} - -func (mic MockIDContract) GetKey(opts *bind.CallOpts, _key [32]byte) (struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int -}, error) { - args := mic.Called(opts, _key) - return args.Get(0).(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }), args.Error(1) -} - -func (mic MockIDContract) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) { - args := mic.Called(opts, key, purpose) - return args.Get(0).(*EthereumIdentityContractKeyAddedIterator), args.Error(1) -} - -func TestGetClientP2PURL_happy(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetClientP2PURL(centID) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.NotEmpty(t, p2p, "p2p url is empty") - assert.Nil(t, err, "error should be nil") -} - -func TestGetClientP2PURL_fail_identity_lookup(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) - i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetClientP2PURL(centID) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "ID lookup failed") -} - -func TestGetClientP2PURL_fail_p2pkey_error(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKeysByPurpose", mock.Anything, mock.Anything).Return([][32]byte{{1}}, errors.New("p2p key error")) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetClientP2PURL(centID) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "p2p key error") -} - -func TestGetIdentityKey_fail_lookup(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), errors.New("ID lookup failed")) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetIdentityKey(centID, pubKey) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "ID lookup failed") -} - -func TestGetIdentityKey_fail_FetchKey(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - [32]byte{1}, - []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, - big.NewInt(1), - }, errors.New("p2p key error")) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetIdentityKey(centID, pubKey) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "p2p key error") -} - -func TestGetIdentityKey_fail_empty(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - [32]byte{}, - []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, - big.NewInt(1), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetIdentityKey(centID, pubKey) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Empty(t, p2p, "p2p is not empty") - assert.Errorf(t, err, "error should not be nil") - assert.Contains(t, err.Error(), "key not found for identity") -} - -func TestGetIdentityKey_Success(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - [32]byte{1}, - []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, - big.NewInt(1), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - p2p, err := srv.GetIdentityKey(centID, pubKey) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.NotEmpty(t, p2p, "p2p is empty") - assert.Nil(t, err, "error must be nil") -} - -func TestValidateKey_success(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - var key [32]byte - copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - key, - []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - big.NewInt(0), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Nil(t, err, "error must be nil") -} - -func TestValidateKey_fail_getId(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - var key [32]byte - copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - key, - []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - big.NewInt(0), - }, errors.New("Key error")) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Contains(t, err.Error(), "Key error") -} - -func TestValidateKey_fail_mismatch_key(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - [32]byte{1}, - []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - big.NewInt(0), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Contains(t, err.Error(), "Key doesn't match") -} - -func TestValidateKey_fail_missing_purpose(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - var key [32]byte - copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - key, - nil, - big.NewInt(0), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Contains(t, err.Error(), "Key doesn't have purpose") -} - -func TestValidateKey_fail_wrong_purpose(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - var key [32]byte - copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - key, - []*big.Int{big.NewInt(identity.KeyPurposeP2P)}, - big.NewInt(0), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Contains(t, err.Error(), "Key doesn't have purpose") -} - -func TestValidateKey_fail_revocation(t *testing.T) { - centID, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - pubKey := utils.RandomSlice(32) - var key [32]byte - copy(key[:], pubKey) - c, f, r, g, i := &testingconfig.MockConfig{}, &MockIDFactory{}, &MockIDRegistry{}, &testingcommons.MockEthClient{}, &MockIDContract{} - g.On("GetGethCallOpts").Return(&bind.CallOpts{}, func() {}) - g.On("GetEthClient").Return(ðclient.Client{}) - r.On("GetIdentityByCentrifugeId", mock.Anything, centID.BigInt()).Return(common.BytesToAddress(utils.RandomSlice(20)), nil) - i.On("GetKey", mock.Anything, mock.Anything).Return(struct { - Key [32]byte - Purposes []*big.Int - RevokedAt *big.Int - }{ - key, - []*big.Int{big.NewInt(identity.KeyPurposeSigning)}, - big.NewInt(1), - }, nil) - srv := NewEthereumIdentityService(c, f, r, nil, func() ethereum.Client { - return g - }, func(address common.Address, backend bind.ContractBackend) (contract, error) { - return i, nil - }) - err := srv.ValidateKey(centID, pubKey, identity.KeyPurposeSigning) - f.AssertExpectations(t) - r.AssertExpectations(t) - g.AssertExpectations(t) - assert.Contains(t, err.Error(), "Key is currently revoked since block") -} diff --git a/identity/ethid/id_registration_confirmation_task.go b/identity/ethid/id_registration_confirmation_task.go deleted file mode 100644 index 5c7ffbd05..000000000 --- a/identity/ethid/id_registration_confirmation_task.go +++ /dev/null @@ -1,124 +0,0 @@ -package ethid - -import ( - "context" - "math/big" - "time" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/accounts/abi/bind" -) - -const ( - idRegistrationConfirmationTaskName string = "idRegistrationConfirmationTaskName" -) - -type identitiesCreatedFilterer interface { - FilterIdentityCreated(opts *bind.FilterOpts, centID []*big.Int) (*EthereumIdentityFactoryContractIdentityCreatedIterator, error) -} - -// idRegistrationConfirmationTask is a queued task to watch ID registration events on Ethereum using EthereumIdentityFactoryContract. -// To see how it gets registered see bootstrapper.go and to see how it gets used see setUpRegistrationEventListener method -type idRegistrationConfirmationTask struct { - centID identity.CentID - blockHeight uint64 - timeout time.Duration - contextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) - ctx context.Context - filterer identitiesCreatedFilterer -} - -func newIDRegistrationConfirmationTask( - timeout time.Duration, - identityCreatedWatcher identitiesCreatedFilterer, - ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), -) *idRegistrationConfirmationTask { - return &idRegistrationConfirmationTask{ - timeout: timeout, - filterer: identityCreatedWatcher, - contextInitializer: ethContextInitializer, - } -} - -// TaskTypeName returns the name of the task -func (rct *idRegistrationConfirmationTask) TaskTypeName() string { - return idRegistrationConfirmationTaskName -} - -// Copy returns a new copy of the the task -func (rct *idRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &idRegistrationConfirmationTask{ - rct.centID, - rct.blockHeight, - rct.timeout, - rct.contextInitializer, - rct.ctx, - rct.filterer}, nil -} - -// ParseKwargs parses the kwargs into the task. -func (rct *idRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - id, ok := kwargs[centIDParam] - if !ok { - return errors.New("undefined kwarg " + centIDParam) - } - centID, err := getCentID(id) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) - } - rct.centID = centID - - rct.blockHeight, err = queue.ParseBlockHeight(kwargs) - if err != nil { - return err - } - - // override timeout param if provided - tdRaw, ok := kwargs[queue.TimeoutParam] - if ok { - td, err := queue.GetDuration(tdRaw) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) - } - rct.timeout = td - } - - return nil -} - -// RunTask calls listens to events from geth related to idRegistrationConfirmationTask#CentID and records result. -func (rct *idRegistrationConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the ID [%x]", rct.centID) - if rct.ctx == nil { - rct.ctx, _ = rct.contextInitializer(rct.timeout) - } - - fOpts := &bind.FilterOpts{ - Context: rct.ctx, - Start: rct.blockHeight, - } - - for { - iter, err := rct.filterer.FilterIdentityCreated(fOpts, []*big.Int{rct.centID.BigInt()}) - if err != nil { - return nil, centerrors.Wrap(err, "failed to start filtering identity event logs") - } - - err = utils.LookForEvent(iter) - if err == nil { - log.Infof("Received filtered event Id Registration Confirmation for CentrifugeID [%s]\n", rct.centID.String()) - return iter.Event, nil - } - - if err != utils.ErrEventNotFound { - return nil, err - } - time.Sleep(100 * time.Millisecond) - } -} diff --git a/identity/ethid/id_registration_confirmation_task_test.go b/identity/ethid/id_registration_confirmation_task_test.go deleted file mode 100644 index f8030fd65..000000000 --- a/identity/ethid/id_registration_confirmation_task_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// +build unit - -package ethid - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -func TestRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { - rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - blockHeight := uint64(3132) - timeout := float64(3000) - idBytes, _ := identity.ToCentID(id) - kwargs := map[string]interface{}{ - centIDParam: idBytes, - queue.BlockHeightParam: blockHeight, - queue.TimeoutParam: timeout, - } - decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) - err = rct.ParseKwargs(decoded) - if err != nil { - t.Errorf("Could not parse %s for [%x]", centIDParam, id) - } - assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") - assert.Equal(t, blockHeight, rct.blockHeight, "Resulting blockheight should be same as the input") -} - -func TestRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { - rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{"notId": id}) - assert.NotNil(t, err, "Should not allow parsing without centId") -} - -func TestRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { - rct := idRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) - assert.NotNil(t, err, "Should not parse without the correct type of centId") -} diff --git a/identity/ethid/key_registration_confirmation_task.go b/identity/ethid/key_registration_confirmation_task.go deleted file mode 100644 index c2aacb5b7..000000000 --- a/identity/ethid/key_registration_confirmation_task.go +++ /dev/null @@ -1,180 +0,0 @@ -package ethid - -import ( - "context" - "math/big" - "time" - - "github.com/centrifuge/go-centrifuge/identity" - - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/gocelery" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -const ( - keyRegistrationConfirmationTaskName = "keyRegistrationConfirmationTaskName" - keyParam = "keyParam" - keyPurposeParam = "keyPurposeParam" -) - -type keyRegisteredFilterer interface { - FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int) (*EthereumIdentityContractKeyAddedIterator, error) -} - -// keyRegistrationConfirmationTask is a queued task to filter key registration events on Ethereum using EthereumIdentityContract. -// To see how it gets registered see bootstrapper.go and to see how it gets used see setUpKeyRegisteredEventListener method -type keyRegistrationConfirmationTask struct { - centID identity.CentID - key [32]byte - keyPurpose int - blockHeight uint64 - timeout time.Duration - contextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) - ctx context.Context - filterer keyRegisteredFilterer - contract *EthereumIdentityRegistryContract - config identity.Config - gethClientFinder func() ethereum.Client - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error) - queue *queue.Server -} - -func newKeyRegistrationConfirmationTask( - ethContextInitializer func(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc), - registryContract *EthereumIdentityRegistryContract, - config identity.Config, - queue *queue.Server, - gethClientFinder func() ethereum.Client, - contractProvider func(address common.Address, backend bind.ContractBackend) (contract, error), -) *keyRegistrationConfirmationTask { - return &keyRegistrationConfirmationTask{ - contextInitializer: ethContextInitializer, - contract: registryContract, - config: config, - queue: queue, - timeout: config.GetEthereumContextWaitTimeout(), - gethClientFinder: gethClientFinder, - contractProvider: contractProvider, - } -} - -// TaskTypeName returns keyRegistrationConfirmationTaskName -func (krct *keyRegistrationConfirmationTask) TaskTypeName() string { - return keyRegistrationConfirmationTaskName -} - -// Copy returns a new copy of the task -func (krct *keyRegistrationConfirmationTask) Copy() (gocelery.CeleryTask, error) { - return &keyRegistrationConfirmationTask{ - krct.centID, - krct.key, - krct.keyPurpose, - krct.blockHeight, - krct.timeout, - krct.contextInitializer, - krct.ctx, - krct.filterer, - krct.contract, - krct.config, - krct.gethClientFinder, - krct.contractProvider, - krct.queue, - }, nil -} - -// ParseKwargs parses the args into the task -func (krct *keyRegistrationConfirmationTask) ParseKwargs(kwargs map[string]interface{}) error { - id, ok := kwargs[centIDParam] - if !ok { - return errors.New("undefined kwarg " + centIDParam) - } - centID, err := getCentID(id) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", centIDParam, err.Error()) - } - krct.centID = centID - - // key parsing - key, ok := kwargs[keyParam] - if !ok { - return errors.New("undefined kwarg " + keyParam) - } - keyTyped, err := getBytes32(key) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", keyParam, err.Error()) - } - krct.key = keyTyped - - // key purpose parsing - keyPurpose, ok := kwargs[keyPurposeParam] - if !ok { - return errors.New("undefined kwarg " + keyPurposeParam) - } - keyPurposeF, ok := keyPurpose.(float64) - if ok { - krct.keyPurpose = int(keyPurposeF) - } else { - return errors.New("can not parse " + keyPurposeParam) - } - - // block height parsing - krct.blockHeight, err = queue.ParseBlockHeight(kwargs) - if err != nil { - return err - } - - tdRaw, ok := kwargs[queue.TimeoutParam] - if ok { - td, err := queue.GetDuration(tdRaw) - if err != nil { - return errors.New("malformed kwarg [%s] because [%s]", queue.TimeoutParam, err.Error()) - } - krct.timeout = td - } - - return nil -} - -// RunTask calls listens to events from geth related to keyRegistrationConfirmationTask#Key and records result. -func (krct *keyRegistrationConfirmationTask) RunTask() (interface{}, error) { - log.Infof("Waiting for confirmation for the Key [%x]", krct.key) - if krct.ctx == nil { - krct.ctx, _ = krct.contextInitializer(krct.timeout) - } - - id := newEthereumIdentity(krct.centID, krct.contract, krct.config, krct.queue, krct.gethClientFinder, krct.contractProvider) - contract, err := id.getContract() - if err != nil { - return nil, err - } - - krct.filterer = contract - fOpts := &bind.FilterOpts{ - Context: krct.ctx, - Start: krct.blockHeight, - } - - for { - iter, err := krct.filterer.FilterKeyAdded(fOpts, [][32]byte{krct.key}, []*big.Int{big.NewInt(int64(krct.keyPurpose))}) - if err != nil { - return nil, centerrors.Wrap(err, "failed to start filtering key event logs") - } - - err = utils.LookForEvent(iter) - if err == nil { - log.Infof("Received filtered event Key Registration Confirmation for CentrifugeID [%s] and key [%x] with purpose [%d]\n", krct.centID.String(), krct.key, krct.keyPurpose) - return iter.Event, nil - } - - if err != utils.ErrEventNotFound { - return nil, err - } - time.Sleep(100 * time.Millisecond) - } -} diff --git a/identity/ethid/key_registration_confirmation_task_test.go b/identity/ethid/key_registration_confirmation_task_test.go deleted file mode 100644 index 044aae24b..000000000 --- a/identity/ethid/key_registration_confirmation_task_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build unit - -package ethid - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/identity" - - "time" - - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPath(t *testing.T) { - rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} - id := utils.RandomSlice(identity.CentIDLength) - key := utils.RandomSlice(32) - var keyFixed [32]byte - copy(keyFixed[:], key) - keyPurpose := identity.KeyPurposeSigning - bh := uint64(12) - idBytes, _ := identity.ToCentID(id) - kwargs := map[string]interface{}{ - centIDParam: idBytes, - keyParam: keyFixed, - keyPurposeParam: keyPurpose, - queue.BlockHeightParam: bh, - } - decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) - err = rct.ParseKwargs(decoded) - if err != nil { - t.Errorf("parse error %s", err.Error()) - } - assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") - assert.Equal(t, keyFixed, rct.key, "Resulting key should be same as the input") - assert.Equal(t, keyPurpose, rct.keyPurpose, "Resulting keyPurpose should be same as the input") - assert.Equal(t, bh, rct.blockHeight, "Resulting blockheight should be same as the input") -} - -func TestKeyRegistrationConfirmationTask_ParseKwargsHappyPathOverrideTimeout(t *testing.T) { - rct := keyRegistrationConfirmationTask{timeout: time.Second * 10} - id := utils.RandomSlice(identity.CentIDLength) - key := utils.RandomSlice(32) - var keyFixed [32]byte - copy(keyFixed[:], key) - keyPurpose := identity.KeyPurposeSigning - bh := uint64(12) - idBytes, _ := identity.ToCentID(id) - overrideTimeout := float64(time.Second * 3) - kwargs := map[string]interface{}{ - centIDParam: idBytes, - keyParam: keyFixed, - keyPurposeParam: keyPurpose, - queue.BlockHeightParam: bh, - queue.TimeoutParam: overrideTimeout, - } - decoded, err := utils.SimulateJSONDecodeForGocelery(kwargs) - err = rct.ParseKwargs(decoded) - if err != nil { - t.Errorf("parse error %s", err.Error()) - } - assert.Equal(t, idBytes, rct.centID, "Resulting mockID should have the same ID as the input") - assert.Equal(t, keyFixed, rct.key, "Resulting key should be same as the input") - assert.Equal(t, keyPurpose, rct.keyPurpose, "Resulting keyPurpose should be same as the input") - assert.Equal(t, bh, rct.blockHeight, "Resulting blockheight should be same as the input") - assert.Equal(t, time.Duration(overrideTimeout).Seconds(), rct.timeout.Seconds(), "Resulting timeout should be overwritten by kwargs") -} - -func TestKeyRegistrationConfirmationTask_ParseKwargsDoesNotExist(t *testing.T) { - rct := keyRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{"notId": id}) - assert.NotNil(t, err, "Should not allow parsing without centId") -} - -func TestKeyRegistrationConfirmationTask_ParseKwargsInvalidType(t *testing.T) { - rct := keyRegistrationConfirmationTask{} - id := utils.RandomSlice(identity.CentIDLength) - err := rct.ParseKwargs(map[string]interface{}{centIDParam: id}) - assert.NotNil(t, err, "Should not parse without the correct type of centId") -} diff --git a/identity/ethid/test_bootstrapper.go b/identity/ethid/test_bootstrapper.go deleted file mode 100644 index 39c9e3416..000000000 --- a/identity/ethid/test_bootstrapper.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build integration unit - -package ethid - -func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { - return b.Bootstrap(context) -} - -func (*Bootstrapper) TestTearDown() error { - return nil -} diff --git a/identity/ethid/util.go b/identity/ethid/util.go deleted file mode 100644 index 354208908..000000000 --- a/identity/ethid/util.go +++ /dev/null @@ -1,38 +0,0 @@ -package ethid - -import ( - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" -) - -const ( - centIDParam string = "CentID" -) - -func getBytes32(key interface{}) ([32]byte, error) { - var fixed [32]byte - b, ok := key.([]interface{}) - if !ok { - return fixed, errors.New("could not parse interface to []byte") - } - // convert and copy b byte values - for i, v := range b { - fv := v.(float64) - fixed[i] = byte(fv) - } - return fixed, nil -} - -func getCentID(key interface{}) (identity.CentID, error) { - var fixed [identity.CentIDLength]byte - b, ok := key.([]interface{}) - if !ok { - return fixed, errors.New("could not parse interface to []byte") - } - // convert and copy b byte values - for i, v := range b { - fv := v.(float64) - fixed[i] = byte(fv) - } - return fixed, nil -} diff --git a/identity/identity.go b/identity/identity.go deleted file mode 100644 index 4431ef46d..000000000 --- a/identity/identity.go +++ /dev/null @@ -1,254 +0,0 @@ -package identity - -import ( - "context" - "fmt" - "math/big" - - "github.com/centrifuge/go-centrifuge/crypto" - - "github.com/centrifuge/go-centrifuge/errors" - - "time" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/centerrors" - "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -const ( - - // BootstrappedIDService is used as a key to map the configured ID Service through context. - BootstrappedIDService string = "BootstrappedIDService" - - // CentIDLength is the length in bytes of the CentrifugeID - CentIDLength = 6 - - // KeyPurposeP2P represents a key used for p2p txns - KeyPurposeP2P = 1 - - // KeyPurposeSigning represents a key used for signing - KeyPurposeSigning = 2 - - // KeyPurposeEthMsgAuth represents a key used for ethereum txns - KeyPurposeEthMsgAuth = 3 - - // KeyTypeECDSA has the value one in the ERC725 identity contract - KeyTypeECDSA = 1 -) - -// CentID represents a CentIDLength identity of an entity -type CentID [CentIDLength]byte - -// IDConfig holds information about the identity -type IDConfig struct { - ID CentID - Keys map[int]IDKey -} - -// IDKey represents a key pair -type IDKey struct { - PublicKey []byte - PrivateKey []byte -} - -// Equal checks if c == other -func (c CentID) Equal(other CentID) bool { - for i := range c { - if c[i] != other[i] { - return false - } - } - - return true -} - -// String returns the hex format of CentID -func (c CentID) String() string { - return hexutil.Encode(c[:]) -} - -// BigInt returns CentID in bigInt -func (c CentID) BigInt() *big.Int { - return utils.ByteSliceToBigInt(c[:]) -} - -// Config defines methods required for the package identity. -type Config interface { - GetEthereumDefaultAccountName() string - GetIdentityID() ([]byte, error) - GetP2PKeyPair() (pub, priv string) - GetSigningKeyPair() (pub, priv string) - GetEthAuthKeyPair() (pub, priv string) - GetEthereumContextWaitTimeout() time.Duration -} - -// Identity defines an Identity on chain -type Identity interface { - fmt.Stringer - CentID() CentID - SetCentrifugeID(centID CentID) - CurrentP2PKey() (ret string, err error) - LastKeyForPurpose(keyPurpose int) (key []byte, err error) - AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *WatchIdentity, err error) - FetchKey(key []byte) (Key, error) -} - -// Key defines a single ERC725 identity key -type Key interface { - GetKey() [32]byte - GetPurposes() []*big.Int - GetRevokedAt() *big.Int -} - -// WatchIdentity holds the identity received form chain event -type WatchIdentity struct { - Identity Identity - Error error -} - -// Service is used to interact with centrifuge identities -// Deprecated -type Service interface { - - // LookupIdentityForID looks up if the identity for given CentID exists on ethereum TODO: remove func - LookupIdentityForID(centrifugeID CentID) (id Identity, err error) - - // CreateIdentity creates an identity representing the id on ethereum TODO: edit remove CentID - CreateIdentity(ctx context.Context, centrifugeID CentID) (id Identity, confirmations chan *WatchIdentity, err error) - - // CheckIdentityExists checks if the identity represented by id actually exists on ethereum - CheckIdentityExists(centrifugeID CentID) (exists bool, err error) - - // GetIdentityAddress gets the address of the ethereum identity contract for the given CentID TODO: remove func - GetIdentityAddress(centID CentID) (common.Address, error) - - // GetClientP2PURL returns the p2p url associated with the centID - GetClientP2PURL(centID CentID) (url string, err error) - - // GetClientsP2PURLs returns p2p urls associated with each centIDs - // will error out at first failure - GetClientsP2PURLs(centIDs []CentID) ([]string, error) - - // GetIdentityKey returns the key for provided identity TODO: change func name - GetIdentityKey(identity CentID, pubKey []byte) (keyInfo Key, err error) - - // ValidateKey checks if a given key is valid for the given centrifugeID. - ValidateKey(centID CentID, key []byte, purpose int) error - - // AddKeyFromConfig adds a key previously generated and indexed in the configuration file to the identity specified in such config file TODO: not part of the service anymore - AddKeyFromConfig(config Config, purpose int) error - - // ValidateSignature validates a signature on a message based on identity data TODO: add purpose parameter - ValidateSignature(signature *coredocumentpb.Signature, message []byte) error -} - -// GetIdentityConfig returns the identity and keys associated with the node. -func GetIdentityConfig(config Config) (*IDConfig, error) { - centIDBytes, err := config.GetIdentityID() - if err != nil { - return nil, err - } - centID, err := ToCentID(centIDBytes) - if err != nil { - return nil, err - } - - //ed25519 keys - keys := map[int]IDKey{} - - pk, sk, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) - if err != nil { - return nil, err - } - keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} - - pk, sk, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) - if err != nil { - return nil, err - } - keys[KeyPurposeSigning] = IDKey{PublicKey: pk, PrivateKey: sk} - - //secp256k1 keys - pk, sk, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) - if err != nil { - return nil, err - } - pubKey, err := hexutil.Decode(secp256k1.GetAddress(pk)) - if err != nil { - return nil, err - } - keys[KeyPurposeEthMsgAuth] = IDKey{PublicKey: pubKey, PrivateKey: sk} - - return &IDConfig{ID: centID, Keys: keys}, nil -} - -// ToCentID takes bytes and return CentID -// errors out if bytes are empty, nil, or len(bytes) > CentIDLength -func ToCentID(bytes []byte) (centID CentID, err error) { - if utils.IsEmptyByteSlice(bytes) { - return centID, errors.New("empty bytes provided") - } - - if !utils.IsValidByteSliceForLength(bytes, CentIDLength) { - return centID, errors.New("invalid length byte slice provided for centID") - } - - copy(centID[:], bytes[:CentIDLength]) - return centID, nil -} - -// CentIDFromString takes an hex string and returns a CentID -func CentIDFromString(id string) (centID CentID, err error) { - decID, err := hexutil.Decode(id) - if err != nil { - return centID, centerrors.Wrap(err, "failed to decode id") - } - - return ToCentID(decID) -} - -// CentIDsFromStrings converts hex ids to centIDs -func CentIDsFromStrings(ids []string) ([]CentID, error) { - var cids []CentID - for _, id := range ids { - cid, err := CentIDFromString(id) - if err != nil { - return nil, err - } - - cids = append(cids, cid) - } - - return cids, nil -} - -// RandomCentID returns a randomly generated CentID -func RandomCentID() CentID { - ID, _ := ToCentID(utils.RandomSlice(CentIDLength)) - return ID -} - -// ValidateCentrifugeIDBytes validates a centrifuge ID given as bytes -func ValidateCentrifugeIDBytes(givenCentID []byte, centrifugeID CentID) error { - centIDSignature, err := ToCentID(givenCentID) - if err != nil { - return err - } - - if !centrifugeID.Equal(centIDSignature) { - return errors.New("provided bytes doesn't match centID") - } - - return nil -} - -// Sign the document with the private key and return the signature along with the public key for the verification -// assumes that signing root for the document is generated -func Sign(idConfig *IDConfig, purpose int, payload []byte) *coredocumentpb.Signature { - return crypto.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) -} diff --git a/identity/identity_test.go b/identity/identity_test.go deleted file mode 100644 index 13388b8bd..000000000 --- a/identity/identity_test.go +++ /dev/null @@ -1,208 +0,0 @@ -// +build unit - -package identity - -import ( - "os" - "testing" - - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/stretchr/testify/assert" -) - -var ctx = map[string]interface{}{} -var cfg config.Configuration - -func TestMain(m *testing.M) { - ibootstappers := []bootstrap.TestBootstrapper{ - &config.Bootstrapper{}, - } - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") - cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - -func TestGetIdentityConfig_Success(t *testing.T) { - idConfig, err := GetIdentityConfig(cfg) - assert.Nil(t, err) - assert.NotNil(t, idConfig) - configId, err := cfg.GetIdentityID() - assert.Nil(t, err) - idBytes := idConfig.ID[:] - assert.Equal(t, idBytes, configId) - assert.Equal(t, 3, len(idConfig.Keys)) -} - -func TestGetIdentityConfig_Error(t *testing.T) { - //Wrong Hex - currentId := cfg.GetString("identityId") - cfg.Set("identityId", "ABCD") - idConfig, err := GetIdentityConfig(cfg) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "hex string without 0x prefix") - assert.Nil(t, idConfig) - cfg.Set("identityId", currentId) - - //Wrong length - currentId = cfg.GetString("identityId") - cfg.Set("identityId", "0x0101010101") - idConfig, err = GetIdentityConfig(cfg) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "invalid length byte slice provided for centID") - assert.Nil(t, idConfig) - cfg.Set("identityId", currentId) - - //Wrong public signing key path - currentKeyPath, _ := cfg.GetSigningKeyPair() - cfg.Set("keys.signing.publicKey", "./build/resources/signingKey.pub.pem") - idConfig, err = GetIdentityConfig(cfg) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "no such file or directory") - assert.Nil(t, idConfig) - cfg.Set("keys.signing.publicKey", currentKeyPath) - - //Wrong public ethauth key path - currentKeyPath, _ = cfg.GetEthAuthKeyPair() - cfg.Set("keys.ethauth.publicKey", "./build/resources/ethauth.pub.pem") - idConfig, err = GetIdentityConfig(cfg) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "no such file or directory") - assert.Nil(t, idConfig) - cfg.Set("keys.ethauth.publicKey", currentKeyPath) -} - -func TestToCentId(t *testing.T) { - tests := []struct { - name string - slice []byte - err string - }{ - { - "smallerSlice", - utils.RandomSlice(CentIDLength - 1), - "invalid length byte slice provided for centID", - }, - { - "largerSlice", - utils.RandomSlice(CentIDLength + 1), - "invalid length byte slice provided for centID", - }, - { - "nilSlice", - nil, - "empty bytes provided", - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - _, err := ToCentID(test.slice) - assert.Equal(t, test.err, err.Error()) - }) - } -} - -func TestNewCentIdEqual(t *testing.T) { - randomBytes := utils.RandomSlice(CentIDLength) - centrifugeIdA, err := ToCentID(randomBytes) - assert.Nil(t, err, "centrifugeId not initialized correctly ") - - centrifugeIdB, err := ToCentID(randomBytes) - assert.Nil(t, err, "centrifugeId not initialized correctly ") - assert.True(t, centrifugeIdA.Equal(centrifugeIdB), "centrifuge Id's should be the equal") - - randomBytes = utils.RandomSlice(CentIDLength) - centrifugeIdC, _ := ToCentID(randomBytes) - assert.False(t, centrifugeIdA.Equal(centrifugeIdC), "centrifuge Id's should not be equal") -} - -func TestCentIDFromString(t *testing.T) { - tests := []struct { - id string - result CentID - err error - }{ - { - id: "0x010203040506", - result: [CentIDLength]byte{1, 2, 3, 4, 5, 6}, - }, - - { - id: "0x01020304050607", - err: errors.New("invalid length byte slice provided for centID"), - }, - - { - id: "0xsome random", - err: errors.New("failed to decode id"), - }, - - { - id: "some random", - err: errors.New("hex string without 0x"), - }, - } - - for _, c := range tests { - id, err := CentIDFromString(c.id) - if c.err == nil { - assert.Nil(t, err, "must be nil") - assert.Equal(t, c.result, id, "id must match") - continue - } - - assert.Error(t, err, "must be a non nil error") - assert.Contains(t, err.Error(), c.err.Error()) - } -} - -func TestCentIDsFromStrings(t *testing.T) { - // fail due to error - ids := []string{"0x010203040506", "some id"} - cids, err := CentIDsFromStrings(ids) - assert.Error(t, err) - assert.Nil(t, cids) - - ids = []string{"0x010203040506", "0x020301020304"} - cids, err = CentIDsFromStrings(ids) - assert.Nil(t, err) - assert.NotNil(t, cids) - assert.Equal(t, cids, []CentID{{1, 2, 3, 4, 5, 6}, {2, 3, 1, 2, 3, 4}}) -} - -func TestValidateCentrifugeIDBytes(t *testing.T) { - c := RandomCentID() - assert.True(t, ValidateCentrifugeIDBytes(c[:], c) == nil) - - err := ValidateCentrifugeIDBytes(utils.RandomSlice(20), c) - if assert.Error(t, err) { - assert.Equal(t, "invalid length byte slice provided for centID", err.Error()) - } - - err = ValidateCentrifugeIDBytes(utils.RandomSlice(6), c) - if assert.Error(t, err) { - assert.Equal(t, "provided bytes doesn't match centID", err.Error()) - } -} - -func TestSign(t *testing.T) { - key1Pub := []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 := []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - c := RandomCentID() - msg := utils.RandomSlice(100) - sig := Sign(&IDConfig{c, map[int]IDKey{KeyPurposeSigning: {PrivateKey: key1, PublicKey: key1Pub}}}, KeyPurposeSigning, msg) - - err := crypto.VerifySignature(key1Pub, msg, sig.Signature) - assert.True(t, err == nil) -} diff --git a/identity/ideth/bootstrapper.go b/identity/ideth/bootstrapper.go new file mode 100644 index 000000000..9e33b1c2d --- /dev/null +++ b/identity/ideth/bootstrapper.go @@ -0,0 +1,66 @@ +package ideth + +import ( + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/config/configstore" + + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/ethereum/go-ethereum/common" +) + +// Bootstrapper implements bootstrap.Bootstrapper. +type Bootstrapper struct{} + +// Bootstrap initializes the factory contract +func (*Bootstrapper) Bootstrap(context map[string]interface{}) error { + // we have to allow loading from file in case this is coming from create config cmd where we don't add configs to db + cfg, err := configstore.RetrieveConfig(false, context) + if err != nil { + return err + } + + if _, ok := context[ethereum.BootstrappedEthereumClient]; !ok { + return errors.New("ethereum client hasn't been initialized") + } + client := context[ethereum.BootstrappedEthereumClient].(ethereum.Client) + + factoryAddress := getFactoryAddress(cfg) + + factoryContract, err := bindFactory(factoryAddress, client) + if err != nil { + return err + } + + txManager, ok := context[transactions.BootstrappedService].(transactions.Manager) + if !ok { + return errors.New("transactions repository not initialised") + } + + queueSrv, ok := context[bootstrap.BootstrappedQueueServer].(*queue.Server) + if !ok { + return errors.New("queue hasn't been initialized") + } + + factory := NewFactory(factoryContract, client, txManager, queueSrv, factoryAddress) + context[identity.BootstrappedDIDFactory] = factory + + service := NewService(client, txManager, queueSrv) + context[identity.BootstrappedDIDService] = service + + return nil +} + +func bindFactory(factoryAddress common.Address, client ethereum.Client) (*FactoryContract, error) { + return NewFactoryContract(factoryAddress, client.GetEthClient()) +} + +func getFactoryAddress(cfg config.Configuration) common.Address { + return cfg.GetContractAddress(config.IdentityFactory) +} diff --git a/identity/did/bootstrapper_test.go b/identity/ideth/bootstrapper_test.go similarity index 94% rename from identity/did/bootstrapper_test.go rename to identity/ideth/bootstrapper_test.go index 56a374dfe..0801c7d4c 100644 --- a/identity/did/bootstrapper_test.go +++ b/identity/ideth/bootstrapper_test.go @@ -1,6 +1,6 @@ // +build unit -package did +package ideth import ( "testing" diff --git a/identity/did/execute_integration_test.go b/identity/ideth/execute_integration_test.go similarity index 89% rename from identity/did/execute_integration_test.go rename to identity/ideth/execute_integration_test.go index 37b830ab7..f19b8f807 100644 --- a/identity/did/execute_integration_test.go +++ b/identity/ideth/execute_integration_test.go @@ -13,12 +13,16 @@ correct implementation. */ -package did +package ideth import ( "context" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/ethereum" @@ -35,11 +39,15 @@ func resetDefaultCentID() { cfg.Set("identityId", "0x010101010101") } +func getAnchorAddress(cfg config.Configuration) common.Address { + return cfg.GetContractAddress(config.AnchorRepo) +} + func TestExecute_successful(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() - anchorAddress := getAnchorAddress() + anchorAddress := getAnchorAddress(cfg) // init params testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) @@ -59,7 +67,7 @@ func TestExecute_fail_falseMethodName(t *testing.T) { aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() - anchorAddress := getAnchorAddress() + anchorAddress := getAnchorAddress(cfg) testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) @@ -77,7 +85,7 @@ func TestExecute_fail_MissingParam(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() - anchorAddress := getAnchorAddress() + anchorAddress := getAnchorAddress(cfg) testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) @@ -89,7 +97,7 @@ func TestExecute_fail_MissingParam(t *testing.T) { } func checkAnchor(t *testing.T, anchorId anchors.AnchorID, expectedRootHash []byte) { - anchorAddress := getAnchorAddress() + anchorAddress := getAnchorAddress(cfg) client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) // check if anchor has been added @@ -103,7 +111,7 @@ func checkAnchor(t *testing.T, anchorId anchors.AnchorID, expectedRootHash []byt // Checks the standard behaviour of the anchor contract func TestAnchorWithoutExecute_successful(t *testing.T) { client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) - anchorAddress := getAnchorAddress() + anchorAddress := getAnchorAddress(cfg) anchorContract := bindAnchorContract(t, anchorAddress) testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) @@ -131,9 +139,8 @@ func commitAnchorWithoutExecute(t *testing.T, anchorContract *anchors.AnchorCont queue := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) - // TODO: did can be passed instead of randomCentID after CentID is DID - _, done, err := txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX add execute", - func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + _, done, err := txManager.ExecuteWithinTX(context.Background(), testingidentity.GenerateRandomDID(), transactions.NilTxID(), "Check TX add execute", + func(accountID id.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := client.SubmitTransactionWithRetries(anchorContract.Commit, opts, anchorId.BigInt(), rootHash, proofs) if err != nil { errOut <- err diff --git a/identity/did/factory.go b/identity/ideth/factory.go similarity index 71% rename from identity/did/factory.go rename to identity/ideth/factory.go index d40146fad..8d5f710e3 100644 --- a/identity/did/factory.go +++ b/identity/ideth/factory.go @@ -1,4 +1,4 @@ -package did +package ideth import ( "context" @@ -19,12 +19,8 @@ import ( var log = logging.Logger("identity") -// Factory is the interface for factory related interactions -type Factory interface { - CreateIdentity(ctx context.Context) (id *DID, err error) -} - type factory struct { + factoryAddress common.Address factoryContract *FactoryContract client ethereum.Client txManager transactions.Manager @@ -32,14 +28,13 @@ type factory struct { } // NewFactory returns a new identity factory service -func NewFactory(factoryContract *FactoryContract, client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Factory { - - return &factory{factoryContract: factoryContract, client: client, txManager: txManager, queue: queue} +func NewFactory(factoryContract *FactoryContract, client ethereum.Client, txManager transactions.Manager, queue *queue.Server, factoryAddress common.Address) id.Factory { + return &factory{factoryAddress: factoryAddress, factoryContract: factoryContract, client: client, txManager: txManager, queue: queue} } func (s *factory) getNonceAt(ctx context.Context, address common.Address) (uint64, error) { // TODO: add blockNumber of the transaction which created the contract - return s.client.GetEthClient().NonceAt(ctx, getFactoryAddress(), nil) + return s.client.GetEthClient().NonceAt(ctx, s.factoryAddress, nil) } // CalculateCreatedAddress calculates the Ethereum address based on address and nonce @@ -49,8 +44,8 @@ func CalculateCreatedAddress(address common.Address, nonce uint64) common.Addres return crypto.CreateAddress(address, nonce) } -func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { +func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := s.client.SubmitTransactionWithRetries(s.factoryContract.CreateIdentity, opts) if err != nil { errOut <- err @@ -77,14 +72,13 @@ func (s *factory) createIdentityTX(opts *bind.TransactOpts) func(accountID id.Ce } -func (s *factory) calculateIdentityAddress(ctx context.Context) (*common.Address, error) { - factoryAddress := getFactoryAddress() - nonce, err := s.getNonceAt(ctx, factoryAddress) +func (s *factory) CalculateIdentityAddress(ctx context.Context) (*common.Address, error) { + nonce, err := s.getNonceAt(ctx, s.factoryAddress) if err != nil { return nil, err } - identityAddress := CalculateCreatedAddress(factoryAddress, nonce) + identityAddress := CalculateCreatedAddress(s.factoryAddress, nonce) log.Infof("Calculated Address of the identity contract: 0x%x\n", identityAddress) return &identityAddress, nil } @@ -95,16 +89,15 @@ func isIdentityContract(identityAddress common.Address, client ethereum.Client) return err } - deployedContractByte := common.Bytes2Hex(contractCode) - identityContractByte := getIdentityByteCode()[2:] // remove 0x prefix - if deployedContractByte != identityContractByte { - return errors.New("deployed identity contract bytecode not correct") + if len(contractCode) == 0 { + return errors.New("bytecode for deployed identity contract %s not correct", identityAddress.String()) } + return nil } -func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { +func (s *factory) CreateIdentity(ctx context.Context) (did *id.DID, err error) { tc, err := contextutil.Account(ctx) if err != nil { return nil, err @@ -116,13 +109,14 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { return nil, err } - identityAddress, err := s.calculateIdentityAddress(ctx) + identityAddress, err := s.CalculateIdentityAddress(ctx) if err != nil { return nil, err } - // TODO refactor randomCentID - txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for create identity status", s.createIdentityTX(opts)) + createdDID := id.NewDID(*identityAddress) + + txID, done, err := s.txManager.ExecuteWithinTX(context.Background(), createdDID, transactions.NilTxID(), "Check TX for create identity status", s.createIdentityTX(opts)) if err != nil { return nil, err } @@ -139,12 +133,11 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *DID, err error) { return nil, err } - createdDID := NewDID(*identityAddress) return &createdDID, nil } // CreateIdentity creates an identity contract -func CreateIdentity(ctx map[string]interface{}, cfg config.Configuration) (*DID, error) { +func CreateIdentity(ctx map[string]interface{}, cfg config.Configuration) (*id.DID, error) { tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) if err != nil { return nil, err @@ -155,7 +148,7 @@ func CreateIdentity(ctx map[string]interface{}, cfg config.Configuration) (*DID, return nil, err } - identityFactory := ctx[BootstrappedDIDFactory].(Factory) + identityFactory := ctx[id.BootstrappedDIDFactory].(id.Factory) did, err := identityFactory.CreateIdentity(tctx) if err != nil { diff --git a/identity/did/factory_contract.go b/identity/ideth/factory_contract.go similarity index 99% rename from identity/did/factory_contract.go rename to identity/ideth/factory_contract.go index 768dd282a..ed0a0f042 100644 --- a/identity/did/factory_contract.go +++ b/identity/ideth/factory_contract.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package did +package ideth import ( "strings" diff --git a/identity/did/factory_integration_test.go b/identity/ideth/factory_integration_test.go similarity index 87% rename from identity/did/factory_integration_test.go rename to identity/ideth/factory_integration_test.go index 06367ccbc..6972eefba 100644 --- a/identity/did/factory_integration_test.go +++ b/identity/ideth/factory_integration_test.go @@ -1,6 +1,6 @@ // +build integration -package did +package ideth import ( "context" @@ -9,12 +9,15 @@ import ( "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/identity" + + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity/ethid" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -25,6 +28,9 @@ var cfg config.Configuration var ctx = map[string]interface{}{} func TestMain(m *testing.M) { + + ctx = testingutils.BuildIntegrationTestingContext() + var bootstappers = []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -32,7 +38,7 @@ func TestMain(m *testing.M) { txv1.Bootstrapper{}, &queue.Bootstrapper{}, ethereum.Bootstrapper{}, - ðid.Bootstrapper{}, + &Bootstrapper{}, &configstore.Bootstrapper{}, &Bootstrapper{}, &queue.Starter{}, @@ -46,7 +52,8 @@ func TestMain(m *testing.M) { } func TestCreateIdentity_successful(t *testing.T) { - factory := ctx[BootstrappedDIDFactory].(Factory) + + factory := ctx[identity.BootstrappedDIDFactory].(identity.Factory) accountCtx := testingconfig.CreateAccountContext(t, cfg) diff --git a/identity/did/identity_contract.go b/identity/ideth/identity_contract.go similarity index 99% rename from identity/did/identity_contract.go rename to identity/ideth/identity_contract.go index 624d4b9d6..3280ff467 100644 --- a/identity/did/identity_contract.go +++ b/identity/ideth/identity_contract.go @@ -1,7 +1,7 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package did +package ideth import ( "math/big" diff --git a/identity/did/service.go b/identity/ideth/service.go similarity index 57% rename from identity/did/service.go rename to identity/ideth/service.go index 29858f4c8..fdbac96ea 100644 --- a/identity/did/service.go +++ b/identity/ideth/service.go @@ -1,4 +1,4 @@ -package did +package ideth import ( "context" @@ -6,8 +6,10 @@ import ( "math/big" "strings" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" @@ -24,64 +26,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// DID stores the identity address of the user -type DID common.Address - -// ToAddress returns the DID as common.Address -func (d DID) ToAddress() common.Address { - return common.Address(d) -} - -// NewDID returns a DID based on a common.Address -func NewDID(address common.Address) DID { - return DID(address) -} - -// NewDIDFromString returns a DID based on a hex string -func NewDIDFromString(address string) DID { - return DID(common.HexToAddress(address)) -} - -// Service interface contains the methods to interact with the identity contract -type Service interface { - // AddKey adds a key to identity contract - AddKey(ctx context.Context, key Key) error - - // GetKey return a key from the identity contract - GetKey(did DID, key [32]byte) (*KeyResponse, error) - - // RawExecute calls the execute method on the identity contract - RawExecute(ctx context.Context, to common.Address, data []byte) error - - // Execute creates the abi encoding an calls the execute method on the identity contract - Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error - - // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys - IsSignedWithPurpose(did DID, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) - - // AddMultiPurposeKey adds a key with multiple purposes - AddMultiPurposeKey(context context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error - - // RevokeKey revokes an existing key in the smart contract - RevokeKey(ctx context.Context, key [32]byte) error - - // GetClientP2PURL returns the p2p url associated with the did - GetClientP2PURL(did DID) (string, error) - - //Exists checks if an identity contract exists - Exists(ctx context.Context, did DID) error - - // ValidateKey checks if a given key is valid for the given centrifugeID. - ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error - - // GetClientsP2PURLs returns p2p urls associated with each centIDs - // will error out at first failure - GetClientsP2PURLs(did []*DID) ([]string, error) - - // GetKeysByPurpose returns keys grouped by purpose from the identity contract. - GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) -} - type contract interface { // Ethereum Calls @@ -111,7 +55,7 @@ type service struct { queue *queue.Server } -func (i service) prepareTransaction(ctx context.Context, did DID) (contract, *bind.TransactOpts, error) { +func (i service) prepareTransaction(ctx context.Context, did id.DID) (contract, *bind.TransactOpts, error) { tc, err := contextutil.Account(ctx) if err != nil { return nil, nil, err @@ -132,7 +76,7 @@ func (i service) prepareTransaction(ctx context.Context, did DID) (contract, *bi } -func (i service) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelFunc, error) { +func (i service) prepareCall(did id.DID) (contract, *bind.CallOpts, context.CancelFunc, error) { opts, cancelFunc := i.client.GetGethCallOpts(false) contract, err := i.bindContract(did) @@ -144,7 +88,7 @@ func (i service) prepareCall(did DID) (contract, *bind.CallOpts, context.CancelF } -func (i service) bindContract(did DID) (contract, error) { +func (i service) bindContract(did id.DID) (contract, error) { contract, err := NewIdentityContract(did.ToAddress(), i.client.GetEthClient()) if err != nil { return nil, errors.New("Could not bind identity contract: %v", err) @@ -155,7 +99,7 @@ func (i service) bindContract(did DID) (contract, error) { } // NewService creates a instance of the identity service -func NewService(client ethereum.Client, txManager transactions.Manager, queue *queue.Server) Service { +func NewService(client ethereum.Client, txManager transactions.Manager, queue *queue.Server) id.ServiceDID { return service{client: client, txManager: txManager, queue: queue} } @@ -164,36 +108,20 @@ func logTxHash(tx *types.Transaction) { log.Infof("Transfer pending: 0x%x\n", tx.Hash()) } -func (i service) getDID(ctx context.Context) (did DID, err error) { - tc, err := contextutil.Account(ctx) - if err != nil { - return did, err - } - - addressByte, err := tc.GetIdentityID() - if err != nil { - return did, err - } - did = NewDID(common.BytesToAddress(addressByte)) - return did, nil - -} - // AddKey adds a key to identity contract -func (i service) AddKey(ctx context.Context, key Key) error { - did, err := i.getDID(ctx) +func (i service) AddKey(ctx context.Context, key id.KeyDID) error { + DID, err := NewDIDFromContext(ctx) if err != nil { return err } - contract, opts, err := i.prepareTransaction(ctx, did) + contract, opts, err := i.prepareTransaction(ctx, DID) if err != nil { return err } - // TODO: did can be passed instead of randomCentID after CentID is DID - log.Info("Add key to identity contract %s", did.ToAddress().String()) - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for add key", + log.Info("Add key to identity contract %s", DID.ToAddress().String()) + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), DID, transactions.NilTxID(), "Check TX for add key", i.ethereumTX(opts, contract.AddKey, key.GetKey(), key.GetPurpose(), key.GetType())) if err != nil { return err @@ -211,18 +139,17 @@ func (i service) AddKey(ctx context.Context, key Key) error { // AddMultiPurposeKey adds a key with multiple purposes func (i service) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error { - did, err := i.getDID(ctx) + DID, err := NewDIDFromContext(ctx) if err != nil { return err } - contract, opts, err := i.prepareTransaction(ctx, did) + contract, opts, err := i.prepareTransaction(ctx, DID) if err != nil { return err } - // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for add multi purpose key", + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), DID, transactions.NilTxID(), "Check TX for add multi purpose key", i.ethereumTX(opts, contract.AddMultiPurposeKey, key, purposes, keyType)) if err != nil { return err @@ -239,18 +166,17 @@ func (i service) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes // RevokeKey revokes an existing key in the smart contract func (i service) RevokeKey(ctx context.Context, key [32]byte) error { - did, err := i.getDID(ctx) + DID, err := NewDIDFromContext(ctx) if err != nil { return err } - contract, opts, err := i.prepareTransaction(ctx, did) + contract, opts, err := i.prepareTransaction(ctx, DID) if err != nil { return err } - // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for revoke key", + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), DID, transactions.NilTxID(), "Check TX for revoke key", i.ethereumTX(opts, contract.RevokeKey, key)) if err != nil { return err @@ -266,8 +192,8 @@ func (i service) RevokeKey(ctx context.Context, key [32]byte) error { } // ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result -func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID id.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { +func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, params ...interface{}) func(accountID id.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID id.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { ethTX, err := i.client.SubmitTransactionWithRetries(contractMethod, opts, params...) if err != nil { errOut <- err @@ -291,7 +217,7 @@ func (i service) ethereumTX(opts *bind.TransactOpts, contractMethod interface{}, } // GetKey return a key from the identity contract -func (i service) GetKey(did DID, key [32]byte) (*KeyResponse, error) { +func (i service) GetKey(did id.DID, key [32]byte) (*id.KeyResponse, error) { contract, opts, _, err := i.prepareCall(did) if err != nil { return nil, err @@ -303,28 +229,28 @@ func (i service) GetKey(did DID, key [32]byte) (*KeyResponse, error) { return nil, errors.New("Could not call identity contract: %v", err) } - return &KeyResponse{result.Key, result.Purposes, result.RevokedAt}, nil + return &id.KeyResponse{result.Key, result.Purposes, result.RevokedAt}, nil } // IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys -func (i service) IsSignedWithPurpose(did DID, message [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { +func (i service) IsSignedWithPurpose(did id.DID, message [32]byte, signature []byte, purpose *big.Int) (bool, error) { contract, opts, _, err := i.prepareCall(did) if err != nil { return false, err } - return contract.IsSignedWithPurpose(opts, message, _signature, _purpose) + return contract.IsSignedWithPurpose(opts, message, signature, purpose) } // RawExecute calls the execute method on the identity contract func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) error { - did, err := i.getDID(ctx) + DID, err := NewDIDFromContext(ctx) if err != nil { return err } - contract, opts, err := i.prepareTransaction(ctx, did) + contract, opts, err := i.prepareTransaction(ctx, DID) if err != nil { return err } @@ -332,8 +258,7 @@ func (i service) RawExecute(ctx context.Context, to common.Address, data []byte) // default: no ether should be send value := big.NewInt(0) - // TODO: did can be passed instead of randomCentID after CentID is DID - txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), id.RandomCentID(), transactions.NilTxID(), "Check TX for execute", i.ethereumTX(opts, contract.Execute, to, value, data)) + txID, done, err := i.txManager.ExecuteWithinTX(context.Background(), DID, transactions.NilTxID(), "Check TX for execute", i.ethereumTX(opts, contract.Execute, to, value, data)) if err != nil { return err } @@ -363,7 +288,7 @@ func (i service) Execute(ctx context.Context, to common.Address, contractAbi, me return i.RawExecute(ctx, to, data) } -func (i service) GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) { +func (i service) GetKeysByPurpose(did id.DID, purpose *big.Int) ([][32]byte, error) { contract, opts, _, err := i.prepareCall(did) if err != nil { return nil, err @@ -373,44 +298,48 @@ func (i service) GetKeysByPurpose(did DID, purpose *big.Int) ([][32]byte, error) } -// GetClientP2PURL returns the p2p url associated with the did -func (i service) GetClientP2PURL(did DID) (string, error) { - contract, opts, _, err := i.prepareCall(did) +// CurrentP2PKey returns the latest P2P key +func (i service) CurrentP2PKey(did id.DID) (ret string, err error) { + keys, err := i.GetKeysByPurpose(did, big.NewInt(id.KeyPurposeP2P)) if err != nil { - return "", err + return ret, err } - keys, err := contract.GetKeysByPurpose(opts, big.NewInt(id.KeyPurposeP2P)) + lastKey := keys[len(keys)-1] + key, err := i.GetKey(did, lastKey) if err != nil { return "", err } - lastIdx := len(keys) - 1 - key, err := contract.GetKey(opts, keys[lastIdx]) + if key.RevokedAt.Cmp(big.NewInt(0)) != 0 { + return "", errors.New("current p2p key has been revoked") + } + p2pID, err := ed25519.PublicKeyToP2PKey(key.Key) if err != nil { - return "", err + return ret, err } - if key.RevokedAt.Cmp(big.NewInt(0)) != 0 { - return "", errors.New("p2p key has been revoked") - } + return p2pID.Pretty(), nil +} - p2pID, err := ed25519.PublicKeyToP2PKey(key.Key) +// GetClientP2PURL returns the p2p url associated with the did +func (i service) GetClientP2PURL(did id.DID) (string, error) { + p2pID, err := i.CurrentP2PKey(did) if err != nil { return "", err } - return fmt.Sprintf("/ipfs/%s", p2pID.Pretty()), nil + return fmt.Sprintf("/ipfs/%s", p2pID), nil } //Exists checks if an identity contract exists -func (i service) Exists(ctx context.Context, did DID) error { +func (i service) Exists(ctx context.Context, did id.DID) error { return isIdentityContract(did.ToAddress(), i.client) } // ValidateKey checks if a given key is valid for the given centrifugeID. -func (i service) ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error { +func (i service) ValidateKey(ctx context.Context, did id.DID, key []byte, purpose int64) error { contract, opts, _, err := i.prepareCall(did) if err != nil { return err @@ -437,7 +366,7 @@ func (i service) ValidateKey(ctx context.Context, did DID, key []byte, purpose i // GetClientsP2PURLs returns p2p urls associated with each centIDs // will error out at first failure -func (i service) GetClientsP2PURLs(dids []*DID) ([]string, error) { +func (i service) GetClientsP2PURLs(dids []*id.DID) ([]string, error) { urls := make([]string, len(dids)) for idx, did := range dids { @@ -452,13 +381,13 @@ func (i service) GetClientsP2PURLs(dids []*DID) ([]string, error) { return urls, nil } -func getKeyPairsFromConfig(config config.Configuration) (map[int]Key, error) { - keys := map[int]Key{} +func getKeyPairsFromAccount(acc config.Account) (map[int]id.KeyDID, error) { + keys := map[int]id.KeyDID{} var pk []byte // ed25519 keys // KeyPurposeP2P - pk, _, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) + pk, _, err := ed25519.GetSigningKeyPair(acc.GetP2PKeyPair()) if err != nil { return nil, err } @@ -466,10 +395,10 @@ func getKeyPairsFromConfig(config config.Configuration) (map[int]Key, error) { if err != nil { return nil, err } - keys[id.KeyPurposeP2P] = NewKey(pk32, big.NewInt(id.KeyPurposeP2P), big.NewInt(id.KeyTypeECDSA)) + keys[id.KeyPurposeP2P] = id.NewKey(pk32, big.NewInt(id.KeyPurposeP2P), big.NewInt(id.KeyTypeECDSA)) // KeyPurposeSigning - pk, _, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + pk, _, err = ed25519.GetSigningKeyPair(acc.GetSigningKeyPair()) if err != nil { return nil, err } @@ -477,52 +406,82 @@ func getKeyPairsFromConfig(config config.Configuration) (map[int]Key, error) { if err != nil { return nil, err } - keys[id.KeyPurposeSigning] = NewKey(pk32, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) + keys[id.KeyPurposeSigning] = id.NewKey(pk32, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) // secp256k1 keys // KeyPurposeEthMsgAuth - pk, _, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) + pk, _, err = secp256k1.GetEthAuthKey(acc.GetEthAuthKeyPair()) if err != nil { return nil, err } address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - keys[id.KeyPurposeEthMsgAuth] = NewKey(address32Bytes, big.NewInt(id.KeyPurposeEthMsgAuth), big.NewInt(id.KeyTypeECDSA)) + keys[id.KeyPurposeEthMsgAuth] = id.NewKey(address32Bytes, big.NewInt(id.KeyPurposeEthMsgAuth), big.NewInt(id.KeyTypeECDSA)) return keys, nil } -// AddKeysFromConfig adds the keys from the config to the smart contracts -func AddKeysFromConfig(ctx map[string]interface{}, cfg config.Configuration) error { - idSrv := ctx[BootstrappedDIDService].(Service) - - tc, err := configstore.NewAccount(cfg.GetEthereumDefaultAccountName(), cfg) +// AddKeysForAccount adds the keys from the config to the smart contracts +func (i service) AddKeysForAccount(acc config.Account) error { + tctx, err := contextutil.New(context.Background(), acc) if err != nil { return err } - tctx, err := contextutil.New(context.Background(), tc) + keys, err := getKeyPairsFromAccount(acc) if err != nil { return err } - - keys, err := getKeyPairsFromConfig(cfg) + err = i.AddKey(tctx, keys[id.KeyPurposeP2P]) if err != nil { return err } - err = idSrv.AddKey(tctx, keys[id.KeyPurposeP2P]) + + err = i.AddKey(tctx, keys[id.KeyPurposeSigning]) if err != nil { return err } - err = idSrv.AddKey(tctx, keys[id.KeyPurposeSigning]) + err = i.AddKey(tctx, keys[id.KeyPurposeEthMsgAuth]) if err != nil { return err } + return nil +} - err = idSrv.AddKey(tctx, keys[id.KeyPurposeEthMsgAuth]) +// ValidateSignature validates a signature on a message based on identity data +func (i service) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { + centID := id.NewDIDFromBytes(signature.EntityId) + + err := i.ValidateKey(context.Background(), centID, signature.PublicKey, id.KeyPurposeSigning) if err != nil { return err } + + return crypto.VerifySignature(signature.PublicKey, message, signature.Signature) +} + +// ValidateCentrifugeIDBytes validates a centrifuge ID given as bytes +func ValidateCentrifugeIDBytes(givenDID []byte, DID id.DID) error { + calcCentID := id.NewDIDFromBytes(givenDID) + if !DID.Equal(calcCentID) { + return errors.New("provided bytes doesn't match centID") + } + return nil } + +// NewDIDFromContext returns DID from context.Account +// TODO remove this function to identity/did.go as soon as IDConfig is removed otherwise there is a cyclic dep +func NewDIDFromContext(ctx context.Context) (id.DID, error) { + tc, err := contextutil.Account(ctx) + if err != nil { + return id.DID{}, err + } + + addressByte, err := tc.GetIdentityID() + if err != nil { + return id.DID{}, err + } + return id.NewDID(common.BytesToAddress(addressByte)), nil +} diff --git a/identity/did/service_integration_test.go b/identity/ideth/service_integration_test.go similarity index 87% rename from identity/did/service_integration_test.go rename to identity/ideth/service_integration_test.go index e5947f73e..9c8330d69 100644 --- a/identity/did/service_integration_test.go +++ b/identity/ideth/service_integration_test.go @@ -1,6 +1,6 @@ // +build integration -package did +package ideth import ( "context" @@ -8,6 +8,8 @@ import ( "math/big" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/identity" @@ -15,10 +17,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/centrifuge/go-centrifuge/bootstrap" + id "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" @@ -26,18 +28,18 @@ import ( "github.com/stretchr/testify/assert" ) -func getTestKey() Key { - return &key{Key: utils.RandomByte32(), Purpose: utils.ByteSliceToBigInt([]byte{123}), Type: utils.ByteSliceToBigInt([]byte{123})} +func getTestKey() id.KeyDID { + return id.NewKey(utils.RandomByte32(), utils.ByteSliceToBigInt([]byte{123}), utils.ByteSliceToBigInt([]byte{123})) } -func initIdentity() Service { +func initIdentity() id.ServiceDID { client := ctx[ethereum.BootstrappedEthereumClient].(ethereum.Client) txManager := ctx[transactions.BootstrappedService].(transactions.Manager) queue := ctx[bootstrap.BootstrappedQueueServer].(*queue.Server) return NewService(client, txManager, queue) } -func getTestDIDContext(t *testing.T, did DID) context.Context { +func getTestDIDContext(t *testing.T, did id.DID) context.Context { cfg.Set("identityId", did.ToAddress().String()) cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") @@ -47,8 +49,8 @@ func getTestDIDContext(t *testing.T, did DID) context.Context { } -func deployIdentityContract(t *testing.T) *DID { - factory := ctx[BootstrappedDIDFactory].(Factory) +func deployIdentityContract(t *testing.T) *id.DID { + factory := ctx[identity.BootstrappedDIDFactory].(identity.Factory) accountCtx := testingconfig.CreateAccountContext(t, cfg) did, err := factory.CreateIdentity(accountCtx) assert.Nil(t, err, "create identity should be successful") @@ -63,7 +65,7 @@ func deployIdentityContract(t *testing.T) *DID { } -func addKey(aCtx context.Context, t *testing.T, did DID, idSrv Service, testKey Key) { +func addKey(aCtx context.Context, t *testing.T, did id.DID, idSrv id.ServiceDID, testKey id.KeyDID) { err := idSrv.AddKey(aCtx, testKey) assert.Nil(t, err, "add key should be successful") @@ -87,7 +89,7 @@ func TestServiceAddKey_successful(t *testing.T) { func TestServiceAddKey_fail(t *testing.T) { testKey := getTestKey() - did := NewDIDFromString("0x123") + did := testingidentity.GenerateRandomDID() aCtx := getTestDIDContext(t, did) idSrv := initIdentity() @@ -115,7 +117,8 @@ func TestService_IsSignedWithPurpose(t *testing.T) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() - key := &key{Key: address32Bytes, Purpose: purpose, Type: utils.ByteSliceToBigInt([]byte{123})} + key := id.NewKey(address32Bytes, purpose, utils.ByteSliceToBigInt([]byte{123})) + err = idSrv.AddKey(aCtx, key) assert.Nil(t, err, "add key should be successful") @@ -198,7 +201,7 @@ func TestExists(t *testing.T) { err := idSrv.Exists(aCtx, *did) assert.Nil(t, err, "identity contract should exist") - err = idSrv.Exists(aCtx, NewDIDFromString("0x123")) + err = idSrv.Exists(aCtx, testingidentity.GenerateRandomDID()) assert.Error(t, err, "identity contract should not exist") resetDefaultCentID() @@ -227,14 +230,14 @@ func TestValidateKey(t *testing.T) { } -func addP2PKeyTestGetClientP2PURL(t *testing.T) (*DID, string) { +func addP2PKeyTestGetClientP2PURL(t *testing.T) (*id.DID, string) { did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() p2pKey := utils.RandomByte32() - testKey := &key{Key: p2pKey, Purpose: utils.ByteSliceToBigInt([]byte{identity.KeyPurposeP2P}), Type: utils.ByteSliceToBigInt([]byte{123})} + testKey := id.NewKey(p2pKey, utils.ByteSliceToBigInt([]byte{identity.KeyPurposeP2P}), utils.ByteSliceToBigInt([]byte{123})) addKey(aCtx, t, *did, idSrv, testKey) url, err := idSrv.GetClientP2PURL(*did) @@ -261,7 +264,7 @@ func TestGetClientP2PURLs(t *testing.T) { didB, urlB := addP2PKeyTestGetClientP2PURL(t) idSrv := initIdentity() - urls, err := idSrv.GetClientsP2PURLs([]*DID{didA, didB}) + urls, err := idSrv.GetClientsP2PURLs([]*id.DID{didA, didB}) assert.Nil(t, err) assert.Equal(t, urlA, urls[0], "p2p url should be the same") diff --git a/identity/did/test_bootstrapper.go b/identity/ideth/test_bootstrapper.go similarity index 93% rename from identity/did/test_bootstrapper.go rename to identity/ideth/test_bootstrapper.go index a88ae38c3..b18b6b7a5 100644 --- a/identity/did/test_bootstrapper.go +++ b/identity/ideth/test_bootstrapper.go @@ -1,6 +1,6 @@ // +build integration unit -package did +package ideth func (b *Bootstrapper) TestBootstrap(context map[string]interface{}) error { return b.Bootstrap(context) diff --git a/nft/bootstrapper.go b/nft/bootstrapper.go index b9914bb5b..c50685066 100644 --- a/nft/bootstrapper.go +++ b/nft/bootstrapper.go @@ -38,7 +38,7 @@ func (*Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("document service not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) if !ok { return errors.New("identity service not initialised") } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 7d7dcb274..1b1113e0d 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -35,7 +35,7 @@ type Config interface { // ethereumPaymentObligation handles all interactions related to minting of NFTs for payment obligations on Ethereum type ethereumPaymentObligation struct { cfg Config - identityService identity.Service + identityService identity.ServiceDID ethClient ethereum.Client queue queue.TaskQueuer docSrv documents.Service @@ -47,7 +47,7 @@ type ethereumPaymentObligation struct { // newEthereumPaymentObligation creates ethereumPaymentObligation given the parameters func newEthereumPaymentObligation( cfg Config, - identityService identity.Service, + identityService identity.ServiceDID, ethClient ethereum.Client, queue queue.TaskQueuer, docSrv documents.Service, @@ -66,7 +66,7 @@ func newEthereumPaymentObligation( } } -func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, tokenID TokenID, cid identity.CentID, req MintNFTRequest) (mreq MintRequest, err error) { +func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, tokenID TokenID, cid identity.DID, req MintNFTRequest) (mreq MintRequest, err error) { docProofs, err := s.docSrv.CreateProofs(ctx, req.DocumentID, req.ProofFields) if err != nil { return mreq, err @@ -130,10 +130,7 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, req MintNFTRequ return nil, nil, err } - cid, err := identity.ToCentID(cidBytes) - if err != nil { - return nil, nil, err - } + cid := identity.NewDIDFromBytes(cidBytes) if !req.GrantNFTReadAccess && req.SubmitNFTReadAccessProof { return nil, nil, errors.New("enable grant_nft_access to generate Read Access Proof") @@ -169,8 +166,8 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, req MintNFTRequ }, done, nil } -func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, req MintNFTRequest) func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { - return func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { +func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, model documents.Model, req MintNFTRequest) func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { + return func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, errOut chan<- error) { tc, err := contextutil.Account(ctx) if err != nil { errOut <- err diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 03000130b..3780c4e42 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,13 +7,14 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/nft" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" @@ -145,14 +146,14 @@ func (m *MockPaymentObligation) Mint(opts *bind.TransactOpts, _to common.Address func TestPaymentObligationService(t *testing.T) { tests := []struct { name string - mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) + mocker func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIdentityService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) request *nftpb.NFTMintRequest err error result string }{ { "happypath", - func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIDService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) { + func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIdentityService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) { coreDocModel := documents.NewCoreDocModel() coreDoc := coreDocModel.Document coreDoc.DocumentRoot = utils.RandomSlice(32) @@ -161,7 +162,7 @@ func TestPaymentObligationService(t *testing.T) { docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocumentModel: coreDocModel}, nil) docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) paymentObligationMock := &MockPaymentObligation{} - idServiceMock := testingcommons.MockIDService{} + idServiceMock := testingcommons.MockIdentityService{} ethClientMock := testingcommons.MockEthClient{} ethClientMock.On("GetTxOpts", "ethacc").Return(&bind.TransactOpts{}, nil) ethClientMock.On("SubmitTransactionWithRetries", @@ -171,7 +172,7 @@ func TestPaymentObligationService(t *testing.T) { ).Return(&types.Transaction{}, nil) configMock := testingconfig.MockConfig{} configMock.On("GetEthereumDefaultAccountName").Return("ethacc") - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() configMock.On("GetIdentityID").Return(cid[:], nil) configMock.On("GetEthereumAccount").Return(&config.AccountConfig{}, nil) configMock.On("GetEthereumContextWaitTimeout").Return(time.Second) diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 8f8ce8f8e..d2ac3e6ca 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" @@ -29,7 +31,8 @@ import ( var registry *documents.ServiceRegistry var cfg config.Configuration -var idService identity.Service +var idService identity.ServiceDID +var idFactory identity.Factory var payOb nft.PaymentObligation var txManager transactions.Manager var tokenRegistry documents.TokenRegistry @@ -38,7 +41,8 @@ func TestMain(m *testing.M) { log.Debug("Test PreSetup for NFT") ctx := cc.TestFunctionalEthereumBootstrap() registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - idService = ctx[identity.BootstrappedIDService].(identity.Service) + idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txManager = ctx[transactions.BootstrappedService].(transactions.Manager) @@ -48,10 +52,18 @@ func TestMain(m *testing.M) { os.Exit(result) } -func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address, string, documents.Service, identity.CentID) { +func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address, string, documents.Service, identity.DID) { // create identity log.Debug("Create Identity for Testing") - cid := testingidentity.CreateIdentityWithKeys(cfg, idService) + didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) + assert.NoError(t, err) + did := identity.NewDID(*didAddr) + tc, err := configstore.TempAccount("", cfg) + assert.NoError(t, err) + tcr := tc.(*configstore.Account) + tcr.IdentityID = did[:] + cid, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService, idFactory) + assert.NoError(t, err) // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) @@ -85,7 +97,7 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address return ctx, id, registry, depositAddr, invSrv, cid } -func mintNFT(t *testing.T, ctx context.Context, req nft.MintNFTRequest, cid identity.CentID, registry common.Address) nft.TokenID { +func mintNFT(t *testing.T, ctx context.Context, req nft.MintNFTRequest, cid identity.DID, registry common.Address) nft.TokenID { resp, done, err := payOb.MintNFT(ctx, req) assert.Nil(t, err, "should not error out when minting an invoice") assert.NotNil(t, resp.TokenID, "token id should be present") diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index e119a5fea..a84859a9c 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -30,7 +30,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("document service not initialised") } - idService, ok := ctx[identity.BootstrappedIDService].(identity.Service) + idService, ok := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) if !ok { return errors.New("identity service not initialised") } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 0c1541d07..6aa094a86 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -29,9 +29,9 @@ func TestBootstrapper_Bootstrap(t *testing.T) { m[bootstrap.BootstrappedConfig] = new(testingconfig.MockConfig) m[config.BootstrappedConfigStorage] = cs cs.On("GetConfig").Return(&configstore.NodeConfig{}, nil) - ids := new(testingcommons.MockIDService) - m[identity.BootstrappedIDService] = ids - m[documents.BootstrappedDocumentService] = documents.DefaultService(nil, nil, nil, documents.NewServiceRegistry()) + ids := new(testingcommons.MockIdentityService) + m[identity.BootstrappedDIDService] = ids + m[documents.BootstrappedDocumentService] = documents.DefaultService(nil, nil, documents.NewServiceRegistry(), ids) err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/client.go b/p2p/client.go index a93a0f272..a6630ac9d 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/p2p/common" @@ -24,7 +26,7 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.CentID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err @@ -43,13 +45,13 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.Cen return h.SendAnchoredDocument(localCtx, in, receiverID[:]) } - id, err := s.idService.LookupIdentityForID(receiverID) + err = s.idService.Exists(ctx, receiverID) if err != nil { return nil, err } // this is a remote account - pid, err := s.getPeerID(id) + pid, err := s.getPeerID(receiverID) if err != nil { return nil, err } @@ -62,7 +64,7 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.Cen recv, err := s.mes.SendMessage( ctx, pid, envelope, - p2pcommon.ProtocolForCID(receiverID)) + p2pcommon.ProtocolForDID(&receiverID)) if err != nil { return nil, err } @@ -91,8 +93,8 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.Cen } // OpenClient returns P2PServiceClient to contact the remote peer -func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { - lastB58Key, err := id.CurrentP2PKey() +func (s *peer) getPeerID(id identity.DID) (libp2pPeer.ID, error) { + lastB58Key, err := s.idService.CurrentP2PKey(id) if err != nil { return "", errors.New("error fetching p2p key: %v", err) } @@ -127,7 +129,7 @@ func (s *peer) getPeerID(id identity.Identity) (libp2pPeer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.CentID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.DID) (*p2ppb.SignatureResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err @@ -154,12 +156,12 @@ func (s *peer) getSignatureForDocument(ctx context.Context, model documents.Core header = &p2ppb.Header{NodeVersion: version.GetVersion().String()} } else { // this is a remote account - id, err := s.idService.LookupIdentityForID(receiverCentID) + err = s.idService.Exists(ctx, receiverCentID) if err != nil { return nil, err } - receiverPeer, err := s.getPeerID(id) + receiverPeer, err := s.getPeerID(receiverCentID) if err != nil { return nil, err } @@ -168,7 +170,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, model documents.Core return nil, err } log.Infof("Requesting signature from %s\n", receiverPeer) - recv, err := s.mes.SendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForCID(receiverCentID)) + recv, err := s.mes.SendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForDID(&receiverCentID)) if err != nil { return nil, err } @@ -205,7 +207,7 @@ type signatureResponseWrap struct { err error } -func (s *peer) getSignatureAsync(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.CentID, out chan<- signatureResponseWrap) { +func (s *peer) getSignatureAsync(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.DID, out chan<- signatureResponseWrap) { resp, err := s.getSignatureForDocument(ctx, model, receiverCentID) out <- signatureResponseWrap{ resp: resp, @@ -237,10 +239,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, model *documents.Co var count int peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) for _, collaborator := range extCollaborators { - collaboratorID, err := identity.ToCentID(collaborator) - if err != nil { - return centerrors.Wrap(err, "failed to convert to CentID") - } + collaboratorID := identity.NewDIDFromBytes(collaborator) count++ m := *model nd := *doc @@ -275,13 +274,13 @@ func convertClientError(recv *p2ppb.Envelope) error { return errors.New(resp.Message) } -func validateSignatureResp(identityService identity.Service, receiver identity.CentID, model *documents.CoreDocumentModel, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { +func validateSignatureResp(identityService identity.ServiceDID, receiver identity.DID, model *documents.CoreDocumentModel, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { compatible := version.CheckVersion(header.NodeVersion) if !compatible { return version.IncompatibleVersionError(header.NodeVersion) } - err := identity.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiver) + err := ideth.ValidateCentrifugeIDBytes(resp.Signature.EntityId, receiver) if err != nil { return centerrors.New(code.AuthenticationFailed, err.Error()) } @@ -289,7 +288,7 @@ func validateSignatureResp(identityService identity.Service, receiver identity.C doc := model.Document err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) if err != nil { - return centerrors.New(code.AuthenticationFailed, "signature invalid") + return centerrors.New(code.AuthenticationFailed, fmt.Sprintf("signature invalid with err: %s", err.Error())) } return nil } diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index cc49fabf0..f75810cf2 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -3,10 +3,15 @@ package p2p_test import ( + "context" "flag" "os" "testing" + "github.com/centrifuge/go-centrifuge/contextutil" + + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" @@ -25,9 +30,11 @@ import ( var ( client documents.Client cfg config.Configuration - idService identity.Service + idService identity.ServiceDID + idFactory identity.Factory cfgStore config.Service docService documents.Service + defaultDID identity.DID ) func TestMain(m *testing.M) { @@ -35,10 +42,18 @@ func TestMain(m *testing.M) { ctx := testingbootstrap.TestFunctionalEthereumBootstrap() cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgStore = ctx[config.BootstrappedConfigStorage].(config.Service) - idService = ctx[identity.BootstrappedIDService].(identity.Service) + idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) client = ctx[bootstrap.BootstrappedPeer].(documents.Client) docService = ctx[documents.BootstrappedDocumentService].(documents.Service) - testingidentity.CreateIdentityWithKeys(cfg, idService) + tc, _ := configstore.TempAccount("", cfg) + didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) + assert.NoError(&testing.T{}, err) + acc := tc.(*configstore.Account) + acc.IdentityID = didAddr.Bytes() + did, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), acc, idService, idFactory) + assert.NoError(&testing.T{}, err) + defaultDID = did result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) @@ -46,8 +61,13 @@ func TestMain(m *testing.M) { func TestClient_GetSignaturesForDocument(t *testing.T) { tc, _, err := createLocalCollaborator(t, false) - ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + acc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) + acci := acc.(*configstore.Account) + acci.IdentityID = defaultDID[:] + ctxh, err := contextutil.New(context.Background(), acci) + assert.Nil(t, err) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) err = client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) assert.Equal(t, 2, len(dm.Document.Signatures)) @@ -56,7 +76,7 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) err = client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) // one signature would be missing @@ -66,32 +86,40 @@ func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { func TestClient_SendAnchoredDocument(t *testing.T) { tc, cid, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) - _, err = client.SendAnchoredDocument(ctxh, cid.CentID(), &p2ppb.AnchorDocumentRequest{Document: dm.Document}) + _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: dm.Document}) if assert.Error(t, err) { assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) } } -func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account, identity.Identity, error) { - tcID := identity.RandomCentID() +func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account, identity.DID, error) { + didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) + assert.NoError(t, err) + did := identity.NewDID(*didAddr) tc, err := configstore.TempAccount("", cfg) assert.NoError(t, err) tcr := tc.(*configstore.Account) - tcr.IdentityID = tcID[:] - id := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService) + tcr.IdentityID = did[:] + cdid, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService, idFactory) + assert.NoError(t, err) + if !cdid.Equal(did) { + assert.True(t, false, "Race condition identified when creating accounts") + } + tcr.IdentityID = did[:] if corruptID { - tcr.IdentityID = utils.RandomSlice(identity.CentIDLength) + tcr.IdentityID = utils.RandomSlice(common.AddressLength) } tc, err = cfgStore.CreateAccount(tcr) assert.NoError(t, err) - return tcr, id, err + return tcr, did, err } -func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) *documents.CoreDocumentModel { +func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte, localID identity.DID) *documents.CoreDocumentModel { idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) + idConfig.ID = localID dm := testingdocuments.GenerateCoreDocumentModelWithCollaborators(collaborators) m, err := docService.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err) diff --git a/p2p/client_test.go b/p2p/client_test.go index db841d97a..7871c0db1 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -20,7 +20,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/identity" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" "github.com/stretchr/testify/assert" @@ -42,24 +42,24 @@ func (mm *MockMessenger) SendMessage(ctx context.Context, p libp2pPeer.ID, pmes } func TestGetSignatureForDocument_fail_connect(t *testing.T) { - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - idService := getIDMocks(centrifugeId) - m := &MockMessenger{} - testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - - coreDocModel := testingdocuments.GenerateCoreDocumentModel() - coreDoc := coreDocModel.Document + centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) ctx := testingconfig.CreateAccountContext(t, c) + idService := getIDMocks(ctx, centrifugeId) + m := &MockMessenger{} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document assert.Nil(t, err, "centrifugeId not initialized correctly ") _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(nil, errors.New("some error")) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(nil, errors.New("some error")) resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -67,23 +67,22 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { } func TestGetSignatureForDocument_fail_version_check(t *testing.T) { - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - assert.Nil(t, err, "centrifugeId not initialized correctly ") - - idService := getIDMocks(centrifugeId) - m := &MockMessenger{} - testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel := testingdocuments.GenerateCoreDocumentModel() - coreDoc := coreDocModel.Document + centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) ctx := testingconfig.CreateAccountContext(t, c) + idService := getIDMocks(ctx, centrifugeId) + m := &MockMessenger{} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) assert.NoError(t, err, "signature request could not be created") - m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp("", nil), nil) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(testClient.createSignatureResp("", nil), nil) resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") @@ -92,16 +91,17 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { } func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { - centrifugeId, err := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - idService := getIDMocks(centrifugeId) - m := &MockMessenger{} - testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel := testingdocuments.GenerateCoreDocumentModel() - coreDoc := coreDocModel.Document + centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) ctx := testingconfig.CreateAccountContext(t, c) + idService := getIDMocks(ctx, centrifugeId) + m := &MockMessenger{} + testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} + coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDoc := coreDocModel.Document assert.Nil(t, err, "centrifugeId not initialized correctly ") @@ -110,7 +110,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} - m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForCID(centrifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) + m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) @@ -121,11 +121,10 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { } -func getIDMocks(centrifugeId identity.CentID) *testingcommons.MockIDService { - idService := &testingcommons.MockIDService{} - id := &testingcommons.MockID{} - id.On("CurrentP2PKey").Return("5dsgvJGnvAfiR3K6HCBc4hcokSfmjj", nil) - idService.On("LookupIdentityForID", centrifugeId).Return(id, nil) +func getIDMocks(ctx context.Context, centrifugeId identity.DID) *testingcommons.MockIdentityService { + idService := &testingcommons.MockIdentityService{} + idService.On("CurrentP2PKey", centrifugeId).Return("5dsgvJGnvAfiR3K6HCBc4hcokSfmjj", nil) + idService.On("Exists", ctx, centrifugeId).Return(nil) return idService } diff --git a/p2p/common/protocol.go b/p2p/common/protocol.go index 98e1df20c..9073779ee 100644 --- a/p2p/common/protocol.go +++ b/p2p/common/protocol.go @@ -71,16 +71,16 @@ func MessageTypeFromString(ht string) MessageType { return messageType } -// ProtocolForCID creates the protocol string for the given CID -func ProtocolForCID(CID identity.CentID) protocol.ID { - return protocol.ID(fmt.Sprintf("%s/%s", CentrifugeProtocol, CID.String())) +// ProtocolForDID creates the protocol string for the given CID +func ProtocolForDID(DID *identity.DID) protocol.ID { + return protocol.ID(fmt.Sprintf("%s/%s", CentrifugeProtocol, DID.String())) } -// ExtractCID extracts CID from a protocol string -func ExtractCID(id protocol.ID) (identity.CentID, error) { +// ExtractDID extracts DID from a protocol string +func ExtractDID(id protocol.ID) (identity.DID, error) { parts := strings.Split(string(id), "/") cidHexStr := parts[len(parts)-1] - return identity.CentIDFromString(cidHexStr) + return identity.NewDIDFromString(cidHexStr) } // ResolveDataEnvelope unwraps Content Envelope out of p2pEnvelope @@ -105,12 +105,15 @@ func ResolveDataEnvelope(mes proto.Message) (*p2ppb.Envelope, error) { // PrepareP2PEnvelope wraps content message into p2p envelope func PrepareP2PEnvelope(ctx context.Context, networkID uint32, messageType MessageType, mes proto.Message) (*protocolpb.P2PEnvelope, error) { - self, err := contextutil.Self(ctx) + self, err := contextutil.Account(ctx) if err != nil { return nil, err } - centIDBytes := self.ID[:] + centIDBytes, err := self.GetIdentityID() + if err != nil { + return nil, err + } p2pheader := &p2ppb.Header{ SenderId: centIDBytes, NodeVersion: version.GetVersion().String(), diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index 84fbb5cc8..934ae17ea 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -38,18 +38,20 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestExtractCID(t *testing.T) { - p := protocol.ID("/centrifuge/0.0.1/0xd9f72e705074") - cid, err := ExtractCID(p) +func TestExtractDID(t *testing.T) { + p := protocol.ID("/centrifuge/0.0.1/0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + cid, err := ExtractDID(p) assert.NoError(t, err) - assert.Equal(t, "0xd9f72e705074", cid.String()) + assert.Equal(t, "0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7", cid.String()) } func TestProtocolForCID(t *testing.T) { - cid := identity.RandomCentID() - p := ProtocolForCID(cid) + cid, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + p := ProtocolForDID(&cid) assert.Contains(t, p, cid.String()) - cidE, err := ExtractCID(p) + cidE, err := ExtractDID(p) + assert.NoError(t, err) assert.NoError(t, err) assert.Equal(t, cid.String(), cidE.String()) } diff --git a/p2p/messenger/messenger_test.go b/p2p/messenger/messenger_test.go index 6866e2146..4c4ab4b1f 100644 --- a/p2p/messenger/messenger_test.go +++ b/p2p/messenger/messenger_test.go @@ -13,6 +13,8 @@ import ( "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -22,7 +24,6 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/queue" @@ -81,14 +82,14 @@ func TestMain(m *testing.M) { &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, &leveldb.Bootstrapper{}, + txv1.Bootstrapper{}, + &queue.Bootstrapper{}, + &ideth.Bootstrapper{}, &configstore.Bootstrapper{}, &queue.Bootstrapper{}, - txv1.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, } - idService := &testingcommons.MockIDService{} - ctx[identity.BootstrappedIDService] = idService bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 47ed5c08c..4e13841e2 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -47,12 +47,12 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - cid, err := p2pcommon.ExtractCID(protoc) + DID, err := p2pcommon.ExtractDID(protoc) if err != nil { return convertToErrorEnvelop(err) } - tc, err := srv.config.GetAccount(cid[:]) + tc, err := srv.config.GetAccount(DID[:]) if err != nil { return convertToErrorEnvelop(err) } @@ -61,11 +61,7 @@ func (srv *Handler) HandleInterceptor(ctx context.Context, peer peer.ID, protoc if err != nil { return convertToErrorEnvelop(err) } - fromID, err := identity.ToCentID(envelope.Header.SenderId) - if err != nil { - return convertToErrorEnvelop(err) - } - + fromID := identity.NewDIDFromBytes(envelope.Header.SenderId) err = srv.handshakeValidator.Validate(envelope.Header, &fromID, &peer) if err != nil { return convertToErrorEnvelop(err) @@ -184,10 +180,7 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc return convertToErrorEnvelop(err) } - requesterCentID, err := identity.ToCentID(msg.Header.SenderId) - if err != nil { - return convertToErrorEnvelop(err) - } + requesterCentID := identity.NewDIDFromBytes(msg.Header.SenderId) res, err := srv.GetDocument(ctx, m, requesterCentID) if err != nil { @@ -208,7 +201,7 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc } // GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository -func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.CentID) (*p2ppb.GetDocumentResponse, error) { +func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.DID) (*p2ppb.GetDocumentResponse, error) { model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) if err != nil { diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index b0403d0f5..8e2070fb1 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -5,9 +5,12 @@ package receiver_test import ( "context" "flag" + "math/big" "os" "testing" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/centrifuge-protobufs/documenttypes" @@ -21,7 +24,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/contextutil" cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" @@ -29,7 +31,6 @@ import ( "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" @@ -40,9 +41,11 @@ var ( handler *receiver.Handler anchorRepo anchors.AnchorRepository cfg config.Configuration - idService identity.Service + idService identity.ServiceDID + idFactory identity.Factory cfgService config.Service docSrv documents.Service + defaultDID identity.DID ) func TestMain(m *testing.M) { @@ -52,9 +55,10 @@ func TestMain(m *testing.M) { cfgService = ctx[config.BootstrappedConfigStorage].(config.Service) docSrv = ctx[documents.BootstrappedDocumentService].(documents.Service) anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) - idService = ctx[identity.BootstrappedIDService].(identity.Service) + idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) - testingidentity.CreateIdentityWithKeys(cfg, idService) + defaultDID = createIdentity(&testing.T{}) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() os.Exit(result) @@ -70,10 +74,16 @@ func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { } func TestHandler_GetDocumentSucceeds(t *testing.T) { - ctxh := testingconfig.CreateAccountContext(t, cfg) + tc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) centrifugeId := createIdentity(t) + acc := tc.(*configstore.Account) + acc.IdentityID = centrifugeId[:] - dm := prepareDocumentForP2PHandler(t, nil) + ctxh, err := contextutil.New(context.Background(), tc) + assert.Nil(t, err) + + dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) @@ -87,19 +97,16 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { doc.DocumentRoot = tree.RootHash() // Anchor document - idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) - messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations - assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") + assert.True(t, watchCommittedAnchor, "No error should be thrown by context") anchorReq := getAnchoredRequest(dm) - anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) + anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, centrifugeId[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") @@ -112,15 +119,19 @@ func TestHandler_GetDocumentSucceeds(t *testing.T) { func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) - ctxh := testingconfig.CreateAccountContext(t, cfg) - tc, err := contextutil.Account(ctxh) - _, err = cfgService.CreateAccount(tc) + tc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) + acc := tc.(*configstore.Account) + acc.IdentityID = centID[:] + ctxh, err := contextutil.New(context.Background(), acc) + assert.Nil(t, err) + _, err = cfgService.CreateAccount(acc) assert.NoError(t, err) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, centID) req := getSignatureRequest(dm) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, req) - pub, _ := cfg.GetP2PKeyPair() + pub, _ := acc.GetP2PKeyPair() publicKey, err := cented25519.GetPublicSigningKey(pub) assert.NoError(t, err) var bPk [32]byte @@ -128,7 +139,7 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { peerID, err := cented25519.PublicKeyToP2PKey(bPk) assert.NoError(t, err) - p2pResp, err := handler.HandleInterceptor(ctxh, peerID, p2pcommon.ProtocolForCID(centID), p2pEnv) + p2pResp, err := handler.HandleInterceptor(ctxh, peerID, p2pcommon.ProtocolForDID(¢ID), p2pEnv) assert.Nil(t, err, "must be nil") assert.NotNil(t, p2pResp, "must be non nil") resp := resolveSignatureResponse(t, p2pResp) @@ -140,7 +151,7 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, defaultDID) doc := dm.Document doc.SigningRoot = nil req := getSignatureRequest(dm) @@ -151,9 +162,15 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { } func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, defaultDID) req := getSignatureRequest(dm) - ctxh := testingconfig.CreateAccountContext(t, cfg) + tc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) + acc := tc.(*configstore.Account) + acc.IdentityID = defaultDID[:] + ctxh, err := contextutil.New(context.Background(), acc) + assert.Nil(t, err) + resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") @@ -166,7 +183,7 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, defaultDID) req := getSignatureRequest(dm) doc := dm.Document resp, err := handler.RequestDocumentSignature(ctxh, req) @@ -179,7 +196,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { newDM, err := dm.PrepareNewVersion(nil) assert.Nil(t, err) updateDocumentForP2Phandler(t, newDM) - newDM = prepareDocumentForP2PHandler(t, newDM) + newDM = prepareDocumentForP2PHandler(t, newDM, defaultDID) req = getSignatureRequest(newDM) resp, err = handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") @@ -192,13 +209,13 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, defaultDID) newDM, err := dm.PrepareNewVersion(nil) assert.Nil(t, err) newDoc := newDM.Document assert.NotEqual(t, newDoc.DocumentIdentifier, newDoc.CurrentVersion) updateDocumentForP2Phandler(t, newDM) - newDM = prepareDocumentForP2PHandler(t, newDM) + newDM = prepareDocumentForP2PHandler(t, newDM, defaultDID) req := getSignatureRequest(newDM) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err, "must be nil") @@ -210,7 +227,7 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T func TestHandler_RequestDocumentSignature(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, defaultDID) doc := dm.Document req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) @@ -224,21 +241,19 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { centrifugeId := createIdentity(t) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) // Anchor document doc := dm.Document idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) - messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) ctx := testingconfig.CreateAccountContext(t, cfg) - anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations - assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") + assert.True(t, watchCommittedAnchor, "No error should be thrown by context") anchorReq := getAnchoredRequest(dm) anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq, idConfig.ID[:]) @@ -249,7 +264,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil) + doc := prepareDocumentForP2PHandler(t, nil, defaultDID) req := getAnchoredRequest(doc) req.Document = nil id, err := cfg.GetIdentityID() @@ -260,10 +275,16 @@ func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { } func TestHandler_SendAnchoredDocument(t *testing.T) { - ctxh := testingconfig.CreateAccountContext(t, cfg) + tc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) centrifugeId := createIdentity(t) + acc := tc.(*configstore.Account) + acc.IdentityID = centrifugeId[:] + + ctxh, err := contextutil.New(context.Background(), tc) + assert.Nil(t, err) - dm := prepareDocumentForP2PHandler(t, nil) + dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) @@ -276,62 +297,63 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { doc.DocumentRoot = tree.RootHash() // Anchor document - idConfig, err := identity.GetIdentityConfig(cfg) anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) - messageToSign := anchors.GenerateCommitHash(anchorIDTyped, centrifugeId, docRootTyped) - signature, _ := secp256k1.SignEthereum(messageToSign, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PrivateKey) - anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, centrifugeId, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}, signature) + anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations - assert.Nil(t, watchCommittedAnchor.Error, "No error should be thrown by context") + assert.True(t, watchCommittedAnchor, "No error should be thrown by context") anchorReq := getAnchoredRequest(dm) - anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, idConfig.ID[:]) + anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, centrifugeId[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") assert.True(t, anchorResp.Accepted) } -func createIdentity(t *testing.T) identity.CentID { +func createIdentity(t *testing.T) identity.DID { // Create Identity - centrifugeId, _ := identity.ToCentID(utils.RandomSlice(identity.CentIDLength)) - cfg.Set("identityId", centrifugeId.String()) - id, confirmations, err := idService.CreateIdentity(testingconfig.CreateAccountContext(t, cfg), centrifugeId) + didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) + assert.NoError(t, err) + tc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) + acc := tc.(*configstore.Account) + acc.IdentityID = didAddr.Bytes() + + ctx, err := contextutil.New(context.Background(), tc) + assert.Nil(t, err) + did, err := idFactory.CreateIdentity(ctx) assert.Nil(t, err, "should not error out when creating identity") - watchRegisteredIdentity := <-confirmations - assert.Nil(t, watchRegisteredIdentity.Error, "No error thrown by context") - assert.Equal(t, centrifugeId, watchRegisteredIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") + assert.Equal(t, did.String(), didAddr.String(), "Resulting Identity should have the same ID as the input") idConfig, err := identity.GetIdentityConfig(cfg) + assert.NoError(t, err) // Add Keys - pubKey := idConfig.Keys[identity.KeyPurposeP2P].PublicKey - confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeP2P, pubKey) + pk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeP2P].PublicKey) + assert.NoError(t, err) + keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeP2P), big.NewInt(identity.KeyTypeECDSA)) + err = idService.AddKey(ctx, keyDID) assert.Nil(t, err, "should not error out when adding key to identity") - assert.NotNil(t, confirmations, "confirmations channel should not be nil") - watchReceivedIdentity := <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - sPubKey := idConfig.Keys[identity.KeyPurposeSigning].PublicKey - confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeSigning, sPubKey) + sPk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeSigning].PublicKey) + assert.NoError(t, err) + keyDID = identity.NewKey(sPk, big.NewInt(identity.KeyPurposeSigning), big.NewInt(identity.KeyTypeECDSA)) + err = idService.AddKey(ctx, keyDID) assert.Nil(t, err, "should not error out when adding key to identity") - assert.NotNil(t, confirmations, "confirmations channel should not be nil") - watchReceivedIdentity = <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - secPubKey := idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey - confirmations, err = id.AddKeyToIdentity(context.Background(), identity.KeyPurposeEthMsgAuth, secPubKey) + secPk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) + assert.NoError(t, err) + keyDID = identity.NewKey(secPk, big.NewInt(identity.KeyPurposeEthMsgAuth), big.NewInt(identity.KeyTypeECDSA)) + err = idService.AddKey(ctx, keyDID) assert.Nil(t, err, "should not error out when adding key to identity") - assert.NotNil(t, confirmations, "confirmations channel should not be nil") - watchReceivedIdentity = <-confirmations - assert.Equal(t, centrifugeId, watchReceivedIdentity.Identity.CentID(), "Resulting Identity should have the same ID as the input") - return centrifugeId + return *did } -func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel) *documents.CoreDocumentModel { +func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel, did identity.DID) *documents.CoreDocumentModel { idConfig, err := identity.GetIdentityConfig(cfg) + idConfig.ID = did assert.Nil(t, err) if dm == nil { dm = testingdocuments.GenerateCoreDocumentModel() diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 34d4ed2b2..fb92132e2 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -39,7 +39,7 @@ var ( handler *Handler registry *documents.ServiceRegistry cfg config.Configuration - mockIDService *testingcommons.MockIDService + mockIDService *testingcommons.MockIdentityService defaultPID libp2pPeer.ID ) @@ -58,16 +58,17 @@ func TestMain(m *testing.M) { &anchors.Bootstrapper{}, documents.Bootstrapper{}, } - ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} + mockIDService = &testingcommons.MockIdentityService{} + ctx[identity.BootstrappedDIDService] = mockIDService + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) cfgService := ctx[config.BootstrappedConfigStorage].(config.Service) registry = ctx[documents.BootstrappedRegistry].(*documents.ServiceRegistry) - docSrv := documents.DefaultService(nil, nil, nil, registry) - mockIDService = &testingcommons.MockIDService{} + docSrv := documents.DefaultService(nil, nil, registry, mockIDService) _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) - mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -102,7 +103,7 @@ func TestHandler_HandleInterceptor_CentIDNotHex(t *testing.T) { assert.NoError(t, err) resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("protocolX"), p2pEnv) assert.Error(t, err, "must return error") - assert.Contains(t, err.Error(), "hex string without 0x prefix") + assert.Equal(t, err, identity.ErrMalformedAddress) assert.Nil(t, resp, "must be nil") } @@ -110,7 +111,7 @@ func TestHandler_HandleInterceptor_TenantNotFound(t *testing.T) { ctx := testingconfig.CreateAccountContext(t, cfg) p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &protocolpb.P2PEnvelope{}) assert.NoError(t, err) - resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("0x001100110011"), p2pEnv) + resp, err := handler.HandleInterceptor(context.Background(), libp2pPeer.ID("SomePeer"), protocol.ID("0x89b0a86583c4442acfd71b463e0d3c55ae1412a5"), p2pEnv) assert.Error(t, err, "must return error") assert.Contains(t, err.Error(), "model not found in db") assert.Nil(t, resp, "must be nil") @@ -210,7 +211,7 @@ func TestP2PService_basicChecks(t *testing.T) { } id, _ := cfg.GetIdentityID() - centID, _ := identity.ToCentID(id) + centID := identity.NewDIDFromBytes(id) for _, c := range tests { err := HandshakeValidator(cfg.GetNetworkID(), mockIDService).Validate(c.header, ¢ID, &defaultPID) if err != nil { diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index fb4829352..3c7bc04b9 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -1,6 +1,7 @@ package receiver import ( + "context" "fmt" "github.com/centrifuge/go-centrifuge/identity" @@ -16,14 +17,14 @@ import ( // Validator defines method that must be implemented by any validator type. type Validator interface { // Validate validates p2p requests - Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error + Validate(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error } // ValidatorGroup implements Validator for validating a set of validators. type ValidatorGroup []Validator // Validate will execute all group specific atomic validations -func (group ValidatorGroup) Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) (errs error) { +func (group ValidatorGroup) Validate(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) (errs error) { for _, v := range group { if err := v.Validate(header, centID, peerID); err != nil { errs = errors.AppendError(errs, err) @@ -34,16 +35,16 @@ func (group ValidatorGroup) Validate(header *p2ppb.Header, centID *identity.Cent // ValidatorFunc implements Validator and can be used as a adaptor for functions // with specific function signature -type ValidatorFunc func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error +type ValidatorFunc func(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error // Validate passes the arguments to the underlying validator // function and returns the results -func (vf ValidatorFunc) Validate(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { +func (vf ValidatorFunc) Validate(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error { return vf(header, centID, peerID) } func versionValidator() Validator { - return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error { if header == nil { return errors.New("nil header") } @@ -55,7 +56,7 @@ func versionValidator() Validator { } func networkValidator(networkID uint32) Validator { - return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error { if header == nil { return errors.New("nil header") } @@ -66,8 +67,8 @@ func networkValidator(networkID uint32) Validator { }) } -func peerValidator(idService identity.Service) Validator { - return ValidatorFunc(func(header *p2ppb.Header, centID *identity.CentID, peerID *libp2pPeer.ID) error { +func peerValidator(idService identity.ServiceDID) Validator { + return ValidatorFunc(func(header *p2ppb.Header, centID *identity.DID, peerID *libp2pPeer.ID) error { if header == nil { return errors.New("nil header") } @@ -88,12 +89,12 @@ func peerValidator(idService identity.Service) Validator { if err != nil { return err } - return idService.ValidateKey(*centID, idKey, identity.KeyPurposeP2P) + return idService.ValidateKey(context.Background(), *centID, idKey, int64(identity.KeyPurposeP2P)) }) } // HandshakeValidator validates the p2p handshake details -func HandshakeValidator(networkID uint32, idService identity.Service) ValidatorGroup { +func HandshakeValidator(networkID uint32, idService identity.ServiceDID) ValidatorGroup { return ValidatorGroup{ versionValidator(), networkValidator(networkID), diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 4a1436af1..99d79f3be 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -20,7 +20,7 @@ import ( var ( key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - id1 = []byte{1, 1, 1, 1, 1, 1} + id1 = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} ) func TestValidate_versionValidator(t *testing.T) { @@ -74,9 +74,9 @@ func TestValidate_networkValidator(t *testing.T) { } func TestValidate_peerValidator(t *testing.T) { - cID, _ := identity.ToCentID(id1) + cID := identity.NewDIDFromBytes(id1) - idService := &testingcommons.MockIDService{} + idService := &testingcommons.MockIdentityService{} sv := peerValidator(idService) // Nil headers @@ -93,19 +93,20 @@ func TestValidate_peerValidator(t *testing.T) { assert.Error(t, err) // Identity validation failure - idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() err = sv.Validate(header, &cID, &defaultPID) assert.Error(t, err) // Success - idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() err = sv.Validate(header, &cID, &defaultPID) assert.NoError(t, err) } func TestValidate_handshakeValidator(t *testing.T) { - cID, _ := identity.ToCentID(id1) - idService := &testingcommons.MockIDService{} + cID := identity.NewDIDFromBytes(id1) + + idService := &testingcommons.MockIdentityService{} hv := HandshakeValidator(cfg.GetNetworkID(), idService) // Incompatible version network and wrong signature @@ -128,14 +129,14 @@ func TestValidate_handshakeValidator(t *testing.T) { assert.NotNil(t, err) // Compatible version, network and wrong eth key - idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() header.NetworkIdentifier = cfg.GetNetworkID() err = hv.Validate(header, &cID, &defaultPID) assert.NotNil(t, err) assert.Contains(t, err.Error(), "key not linked to identity") // Compatible version, network and signature - idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + idService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() err = hv.Validate(header, &cID, &defaultPID) assert.NoError(t, err) } diff --git a/p2p/server.go b/p2p/server.go index ab64c7aae..19aa529d4 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -45,7 +45,7 @@ type messenger interface { type peer struct { disablePeerStore bool config config.Service - idService identity.Service + idService identity.ServiceDID host host.Host handlerCreator func() *receiver.Handler mes messenger @@ -108,18 +108,15 @@ func (s *peer) initProtocols() error { if err != nil { return err } - CID, err := identity.ToCentID(accID) - if err != nil { - return err - } - protocols = append(protocols, p2pcommon.ProtocolForCID(CID)) + DID := identity.NewDIDFromBytes(accID) + protocols = append(protocols, p2pcommon.ProtocolForDID(&DID)) } s.mes.Init(protocols...) return nil } -func (s *peer) InitProtocolForCID(CID identity.CentID) { - p := p2pcommon.ProtocolForCID(CID) +func (s *peer) InitProtocolForDID(DID *identity.DID) { + p := p2pcommon.ProtocolForDID(DID) s.mes.Init(p) } diff --git a/p2p/server_test.go b/p2p/server_test.go index 3b2871d50..1eb95a1cd 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -33,7 +33,7 @@ import ( var ( cfg config.Service - idService identity.Service + idService identity.ServiceDID ) func TestMain(m *testing.M) { @@ -51,8 +51,9 @@ func TestMain(m *testing.M) { &anchors.Bootstrapper{}, documents.Bootstrapper{}, } - idService = &testingcommons.MockIDService{} - ctx[identity.BootstrappedIDService] = idService + idService = &testingcommons.MockIdentityService{} + ctx[identity.BootstrappedDIDService] = idService + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} bootstrap.RunTestBootstrappers(ibootstrappers, ctx) cfg = ctx[config.BootstrappedConfigStorage].(config.Service) result := m.Run() diff --git a/protobufs/config/service.proto b/protobufs/config/service.proto index 7933133f0..0b7d89bdc 100644 --- a/protobufs/config/service.proto +++ b/protobufs/config/service.proto @@ -47,5 +47,6 @@ message ConfigData { uint32 network_id = 19; account.AccountData main_identity = 20; map smart_contract_addresses = 21; + map smart_contract_bytecode = 23; bool pprof_enabled = 22; } diff --git a/protobufs/gen/go/config/service.pb.go b/protobufs/gen/go/config/service.pb.go index 886971dff..a9d09d12a 100644 --- a/protobufs/gen/go/config/service.pb.go +++ b/protobufs/gen/go/config/service.pb.go @@ -50,6 +50,7 @@ type ConfigData struct { NetworkId uint32 `protobuf:"varint,19,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` MainIdentity *account.AccountData `protobuf:"bytes,20,opt,name=main_identity,json=mainIdentity,proto3" json:"main_identity,omitempty"` SmartContractAddresses map[string]string `protobuf:"bytes,21,rep,name=smart_contract_addresses,json=smartContractAddresses,proto3" json:"smart_contract_addresses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + SmartContractBytecode map[string]string `protobuf:"bytes,23,rep,name=smart_contract_bytecode,json=smartContractBytecode,proto3" json:"smart_contract_bytecode,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` PprofEnabled bool `protobuf:"varint,22,opt,name=pprof_enabled,json=pprofEnabled,proto3" json:"pprof_enabled,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -60,7 +61,7 @@ func (m *ConfigData) Reset() { *m = ConfigData{} } func (m *ConfigData) String() string { return proto.CompactTextString(m) } func (*ConfigData) ProtoMessage() {} func (*ConfigData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_347685df747205e5, []int{0} + return fileDescriptor_service_3fe01735a8c62984, []int{0} } func (m *ConfigData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConfigData.Unmarshal(m, b) @@ -227,6 +228,13 @@ func (m *ConfigData) GetSmartContractAddresses() map[string]string { return nil } +func (m *ConfigData) GetSmartContractBytecode() map[string]string { + if m != nil { + return m.SmartContractBytecode + } + return nil +} + func (m *ConfigData) GetPprofEnabled() bool { if m != nil { return m.PprofEnabled @@ -237,6 +245,7 @@ func (m *ConfigData) GetPprofEnabled() bool { func init() { proto.RegisterType((*ConfigData)(nil), "config.ConfigData") proto.RegisterMapType((map[string]string)(nil), "config.ConfigData.SmartContractAddressesEntry") + proto.RegisterMapType((map[string]string)(nil), "config.ConfigData.SmartContractBytecodeEntry") } // Reference imports to suppress errors if they are not otherwise used. @@ -311,59 +320,61 @@ var _ConfigService_serviceDesc = grpc.ServiceDesc{ Metadata: "config/service.proto", } -func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_347685df747205e5) } - -var fileDescriptor_service_347685df747205e5 = []byte{ - // 801 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xdd, 0x6e, 0x23, 0x35, - 0x14, 0xd6, 0xb4, 0xdb, 0x9f, 0x38, 0x49, 0xdb, 0xf5, 0xa6, 0x95, 0x9b, 0x65, 0x61, 0xe8, 0x8a, - 0x25, 0x17, 0x74, 0x22, 0x85, 0x1b, 0xe0, 0xae, 0xdb, 0xad, 0xaa, 0x48, 0x2c, 0x44, 0xb3, 0xa0, - 0x95, 0x00, 0xc9, 0x72, 0x66, 0x4e, 0x33, 0xa3, 0x9d, 0xb1, 0x2d, 0xcf, 0x49, 0x9b, 0xdc, 0x72, - 0xc1, 0x03, 0xc0, 0xa3, 0xf1, 0x0a, 0x3c, 0x08, 0xf2, 0x4f, 0xda, 0x94, 0xa2, 0xed, 0xd5, 0x8c, - 0xbf, 0xef, 0x7c, 0xdf, 0x39, 0x3e, 0xb6, 0x0f, 0xe9, 0x65, 0x4a, 0x5e, 0x95, 0xb3, 0x61, 0x03, - 0xe6, 0xba, 0xcc, 0x20, 0xd1, 0x46, 0xa1, 0xa2, 0xdb, 0x1e, 0xed, 0x1f, 0x8a, 0x2c, 0x53, 0x73, - 0x89, 0xf7, 0xe9, 0xfe, 0x27, 0x33, 0xa5, 0x66, 0x15, 0x0c, 0x85, 0x2e, 0x87, 0x42, 0x4a, 0x85, - 0x02, 0x4b, 0x25, 0x9b, 0xc0, 0x7e, 0x1a, 0x58, 0xb7, 0x9a, 0xce, 0xaf, 0x86, 0xf9, 0xdc, 0xb8, - 0x80, 0xc0, 0x3f, 0xff, 0x2f, 0x0f, 0xb5, 0xc6, 0x65, 0x20, 0xbf, 0x72, 0x9f, 0xec, 0x74, 0x06, - 0xf2, 0xb4, 0xb9, 0x11, 0xb3, 0x19, 0x98, 0xa1, 0xd2, 0xce, 0xfe, 0x61, 0xaa, 0x93, 0x3f, 0x5a, - 0x84, 0x9c, 0xbb, 0x52, 0xdf, 0x08, 0x14, 0xf4, 0x73, 0xd2, 0x69, 0x50, 0x19, 0x31, 0x03, 0xae, - 0x05, 0x16, 0x2c, 0x8a, 0xa3, 0x41, 0x2b, 0x6d, 0x07, 0x6c, 0x22, 0xb0, 0xa0, 0xc7, 0x64, 0x57, - 0x8f, 0x34, 0xd7, 0xca, 0x20, 0xdb, 0x88, 0xa3, 0xc1, 0x56, 0xba, 0xa3, 0x47, 0x7a, 0xa2, 0x0c, - 0xd2, 0x57, 0x64, 0xdf, 0x52, 0xb0, 0x40, 0x30, 0x52, 0x54, 0xbc, 0xd4, 0x6c, 0xd3, 0x19, 0x74, - 0xf5, 0x48, 0x5f, 0x04, 0x74, 0xac, 0xe9, 0x8f, 0xe4, 0xc8, 0xc6, 0x65, 0x4a, 0x4a, 0xc8, 0x6c, - 0x35, 0x1c, 0xcb, 0x1a, 0xd4, 0x1c, 0xd9, 0x93, 0x38, 0x1a, 0xb4, 0x47, 0xc7, 0x89, 0xdf, 0x60, - 0xb2, 0xda, 0x60, 0xf2, 0x26, 0x34, 0x20, 0xed, 0xe9, 0x91, 0x3e, 0xbf, 0xd5, 0xfd, 0xe4, 0x65, - 0xf4, 0x33, 0xd2, 0xb6, 0xfd, 0x05, 0xe3, 0xcb, 0xda, 0x72, 0x65, 0x11, 0x0f, 0xb9, 0xca, 0xbe, - 0x20, 0x7b, 0x21, 0x40, 0xe4, 0xb9, 0x81, 0xa6, 0x61, 0xdb, 0xbe, 0x30, 0x8f, 0x9e, 0x79, 0xd0, - 0xfa, 0xc8, 0x79, 0xcd, 0x6f, 0x94, 0xf9, 0x00, 0xa6, 0x61, 0x3b, 0xde, 0x47, 0xce, 0xeb, 0xf7, - 0x1e, 0xa1, 0xa7, 0xe4, 0x99, 0x27, 0xf9, 0x8d, 0x28, 0xd1, 0x95, 0xcd, 0xeb, 0x86, 0xed, 0xba, - 0xc0, 0x03, 0x4f, 0xbd, 0x17, 0x25, 0xda, 0xc2, 0xde, 0x36, 0x34, 0x26, 0x1d, 0xc0, 0x82, 0x4b, - 0x95, 0x03, 0x9f, 0x9b, 0x8a, 0xb5, 0x5c, 0x52, 0x02, 0x58, 0xfc, 0xa0, 0x72, 0xf8, 0xd9, 0x54, - 0xf4, 0x57, 0xf2, 0xc2, 0x46, 0x64, 0x4a, 0x22, 0x2c, 0x90, 0x1b, 0x10, 0xf9, 0x9d, 0xb5, 0xed, - 0x08, 0x79, 0xac, 0x23, 0xc7, 0x80, 0xc5, 0xb9, 0x97, 0xa7, 0x20, 0xf2, 0x55, 0x76, 0xdb, 0x96, - 0x94, 0xb0, 0x75, 0xf3, 0x7b, 0xbe, 0xed, 0xc7, 0x7c, 0x0f, 0xef, 0x7c, 0xd7, 0x3d, 0x2f, 0x09, - 0xb5, 0x9e, 0xa5, 0x44, 0x30, 0xd7, 0xa2, 0xe2, 0x06, 0xd0, 0x2c, 0x59, 0xe7, 0x31, 0xb7, 0x03, - 0xc0, 0x62, 0x1c, 0x34, 0xa9, 0x95, 0xd8, 0xcb, 0x62, 0x8d, 0x6a, 0xb1, 0x70, 0x1e, 0x25, 0x34, - 0xac, 0x1b, 0x47, 0x83, 0x6e, 0xda, 0x05, 0x2c, 0xde, 0x8a, 0x45, 0xea, 0x41, 0x7a, 0x42, 0x2c, - 0xc0, 0x67, 0xa2, 0xe1, 0xda, 0x94, 0x19, 0xb0, 0xbd, 0x38, 0x1a, 0x3c, 0x49, 0xdb, 0x80, 0xc5, - 0xa5, 0x68, 0x26, 0x16, 0x5a, 0x8f, 0xa9, 0xca, 0xba, 0x44, 0xb6, 0xbf, 0x1e, 0xf3, 0xbd, 0x85, - 0x6c, 0x3e, 0x5c, 0x70, 0xad, 0x54, 0xc5, 0x41, 0x8a, 0x69, 0x05, 0x39, 0x3b, 0x88, 0xa3, 0xc1, - 0x6e, 0xda, 0xc5, 0xc5, 0x44, 0xa9, 0xea, 0xc2, 0x83, 0x94, 0x91, 0x1d, 0x09, 0x68, 0x8f, 0x92, - 0x3d, 0x75, 0xc7, 0xb5, 0x5a, 0xd2, 0x2f, 0xc9, 0xfe, 0x54, 0x29, 0x6c, 0xd0, 0x08, 0xcd, 0x35, - 0xd8, 0x1b, 0x42, 0xe3, 0xcd, 0x41, 0x2b, 0xdd, 0xbb, 0x85, 0x27, 0x16, 0xa5, 0x2f, 0x08, 0x09, - 0x1a, 0x5e, 0xe6, 0xec, 0x99, 0xdb, 0x55, 0x2b, 0x20, 0xe3, 0x9c, 0x7e, 0x4b, 0xba, 0xb5, 0x28, - 0x25, 0x2f, 0x73, 0x90, 0x58, 0xe2, 0x92, 0xf5, 0x5c, 0xf7, 0x7a, 0x49, 0x98, 0x15, 0xc9, 0x99, - 0xff, 0xda, 0x17, 0x99, 0x76, 0x6c, 0xe8, 0x38, 0x44, 0xd2, 0x82, 0xb0, 0xa6, 0x16, 0x06, 0xdd, - 0x99, 0x1a, 0x91, 0xe1, 0xea, 0x3e, 0x43, 0xc3, 0x0e, 0xe3, 0xcd, 0x41, 0x7b, 0x94, 0x24, 0x7e, - 0xf2, 0x24, 0x77, 0xaf, 0x3a, 0x79, 0x67, 0x25, 0xe7, 0x41, 0x71, 0xb6, 0x12, 0x5c, 0x48, 0x34, - 0xcb, 0xf4, 0xa8, 0xf9, 0x5f, 0x92, 0xbe, 0x24, 0x5d, 0xad, 0x8d, 0xba, 0xba, 0x6d, 0xd6, 0x91, - 0x6b, 0x56, 0xc7, 0x81, 0xa1, 0x57, 0xfd, 0x31, 0x79, 0xfe, 0x11, 0x6f, 0x7a, 0x40, 0x36, 0x3f, - 0xc0, 0x32, 0x0c, 0x11, 0xfb, 0x4b, 0x7b, 0x64, 0xeb, 0x5a, 0x54, 0x73, 0x70, 0x93, 0xa3, 0x95, - 0xfa, 0xc5, 0x77, 0x1b, 0xdf, 0x44, 0xa3, 0x9a, 0x74, 0x7d, 0xc5, 0xef, 0xfc, 0xa0, 0xa4, 0xbf, - 0x91, 0xd6, 0x25, 0xa0, 0xc7, 0xe8, 0xd1, 0x83, 0x9b, 0x75, 0x61, 0x47, 0x5e, 0x9f, 0x3e, 0xdc, - 0xed, 0xc9, 0xcb, 0x3f, 0xcf, 0x9e, 0xf6, 0xf7, 0x2f, 0x01, 0x63, 0xfb, 0xc8, 0x62, 0xcf, 0xfc, - 0xfe, 0xf7, 0x3f, 0x7f, 0x6d, 0xb4, 0xe8, 0xce, 0xd0, 0xc7, 0xbf, 0x7e, 0x45, 0x48, 0xa6, 0xea, - 0xa0, 0x7e, 0xdd, 0x09, 0x49, 0x27, 0xd6, 0x7d, 0x12, 0xfd, 0xb2, 0xeb, 0x71, 0x3d, 0x9d, 0x6e, - 0xbb, 0x84, 0x5f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x43, 0x76, 0xcf, 0xec, 0xe6, 0x05, 0x00, - 0x00, +func init() { proto.RegisterFile("config/service.proto", fileDescriptor_service_3fe01735a8c62984) } + +var fileDescriptor_service_3fe01735a8c62984 = []byte{ + // 838 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0x1b, 0x45, + 0x14, 0xd6, 0x36, 0xcd, 0x8f, 0xc7, 0x76, 0x92, 0x4e, 0x9d, 0x74, 0xe2, 0x52, 0x58, 0x52, 0x51, + 0x7c, 0x41, 0xd6, 0x92, 0xb9, 0x01, 0xee, 0x92, 0x34, 0x0a, 0x96, 0x28, 0x58, 0x5b, 0x50, 0x25, + 0x40, 0x1a, 0x8d, 0x77, 0x4f, 0xbc, 0xab, 0xee, 0xce, 0x8c, 0x66, 0x8f, 0x13, 0xfb, 0x96, 0x47, + 0x80, 0x87, 0xe1, 0x41, 0x78, 0x05, 0x1e, 0x04, 0xcd, 0x8f, 0x93, 0xb4, 0x29, 0x44, 0x5c, 0xd9, + 0xfb, 0x7d, 0xdf, 0xf9, 0xce, 0x99, 0x73, 0x66, 0x0e, 0xe9, 0x65, 0x4a, 0x5e, 0x94, 0xb3, 0x61, + 0x03, 0xe6, 0xb2, 0xcc, 0x20, 0xd1, 0x46, 0xa1, 0xa2, 0x1b, 0x1e, 0xed, 0xef, 0x89, 0x2c, 0x53, + 0x73, 0x89, 0xef, 0xd2, 0xfd, 0x8f, 0x66, 0x4a, 0xcd, 0x2a, 0x18, 0x0a, 0x5d, 0x0e, 0x85, 0x94, + 0x0a, 0x05, 0x96, 0x4a, 0x36, 0x81, 0xfd, 0x38, 0xb0, 0xee, 0x6b, 0x3a, 0xbf, 0x18, 0xe6, 0x73, + 0xe3, 0x04, 0x81, 0x7f, 0xfa, 0x3e, 0x0f, 0xb5, 0xc6, 0x65, 0x20, 0xbf, 0x70, 0x3f, 0xd9, 0xd1, + 0x0c, 0xe4, 0x51, 0x73, 0x25, 0x66, 0x33, 0x30, 0x43, 0xa5, 0x9d, 0xfd, 0xdd, 0x54, 0x87, 0x7f, + 0x12, 0x42, 0x4e, 0x5d, 0xa9, 0x2f, 0x05, 0x0a, 0xfa, 0x29, 0xe9, 0x34, 0xa8, 0x8c, 0x98, 0x01, + 0xd7, 0x02, 0x0b, 0x16, 0xc5, 0xd1, 0xa0, 0x95, 0xb6, 0x03, 0x36, 0x11, 0x58, 0xd0, 0x03, 0xb2, + 0xa5, 0x47, 0x9a, 0x6b, 0x65, 0x90, 0x3d, 0x88, 0xa3, 0xc1, 0x7a, 0xba, 0xa9, 0x47, 0x7a, 0xa2, + 0x0c, 0xd2, 0x17, 0x64, 0xc7, 0x52, 0xb0, 0x40, 0x30, 0x52, 0x54, 0xbc, 0xd4, 0x6c, 0xcd, 0x19, + 0x74, 0xf5, 0x48, 0x9f, 0x05, 0x74, 0xac, 0xe9, 0x0f, 0x64, 0xdf, 0xea, 0x32, 0x25, 0x25, 0x64, + 0xb6, 0x1a, 0x8e, 0x65, 0x0d, 0x6a, 0x8e, 0xec, 0x61, 0x1c, 0x0d, 0xda, 0xa3, 0x83, 0xc4, 0x1f, + 0x30, 0x59, 0x1d, 0x30, 0x79, 0x19, 0x1a, 0x90, 0xf6, 0xf4, 0x48, 0x9f, 0x5e, 0xc7, 0xfd, 0xe8, + 0xc3, 0xe8, 0x27, 0xa4, 0x6d, 0xfb, 0x0b, 0xc6, 0x97, 0xb5, 0xee, 0xca, 0x22, 0x1e, 0x72, 0x95, + 0x7d, 0x46, 0xb6, 0x83, 0x40, 0xe4, 0xb9, 0x81, 0xa6, 0x61, 0x1b, 0xbe, 0x30, 0x8f, 0x1e, 0x7b, + 0xd0, 0xfa, 0xc8, 0x79, 0xcd, 0xaf, 0x94, 0x79, 0x0b, 0xa6, 0x61, 0x9b, 0xde, 0x47, 0xce, 0xeb, + 0x37, 0x1e, 0xa1, 0x47, 0xe4, 0xb1, 0x27, 0xf9, 0x95, 0x28, 0xd1, 0x95, 0xcd, 0xeb, 0x86, 0x6d, + 0x39, 0xe1, 0xae, 0xa7, 0xde, 0x88, 0x12, 0x6d, 0x61, 0xaf, 0x1a, 0x1a, 0x93, 0x0e, 0x60, 0xc1, + 0xa5, 0xca, 0x81, 0xcf, 0x4d, 0xc5, 0x5a, 0x2e, 0x29, 0x01, 0x2c, 0xbe, 0x57, 0x39, 0xfc, 0x64, + 0x2a, 0xfa, 0x0b, 0x79, 0x66, 0x15, 0x99, 0x92, 0x08, 0x0b, 0xe4, 0x06, 0x44, 0x7e, 0x63, 0x6d, + 0x3b, 0x42, 0xee, 0xeb, 0xc8, 0x01, 0x60, 0x71, 0xea, 0xc3, 0x53, 0x10, 0xf9, 0x2a, 0xbb, 0x6d, + 0x4b, 0x4a, 0xd8, 0x6d, 0xf3, 0x77, 0x7c, 0xdb, 0xf7, 0xf9, 0xee, 0xdd, 0xf8, 0xde, 0xf6, 0x3c, + 0x27, 0xd4, 0x7a, 0x96, 0x12, 0xc1, 0x5c, 0x8a, 0x8a, 0x1b, 0x40, 0xb3, 0x64, 0x9d, 0xfb, 0xdc, + 0x76, 0x01, 0x8b, 0x71, 0x88, 0x49, 0x6d, 0x88, 0xbd, 0x2c, 0xd6, 0xa8, 0x16, 0x0b, 0xe7, 0x51, + 0x42, 0xc3, 0xba, 0x71, 0x34, 0xe8, 0xa6, 0x5d, 0xc0, 0xe2, 0x95, 0x58, 0xa4, 0x1e, 0xa4, 0x87, + 0xc4, 0x02, 0x7c, 0x26, 0x1a, 0xae, 0x4d, 0x99, 0x01, 0xdb, 0x8e, 0xa3, 0xc1, 0xc3, 0xb4, 0x0d, + 0x58, 0x9c, 0x8b, 0x66, 0x62, 0xa1, 0xdb, 0x9a, 0xaa, 0xac, 0x4b, 0x64, 0x3b, 0xb7, 0x35, 0xdf, + 0x59, 0xc8, 0xe6, 0xc3, 0x05, 0xd7, 0x4a, 0x55, 0x1c, 0xa4, 0x98, 0x56, 0x90, 0xb3, 0xdd, 0x38, + 0x1a, 0x6c, 0xa5, 0x5d, 0x5c, 0x4c, 0x94, 0xaa, 0xce, 0x3c, 0x48, 0x19, 0xd9, 0x94, 0x80, 0x76, + 0x94, 0xec, 0x91, 0x1b, 0xd7, 0xea, 0x93, 0x7e, 0x4e, 0x76, 0xa6, 0x4a, 0x61, 0x83, 0x46, 0x68, + 0xae, 0xc1, 0xde, 0x10, 0x1a, 0xaf, 0x0d, 0x5a, 0xe9, 0xf6, 0x35, 0x3c, 0xb1, 0x28, 0x7d, 0x46, + 0x48, 0x88, 0xe1, 0x65, 0xce, 0x1e, 0xbb, 0x53, 0xb5, 0x02, 0x32, 0xce, 0xe9, 0xd7, 0xa4, 0x5b, + 0x8b, 0x52, 0xf2, 0x32, 0x07, 0x89, 0x25, 0x2e, 0x59, 0xcf, 0x75, 0xaf, 0x97, 0x84, 0x5d, 0x91, + 0x1c, 0xfb, 0x5f, 0xfb, 0x22, 0xd3, 0x8e, 0x95, 0x8e, 0x83, 0x92, 0x16, 0x84, 0x35, 0xb5, 0x30, + 0xe8, 0x66, 0x6a, 0x44, 0x86, 0xab, 0xfb, 0x0c, 0x0d, 0xdb, 0x8b, 0xd7, 0x06, 0xed, 0x51, 0x92, + 0xf8, 0xcd, 0x93, 0xdc, 0xbc, 0xea, 0xe4, 0xb5, 0x0d, 0x39, 0x0d, 0x11, 0xc7, 0xab, 0x80, 0x33, + 0x89, 0x66, 0x99, 0xee, 0x37, 0x1f, 0x24, 0x29, 0x90, 0x27, 0xef, 0x65, 0x9a, 0x2e, 0x11, 0x32, + 0x95, 0x03, 0x7b, 0xe2, 0x12, 0x1d, 0xdd, 0x97, 0xe8, 0x24, 0xe8, 0x7d, 0x9e, 0xbd, 0xe6, 0x43, + 0x1c, 0x7d, 0x4e, 0xba, 0x5a, 0x1b, 0x75, 0x71, 0x3d, 0x93, 0x7d, 0x37, 0x93, 0x8e, 0x03, 0xc3, + 0x48, 0xfa, 0x63, 0xf2, 0xf4, 0x3f, 0x8e, 0x40, 0x77, 0xc9, 0xda, 0x5b, 0x58, 0x86, 0x5d, 0x65, + 0xff, 0xd2, 0x1e, 0x59, 0xbf, 0x14, 0xd5, 0x1c, 0xdc, 0x82, 0x6a, 0xa5, 0xfe, 0xe3, 0x9b, 0x07, + 0x5f, 0x45, 0xfd, 0x6f, 0x49, 0xff, 0xdf, 0x8b, 0xfc, 0x3f, 0x4e, 0xa3, 0x9a, 0x74, 0xfd, 0xc9, + 0x5f, 0xfb, 0xcd, 0x4e, 0x7f, 0x25, 0xad, 0x73, 0x40, 0x8f, 0xd1, 0xfd, 0x3b, 0x4f, 0xe1, 0xcc, + 0xee, 0xe8, 0x3e, 0xbd, 0xdb, 0xb5, 0xc3, 0xe7, 0xbf, 0x1f, 0x3f, 0xea, 0xef, 0x9c, 0x03, 0xc6, + 0x76, 0x2b, 0xc4, 0x9e, 0xf9, 0xed, 0xaf, 0xbf, 0xff, 0x78, 0xd0, 0xa2, 0x9b, 0x43, 0xaf, 0x3f, + 0x79, 0x41, 0x48, 0xa6, 0xea, 0x10, 0x7d, 0xd2, 0x09, 0x49, 0x27, 0xd6, 0x7d, 0x12, 0xfd, 0xbc, + 0xe5, 0x71, 0x3d, 0x9d, 0x6e, 0xb8, 0x84, 0x5f, 0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x6d, + 0x0b, 0x1a, 0x97, 0x06, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 6582c8058..0e7696baf 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"smart_contract_bytecode":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index 216d3b45b..a58c0975a 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -166,6 +166,12 @@ "type": "string" } }, + "smart_contract_bytecode": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, "pprof_enabled": { "type": "boolean", "format": "boolean" diff --git a/resources/data.go b/resources/data.go index 4022448bd..8b5531a3c 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x5b\x73\xdb\x36\x16\x7e\xd7\xaf\x38\xe3\xbc\xb4\x33\x4b\x19\xbc\x93\x9a\xe9\xec\xc8\xb6\x9c\xa4\x71\x5c\xf9\x92\xba\xf1\xcb\x06\x04\x0e\x25\xc4\x14\xc0\x00\xa0\x2e\xf9\xf5\x3b\x00\x29\xd7\x8e\x63\x77\xb7\x9d\xee\xfa\xc5\x14\x88\x73\x70\x2e\xdf\xf7\x11\xc0\x2b\x38\xc1\x9a\x76\x8d\x05\x8e\x6b\x6c\x54\xbb\x42\x69\xc1\xa2\xb1\x12\x2d\xd0\x05\x15\xd2\x58\xd0\x42\xde\x61\xb5\x1b\x31\x94\x56\x8b\xba\x5b\xe0\x39\xda\x8d\xd2\x77\x13\xd0\x9d\x31\x82\xca\xa5\x68\x9a\x91\x77\x26\x24\x82\x5d\x22\xf0\xc1\xaf\xec\x67\x1a\xb0\x4b\x6a\xe1\xf8\xde\x03\xac\xa8\x90\xd6\xf9\x1f\xed\xa7\x4c\x46\x00\xaf\xe0\x4c\x31\xda\xf8\x10\x84\x5c\x00\x53\xd2\x6a\xca\x2c\x50\xce\x35\x1a\x83\x06\x24\x22\x07\xab\xa0\x42\x30\x68\x61\x23\xec\x12\x50\xae\x61\x4d\xb5\xa0\x55\x83\x66\x3c\x82\xbd\xbd\x73\x09\x20\xf8\x04\xe2\x38\xf6\xcf\x68\x97\xa8\xb1\x5b\x0d\x19\xbc\xe5\x13\x28\xe2\xa2\x7f\x57\x29\x65\x8d\xd5\xb4\x9d\x23\x6a\xd3\xdb\x06\x70\x70\x28\xda\xe4\x30\x8c\xf2\x31\x19\x93\x71\x78\x68\x59\x7b\x18\x17\x11\x89\x0e\x45\x5b\x9b\xc3\x8b\xd5\xf5\xc5\xb6\xda\xdc\x75\xb7\x1f\x3f\x9e\xd4\xdd\xd7\xeb\x6a\x3b\x9b\x5e\xe2\xf5\xf9\xf1\x99\xfa\xba\xdb\xa5\x69\xb1\xbe\x90\x8b\x5f\xd7\xf3\xf7\x9f\xcf\x3e\xde\x1d\xfc\x81\xd3\x78\xef\xf4\xd7\x3a\x9b\x9d\x67\xab\xbb\x2f\x37\xf8\xf9\xe6\xdd\x4d\xf4\x65\xde\x85\xd9\x6f\x2d\x7f\x1d\xdf\xfd\xac\xc2\xeb\x78\xb5\xa4\xcb\xf9\x51\x7a\x85\xa9\x0c\x7b\xa7\xfb\x52\x4d\xf7\x95\xea\x13\x70\xe9\xa3\xb4\xc2\xee\x4e\x29\xb3\x4a\xef\x26\x70\x70\xf0\xcd\x9b\x4b\x5c\x08\x63\x1f\xbd\xa2\x92\x2d\x95\xbe\xc4\x56\x19\xf1\x8d\x55\x4b\x77\x0e\x26\xbf\x54\x8d\x58\x50\x2b\x94\xf4\xef\x7c\xf3\xde\x53\x21\xbf\x0b\xa5\xa1\xc7\xf0\xc3\x65\x8f\xa5\x1f\x47\xf0\x10\x3b\x7d\xa8\xaf\xe0\xbc\x5b\xa1\x16\x0c\xde\x9e\x80\xaa\x3d\x8e\x1e\x20\x66\xf0\x71\xdf\xd2\x34\x1c\xac\x8e\xf6\x7d\x83\x46\x18\xeb\x2c\xa5\xe2\xf8\x14\x72\xad\x56\x6b\xe1\x5f\x28\xef\xfb\x41\x00\xfb\x40\xff\x10\x07\x71\x3a\x8e\xa2\x74\x1c\x11\x32\x4e\xa2\x6f\xb1\x10\x46\x27\xf1\x3b\xa5\x6e\xce\x84\x60\x17\xbf\x6e\xae\x97\xd7\x47\x1f\xb3\xed\x3b\x36\x57\x67\x75\x76\x79\xf1\xf1\xe7\xd3\x76\x53\x87\x3a\x4f\x37\x67\xdb\xe8\xf6\x32\x6e\x8f\x79\x78\xf0\x3d\xf7\x45\x36\x8e\x42\xf2\x9c\xfb\x8b\xdb\xf7\xd3\xe2\xf5\xfc\x8d\x5e\xcf\x6e\x8f\xca\x0d\xbf\x53\x1f\xd8\x74\xba\x3a\xbe\x7d\xd3\x96\xb8\xdb\xdd\x26\x57\xb3\x62\x71\xaa\xe3\xe5\xf5\xf9\x6f\x07\x43\x8d\x66\x03\xee\xef\x3b\xf1\xf6\x04\x02\x18\xba\xf1\x1c\x33\x92\xc1\xf8\x8c\xba\xf2\x00\xc7\xb6\x51\x3b\xe4\x70\xb5\xa2\xda\xc2\xf1\x00\x38\x03\xb5\xd2\xbe\xa0\x0b\xb1\x46\xf9\xa8\x94\x4f\x41\x09\xcf\xa2\x92\x6c\x4b\xc2\xa3\x32\x49\xf3\x10\xf3\xb8\x48\xa2\xac\xcc\x69\x96\x55\x39\x2d\x4b\x4a\x4a\xce\x33\x96\xc7\x3c\x4e\x33\xfe\x02\x7e\xc9\xb6\xcc\x32\xc2\x48\x5c\xf2\x38\x0c\x93\x34\xa6\x35\xe1\x69\xc1\xd2\x2c\xcb\xf2\x28\xe6\x25\x8b\x6a\x9a\xf3\x0c\xd9\x0b\x48\x27\xdb\xbc\x2e\xd2\x84\xd7\xb4\x2c\x48\x18\xf1\xbc\xa6\x69\xca\x0a\x12\x57\x15\x8d\xa2\x8c\x54\x8c\x23\x26\x55\x8a\xfc\x25\x4e\x90\x2d\xaf\x48\x5a\x84\xd3\x32\x8e\x8a\x2c\x4b\x8a\x34\x8d\xa3\x62\xca\x4f\x2a\x32\x8b\xd2\x30\x2c\x92\x2c\x21\x75\x89\xe9\xc9\xc0\x9e\x77\x6a\x4d\xfb\xf2\x3d\xc0\x7a\x85\x5a\xd2\x66\x89\x62\xb1\xb4\x03\x16\x5f\xbd\x7a\x35\x34\xa6\xb7\x38\x9d\x5e\x0c\xbf\x03\xb8\x71\x72\x28\x64\xdd\x69\x0a\x3b\xd5\xc1\xc2\xe9\xb8\x04\xd4\x5a\x69\x87\xb2\xeb\xa5\x30\xa0\xf1\x4b\xe7\x56\x11\x06\xa4\xb2\x60\xba\xb6\x55\xda\x22\x87\x0a\x19\xed\x0c\x3a\x4b\xed\x49\xe4\xa6\xe8\x4e\x4a\xa7\xc5\x5e\x69\x8d\xa5\xd6\x31\xa9\x73\x43\x63\xb8\xec\x64\x3f\x1e\x04\xc3\xd8\x4f\x54\xb3\xa5\x58\xe3\xf8\xe0\x1f\x43\x50\x00\x1b\x47\x44\xab\x80\xab\x7f\x7a\x0b\x0a\x8d\x57\xf9\x96\x6a\x61\x77\xfd\x42\xde\xcb\x9d\xcf\x07\x17\x93\xfe\xe7\xa7\x61\x42\x10\xb0\x25\x15\xf2\xa7\xfe\x75\x10\xb8\x68\x7f\x8a\x49\x4c\x12\x08\x82\x0d\xd5\xed\xf0\x2f\xa8\xa8\xd6\x02\x35\xa4\x59\x41\x08\x21\x10\x04\x52\x05\x54\x32\x81\xd2\x06\x55\xa3\xd8\x9d\xe9\xc7\x0c\xea\x35\x06\x8d\x2b\x2a\x04\xc1\x8a\x6e\x83\xd6\x71\x1d\xa2\xd4\x19\x19\x49\x5b\xb3\x54\x76\x18\xf4\x63\x2b\x21\x1f\xfd\x74\x31\x53\x66\xc5\x1a\x21\x08\x1c\xc6\x5d\x89\x54\x5d\x3f\xad\x04\x04\x01\xaf\x02\xa6\x56\xad\x9b\xaf\x24\x18\xc3\x5d\x4a\x94\x2d\x31\x30\xe2\x2b\x42\x42\xca\x0c\x82\xe0\xb3\x51\x52\xb7\x2c\x58\x2a\x63\x0d\xd0\xa6\x79\x30\x26\xa4\x45\x5d\x53\x86\x6e\xfc\xd3\xe3\x76\x3f\x2d\xe6\xf7\x3a\x7f\xe4\xd2\x47\xee\x28\x29\xb1\x0f\xc4\x2a\xb8\xc1\xea\xca\x8d\x5b\x03\xbe\x26\x1a\x6a\xad\x56\xd0\x49\xab\x3b\xe3\x20\xa1\xb4\x58\x08\x39\x81\xf1\xf8\xe0\xd9\x7e\x3a\xee\x3f\xe9\xe5\xa7\x20\xe8\xa4\xa1\x35\x06\xb8\x6d\x95\xc1\x4f\x50\x37\x74\xf1\x0d\x80\xff\x3b\xc1\x8f\xfe\xa2\xe0\x3f\xe2\xd2\x7f\x2c\xf9\x21\x49\xc6\x61\x9a\x8c\xc3\x62\x9c\x3e\xf9\xfc\xef\x35\x79\x6e\x32\x41\xf1\x43\x77\x7a\x7b\xde\x85\xaf\xb7\x6b\xb3\x3b\xba\xbe\xd2\xd7\xa6\x5c\xdb\xa3\xac\xb2\xef\xa7\xf2\xcd\xa9\x3a\xfb\x5c\xdd\x7d\x3d\xa6\x07\xdf\x71\x9f\x8e\xc3\x22\x1d\x47\x71\xfe\xec\x02\xc7\xaf\xd9\x46\x5c\x7f\x56\xef\x6e\xde\xd4\x47\x34\x29\xa2\x0f\x73\x4b\xf1\xc3\xf6\xfc\x6c\xc3\x8b\xaf\x95\x3c\x0a\xaf\xf2\x0d\x4e\x6f\x3f\x6c\x6f\x5f\x16\x7d\x2f\x1a\xcf\x4a\x7e\xf4\x37\x68\xfe\x0b\x92\x5f\xa4\x55\x1c\xd5\x39\x8d\xeb\x84\x24\x45\x58\x87\x51\x1c\x27\x24\x09\xb3\x9c\xb0\x82\x55\x48\xf2\x3a\xe7\x79\xc9\x5e\x94\xfc\x34\xa1\x18\xe7\x71\x4d\xca\xac\xa6\x75\xc4\xab\xac\x2a\x68\x92\xe5\x61\xce\x48\x55\x16\xc8\x6a\x4a\xf2\x94\xf3\x17\x25\x3f\x49\x92\x3a\x4b\x4a\x8c\x49\x9e\x24\x11\xe6\x19\x63\x75\x1e\xe7\x49\x96\x61\x1a\xd5\x61\x46\xca\xaa\x2c\xa2\x8c\xbc\x2c\xf9\x24\x09\x73\xac\xe2\xbc\x4c\xc2\x30\x4b\xe2\xac\x48\x48\x78\x92\x65\x59\x59\x24\x6c\x76\x92\x67\x65\x32\x3d\x62\x47\x55\x38\x48\xfe\xa5\x6a\x8d\xc5\x27\xa2\xcf\xd5\xa2\xa5\x96\x2d\xff\xdc\xbe\x28\xfe\x8b\x34\xd9\xaf\x0e\x3f\x5c\xff\x72\xf2\x0b\x30\x8d\x4e\xf3\xf5\x10\xaa\xa3\x8a\xf7\xf3\xe3\xb3\xcc\xf9\xdb\xb7\x4b\xff\xbf\x0d\x53\x5f\x84\xe7\xd8\x13\xff\x6f\xc9\x93\x26\xd9\xec\xb4\x88\x8e\x53\x12\x63\x1d\x93\x0c\xc3\x7a\x9a\xe4\x79\x5a\xc7\x84\x64\x45\x95\xf0\x12\x23\x52\x84\xc9\xcb\xe4\x49\xc3\x8c\x1c\x85\x11\x29\x43\x96\x84\xb3\xfc\x38\x09\x6b\x72\x34\x4d\xa7\x58\x46\x29\x25\x49\x94\xb1\x84\x4e\x67\xd3\x17\xc9\x13\x87\x75\x9e\x11\xcc\x49\x72\x1a\xe7\x79\x9a\xf2\xf0\x98\x26\xf5\x51\x8a\x27\xd3\xec\x24\x4f\xd3\x59\x48\xf2\x29\x86\xe1\xcb\xe4\x89\x67\x34\x8e\x8e\xa3\x64\x9a\x46\xe9\x2c\xc7\x82\x66\x61\x19\x1e\x97\x51\x9c\x97\x31\x49\xa3\xd3\x3c\xaf\xb2\xb4\x8c\xb3\x83\x91\x3b\x6c\x52\x4b\xe1\xca\x2a\x4d\x17\x38\x32\xfd\xff\xfe\x08\x39\xa7\x76\xe9\x4b\xdc\xb8\x93\xc8\xc9\x11\xd4\xa2\xc1\x91\x5b\xd4\x2e\x27\x70\x68\x57\xed\xe1\xef\x47\xd9\x7f\x71\x6a\xe9\xd8\xcf\xe4\x95\xf3\x7b\xac\x64\x2d\x16\x9d\xf6\x61\xdd\x2f\xc0\xfc\xe8\xd5\x9f\x5f\xa6\x77\xf0\x64\xb5\x29\x63\xaa\x93\xd6\xc0\x1d\xee\x60\xc8\x62\x44\x87\x41\xb7\xce\x1d\xee\xdc\x30\x0e\x1e\xf7\xaf\x9c\xed\xdb\xfb\x3d\xc1\xc6\x21\xd1\x23\x6a\x3a\x7f\x0b\x54\x72\x98\x47\x73\xb8\xea\x3f\xe8\x8e\xfc\x28\x1d\xbb\x47\x8e\xb7\x6f\x94\xb1\x92\xae\x70\x02\xc4\x1f\x3e\xc9\xe8\x15\xcc\x95\xb6\x83\x13\xe7\xe0\xfb\x86\x6e\xd2\x04\x0a\x52\x44\x6e\x71\x47\xf7\xc0\x2a\xbf\x27\x02\xf6\xb0\x66\x66\xd4\x46\x6d\x5f\xa2\xab\x16\x99\xa8\x77\x30\xdb\x5a\xff\xe9\x85\xb7\xf3\x07\xb1\xfa\xbd\x02\xa3\xd2\x1d\xe5\x35\xba\xed\x10\x07\x6a\x41\xd4\x50\xe1\x52\x48\x0e\xe7\xd3\x6b\xe7\x06\x07\xeb\xb7\xf3\x09\x6c\xc6\xdb\xf1\x6e\xfc\xb5\x6f\x80\x8b\xba\x33\xc8\xef\xf9\xe4\xb2\x6e\xe8\x0e\xb5\x6b\x83\x0f\xd7\xab\x81\x9f\x7d\x2d\x56\xa8\x3a\x9f\xa6\x04\xd5\xa2\x1c\xee\x17\x86\xcd\x90\x57\x3f\xbf\xc1\x1b\xc1\x7e\x78\x30\x99\xc0\x41\x4c\x8c\x07\xdd\x45\x87\x1d\x7e\x93\xae\x5f\x9d\x9a\x9d\x64\x4b\xad\xa4\xea\x8c\x13\x54\x86\xc6\x08\xb9\x18\x7d\x71\x06\x7d\x31\xfa\xdb\x11\xd3\xa7\xde\xad\x2a\xd4\x4e\x92\x9d\x74\xa0\x36\x87\x4c\x49\xe3\x54\x7e\x90\xe7\x8d\x3b\x94\x56\x7e\xb7\xa7\x18\xb5\x7d\x65\x8c\xa5\xda\x76\xed\x08\x9c\xfd\x4d\x6f\x38\x81\x3e\xbd\x53\x8d\x68\xa0\x6b\xe1\x78\xfe\x01\xd8\x8e\x35\x68\xfa\x54\xfb\x05\xdc\x46\x7e\x43\x85\xbf\x54\x71\xf1\xe2\x1a\x1d\x8a\x60\x78\x7d\x43\x85\xcf\xf6\xfd\xd5\x04\xc2\xd1\xf0\xc9\x19\x22\xd4\x68\xb5\x40\xbf\x21\x55\x9b\xa1\xd8\x14\x2c\x35\xee\x93\xe3\xfe\x5d\xf6\x13\x26\x10\x12\x57\xa3\x7b\xe5\x34\xbe\xfb\x82\x3d\xae\xd7\x68\xaf\x9b\x03\x44\xb0\x41\x27\x89\x9b\xa5\x60\xcb\x7b\x4d\x85\x01\xe7\xae\x29\xee\x40\x32\x7c\xf5\x94\xab\xdf\xf0\xb9\xe2\x20\xfa\x9d\x27\xeb\x8c\x55\xab\x61\x91\x3d\x09\x87\xfb\xa7\x81\x5e\xe7\x1e\xef\x07\x2b\x2a\xe4\xc1\xfd\x2d\x93\xe7\xf7\xe0\xf8\x7e\x5d\xd6\xb8\xb3\x42\x0f\xcd\x1f\x36\xe8\x8f\x4a\x42\x23\x6c\x0c\x28\x0d\xa2\x65\xc3\xd5\x13\xad\x1a\x74\x8f\xcc\x7f\x28\xfb\x6a\xba\x0f\xa2\x33\xfc\x70\x79\x36\x81\xa5\xb5\xed\xe4\xf0\xd0\xef\xcd\xdd\x86\x7e\x52\xa6\x49\xba\xc7\x81\xbf\x1a\x5b\x50\x97\x8b\x60\x2e\xdc\x05\x35\x73\xf7\xe8\x6a\xb8\xff\x7b\x32\xb9\x11\x2b\x61\xfb\xc9\x67\xee\x71\x02\x49\x1e\x46\x71\x51\x3c\xc2\xb7\x55\xbe\xd1\x7d\x9b\xe4\xef\x99\x59\x4d\xa5\xa1\xf7\x1b\x7f\x97\x03\xe7\xfd\x55\x1a\x05\x7f\x36\xf2\xc2\xd1\xa7\x02\x56\x8b\xc5\x02\x35\xf2\x9e\x0d\x16\xb7\x76\x8f\x91\x9e\x11\x19\x71\x94\x78\x6e\x61\x8d\x94\x83\x92\xcd\xce\x31\x6d\xcf\x93\xfd\x7d\xe2\x3e\xa4\xdf\x5d\x5f\x22\xe5\x8f\xdd\x87\xe9\xe0\xfd\xdc\x75\xe2\x61\xec\xad\x52\x0d\xac\xe8\xf6\x1e\x97\x56\x81\x41\xc9\x1d\x26\x1f\x4c\x53\x6b\xaf\x02\x2b\xba\xbd\x87\x67\x34\xd4\xf4\xfb\x2e\xfd\x09\x6b\x4d\x1b\xef\x77\xd7\x73\x87\xba\x00\x59\xa7\xb5\xbf\xcb\x7a\x60\xb1\xa4\x06\x2a\x44\x09\x1c\x2d\x32\xeb\xcb\xb4\x77\xe0\xd6\x73\x5f\xc5\x68\xc8\xe0\x44\x18\x8f\x16\xef\xd1\xa8\xd5\x13\xb4\x19\xe0\xea\xe1\x41\x1c\xec\xd6\x47\x44\x5b\xe1\x18\xb6\x9d\x2b\xd5\x4c\x99\x53\x94\x99\x74\x9e\xf8\x04\xac\xee\xd0\x71\x8d\xca\x1d\x70\xac\xba\xc5\x62\x50\x33\x47\x01\xaf\x1d\x0b\x05\x6e\x91\x91\x7f\xdb\x53\xad\x6d\xb5\xaa\x7d\x7b\xee\x4d\x9c\x4e\xba\xd1\x09\xd4\xb4\x31\x38\xfa\x77\x00\x00\x00\xff\xff\x55\x54\xf7\xc0\x11\x16\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x59\x73\xdc\x36\x12\x7e\x9f\x5f\xd1\x25\xbf\x24\x55\xcb\x11\x78\x93\x53\x95\xda\x9a\xd3\x76\x2c\x2b\xa3\xc3\x51\xac\x97\x35\x08\x36\x67\x60\x71\x00\x1a\x00\xe7\xf0\xaf\xdf\x02\xc8\x51\x24\xcb\x52\x76\x93\xca\xae\x5e\xc4\x01\xd0\x8d\x3e\xbe\xfe\xd0\xc0\x2b\x98\x61\x45\xdb\xda\x40\x89\x5b\xac\x65\xb3\x41\x61\xc0\xa0\x36\x02\x0d\xd0\x15\xe5\x42\x1b\x50\x5c\xdc\x61\x71\x18\x30\x14\x46\xf1\xaa\x5d\xe1\x39\x9a\x9d\x54\x77\x23\x50\xad\xd6\x9c\x8a\x35\xaf\xeb\x81\x53\xc6\x05\x82\x59\x23\x94\xbd\x5e\xd1\xad\xd4\x60\xd6\xd4\xc0\xf4\x5e\x03\x6c\x28\x17\xc6\xea\x1f\x1c\x97\x8c\x06\x00\xaf\xe0\x4c\x32\x5a\x3b\x13\xb8\x58\x01\x93\xc2\x28\xca\x0c\xd0\xb2\x54\xa8\x35\x6a\x10\x88\x25\x18\x09\x05\x82\x46\x03\x3b\x6e\xd6\x80\x62\x0b\x5b\xaa\x38\x2d\x6a\xd4\xc3\x01\x1c\xe5\xad\x4a\x00\x5e\x8e\x20\x0c\x43\xf7\x8d\x66\x8d\x0a\xdb\x4d\xef\xc1\xdb\x72\x04\x59\x98\x75\x73\x85\x94\x46\x1b\x45\x9b\x25\xa2\xd2\x9d\xac\x07\x27\xa7\xbc\x89\x4e\xfd\x20\x1d\x92\x21\x19\xfa\xa7\x86\x35\xa7\x61\x16\x90\xe0\x94\x37\x95\x3e\xbd\xd8\x5c\x5f\xec\x8b\xdd\x5d\x7b\xfb\xf1\xe3\xac\x6a\xbf\x5e\x17\xfb\xf9\xf8\x12\xaf\xcf\xa7\x67\xf2\xeb\xe1\x10\xc7\xd9\xf6\x42\xac\x7e\xdd\x2e\xdf\x7f\x3e\xfb\x78\x77\xf2\x07\x4a\xc3\xa3\xd2\x5f\xab\x64\x7e\x9e\x6c\xee\xbe\xdc\xe0\xe7\x9b\x77\x37\xc1\x97\x65\xeb\x27\xbf\x35\xe5\xeb\xf0\xee\x67\xe9\x5f\x87\x9b\x35\x5d\x2f\x27\xf1\x15\xc6\xc2\xef\x94\x1e\x43\x35\x3e\x46\xaa\x73\xc0\xba\x8f\xc2\x70\x73\x58\x50\x66\xa4\x3a\x8c\xe0\xe4\xe4\x9b\x99\x4b\x5c\x71\x6d\x1e\x4d\x51\xc1\xd6\x52\x5d\x62\x23\x35\xff\x46\xaa\xa1\x07\x0b\x93\x5f\x8a\x9a\xaf\xa8\xe1\x52\xb8\x39\x97\xbc\xf7\x94\x8b\xef\x42\xa9\xcf\x31\xfc\x70\xd9\x61\xe9\xc7\x01\x3c\xc4\x4e\x67\xea\x2b\x38\x6f\x37\xa8\x38\x83\xb7\x33\x90\x95\xc3\xd1\x03\xc4\xf4\x3a\xee\x53\x1a\xfb\xbd\xd4\xe4\x98\x37\xa8\xb9\x36\x56\x52\xc8\x12\x9f\x42\xae\x51\x72\xcb\xdd\x84\x74\xba\x1f\x18\x70\x34\xf4\x0f\x71\x10\xc6\xc3\x20\x88\x87\x01\x21\xc3\x28\xf8\x16\x0b\x7e\x30\x0b\xdf\x49\x79\x73\xc6\x39\xbb\xf8\x75\x77\xbd\xbe\x9e\x7c\x4c\xf6\xef\xd8\x52\x9e\x55\xc9\xe5\xc5\xc7\x9f\x17\xcd\xae\xf2\x55\x1a\xef\xce\xf6\xc1\xed\x65\xd8\x4c\x4b\xff\xe4\x7b\xea\xb3\x64\x18\xf8\xe4\x39\xf5\x17\xb7\xef\xc7\xd9\xeb\xe5\x1b\xb5\x9d\xdf\x4e\xf2\x5d\x79\x27\x3f\xb0\xf1\x78\x33\xbd\x7d\xd3\xe4\x78\x38\xdc\x46\x57\xf3\x6c\xb5\x50\xe1\xfa\xfa\xfc\xb7\x93\x3e\x46\xf3\x1e\xf7\xf7\x99\x78\x3b\x03\x0f\xfa\x6c\x3c\x57\x19\x51\x2f\x7c\x46\x6d\x78\xa0\xc4\xa6\x96\x07\x2c\xe1\x6a\x43\x95\x81\x69\x0f\x38\x0d\x95\x54\x2e\xa0\x2b\xbe\x45\xf1\x28\x94\x4f\x41\x09\xcf\xa2\x92\xec\x17\x61\x99\x67\x55\x58\x25\x59\x92\xcc\xd3\x34\x08\x49\x1c\x93\x28\xf4\xd3\xd8\xcf\xc7\x7e\x30\x63\x55\x86\x19\xe6\xe3\x17\xf0\x4b\xf6\x79\x92\x10\x46\xc2\xbc\x0c\x7d\x3f\x8a\x43\x5a\x91\x32\xce\x58\x9c\x24\x49\x1a\x84\x65\xce\x82\x8a\xa6\x65\x82\xec\x05\xa4\x93\x7d\x1c\xa6\xc1\x04\x93\x24\xa4\x65\xb8\x98\x21\x99\x04\x8b\x24\x4a\xd3\x84\x64\xfe\x94\xa4\xe9\x34\x9a\xc4\x94\x46\x71\xfa\x52\x4d\x90\x7d\xbc\x20\x41\x9e\x67\xf9\x6c\x9e\x8e\xc7\x11\x49\xe8\x8c\xf8\xb3\x99\x5f\x06\x71\x99\x54\x01\x92\xc0\x9f\x23\x12\x92\xf5\xd5\xf3\x4e\x6e\x69\x17\xbe\x07\x58\x2f\x50\x09\x5a\xaf\x91\xaf\xd6\xa6\xc7\xe2\xab\x57\xaf\xfa\xc4\x74\x12\x8b\xf1\x45\xff\xdb\x83\x1b\x4b\x87\x5c\x54\xad\xa2\x70\x90\x2d\xac\x2c\x8f\x0b\x40\xa5\xa4\xb2\x28\xbb\x5e\x73\x0d\x0a\xbf\xb4\x76\x17\xae\x41\x48\x03\xba\x6d\x1a\xa9\x0c\x96\x50\x20\xa3\xad\x46\x2b\xa9\x5c\x11\xd9\x25\xaa\x15\xc2\x72\xb1\x63\x5a\x6d\xa8\xb1\x95\xd4\xda\xa1\x21\x5c\xb6\xa2\x1b\xf7\xbc\x7e\xec\x27\xaa\xd8\x9a\x6f\x71\x78\xf2\x8f\xde\x28\x80\x9d\x2d\x44\x23\xa1\x94\xff\x74\x12\x14\x6a\xc7\xf2\x0d\x55\xdc\x1c\xba\x8d\x9c\x96\x3b\xe7\x0f\xae\x46\xdd\xcf\x4f\xfd\x02\xcf\x63\x6b\xca\xc5\x4f\xdd\xb4\xe7\x59\x6b\x7f\x0a\x49\x48\x22\xf0\xbc\x1d\x55\x4d\xff\xcf\x2b\xa8\x52\x1c\x15\xc4\x49\x46\x08\x21\xe0\x79\x42\x7a\x54\x30\x8e\xc2\x78\x45\x2d\xd9\x9d\xee\xc6\x34\xaa\x2d\x7a\xb5\x0d\x2a\x78\xde\x86\xee\xbd\xc6\xd6\x3a\x04\xb1\x15\xd2\x82\x36\x7a\x2d\x4d\x3f\xe8\xc6\x36\x5c\x3c\xfa\x69\x6d\xa6\xcc\xf0\x2d\x82\xe7\x59\x8c\xdb\x10\xc9\xaa\x7a\x1a\x09\xf0\xbc\xb2\xf0\x98\xdc\x34\x76\xbd\x14\xa0\x75\x69\x5d\xa2\x6c\x8d\x9e\xe6\x5f\x11\x22\x92\x27\xe0\x79\x9f\xb5\x14\xaa\x61\xde\x5a\x6a\xa3\x81\xd6\xf5\x83\x31\x2e\x0c\xaa\x8a\x32\xb4\xe3\x9f\x1e\xa7\xfb\x69\x30\xbf\x97\xf9\x89\x75\x1f\x4b\x5b\x92\x02\x3b\x43\x8c\x84\x1b\x2c\xae\xec\xb8\xd1\xe0\x62\xa2\xa0\x52\x72\x03\xad\x30\xaa\xd5\x16\x12\x52\xf1\x15\x17\x23\x18\x0e\x4f\x9e\xcd\xa7\xad\xfd\x27\xb9\xfc\xe4\x79\xad\xd0\xb4\x42\x0f\xf7\x8d\xd4\xf8\x09\xaa\x9a\xae\xbe\x01\xf0\x7f\x47\xf8\xc1\x5f\x24\xfc\x47\xb5\xf4\x1f\x53\xbe\x4f\xa2\xa1\x1f\x47\x43\x3f\x1b\xc6\x4f\x8e\xff\x23\x27\x2f\x75\xc2\x29\x7e\x68\x17\xb7\xe7\xad\xff\x7a\xbf\xd5\x87\xc9\xf5\x95\xba\xd6\xf9\xd6\x4c\x92\xc2\xbc\x1f\x8b\x37\x0b\x79\xf6\xb9\xb8\xfb\x3a\xa5\x27\xdf\x51\x1f\x0f\xfd\x2c\x1e\x06\x61\xfa\xec\x06\xd3\xd7\x6c\xc7\xaf\x3f\xcb\x77\x37\x6f\xaa\x09\x8d\xb2\xe0\xc3\xd2\x50\xfc\xb0\x3f\x3f\xdb\x95\xd9\xd7\x42\x4c\xfc\xab\x74\x87\xe3\xdb\x0f\xfb\xdb\x97\x49\xdf\x91\xc6\xb3\x94\x1f\xfc\x0d\x9c\xff\x02\xe5\x4f\xc3\x10\xa3\x64\x9e\x55\x69\x56\x45\xc1\x74\x41\x22\x9f\x4e\x72\x42\x72\x3f\x88\x17\x61\x16\x64\x64\x9e\x91\x79\x38\x7d\x91\xf2\xe3\x88\x62\x98\x86\x15\xc9\x93\x8a\x56\x41\x59\x24\x45\x46\xa3\x24\xf5\x53\x46\x8a\x3c\x43\x56\x51\x92\xc6\x65\xf9\x22\xe5\xb3\x79\x40\x93\x79\x10\x05\xd3\x28\x4e\x27\x2c\x9d\xb3\x02\x09\x2b\xf2\x72\x9c\x55\xc1\x62\x31\x1d\x07\x7e\x90\x86\x2c\x7f\x99\xf2\xa3\x3c\x08\x90\xfa\x94\xc4\xcc\x8f\xe3\x28\xc5\x71\x58\xa5\x34\xc4\x71\x3e\x21\xd5\x64\x11\xe4\x49\x3c\x8f\x92\x64\xd1\x53\xfe\xa5\x6c\xb4\xc1\x27\xa4\x5f\xca\x55\x43\x0d\x5b\xff\xb9\xbe\x28\xfc\x8b\x65\x72\xdc\x1d\x7e\xb8\xfe\x65\xf6\x0b\x30\x85\x96\xf3\x55\x6f\xaa\x2d\x15\xa7\xe7\xc7\x67\x2b\xe7\x6f\x6f\x97\xfe\x7f\x0d\x53\x17\x84\xe7\xaa\x27\xfc\xdf\x16\x4f\x94\x96\xa1\x9f\x47\x55\x16\x67\xa5\xbf\xa0\x41\x32\x8d\x7d\x9a\x87\x49\xe8\x4f\xe7\xe3\x04\x17\x34\x4e\xc9\x3c\x0b\xc3\x97\x8b\x27\xf6\x13\x32\xf1\x03\x92\xfb\x2c\xf2\xe7\xe9\x34\xf2\x2b\x32\x19\xc7\x63\xcc\x83\x98\x92\x28\x48\x58\x44\xc7\xf3\xf1\x8b\xc5\x33\x0f\x83\x20\x23\x29\x09\xd3\x74\x82\xc9\x6c\x46\xc2\x2a\xc8\x93\xc4\x1f\xcf\xfc\x3c\x9a\x97\x24\xcc\xaa\x20\x0b\x49\xf5\x07\xfd\x52\x16\x10\x46\xe2\x79\x86\xf3\xb4\x4c\xc2\x34\x20\xb3\x45\x36\x8b\x31\x99\xc6\x79\x96\x8e\x59\x32\xcb\xf3\x6c\x1a\x05\x27\x03\x7b\xd9\xa4\x86\xc2\x95\x91\x8a\xae\x70\xa0\xbb\xff\xdd\x15\x72\x49\xcd\xda\x85\xb8\xb6\x37\x91\xd9\x04\x2a\x5e\xe3\xc0\x6e\x6a\xd6\x23\x38\x35\x9b\xe6\xf4\xf7\xab\xec\xbf\x4a\x6a\xe8\xd0\xad\x2c\x0b\xab\x77\x2a\x45\xc5\x57\xad\x72\x66\xdd\x6f\xc0\xdc\xe8\xd5\x9f\xdf\xa6\x53\xf0\x64\xb7\x31\x63\xb2\x15\x46\xc3\x1d\x1e\xa0\xf7\x62\x40\xfb\x41\xbb\xcf\x1d\x1e\xec\x30\xf6\x1a\x8f\x53\x56\xf6\xed\x7d\x4f\xb0\xb3\x48\x74\x88\x1a\x2f\xdf\x02\x15\x25\x2c\x83\x25\x5c\x75\x07\xba\x2d\x7e\x14\xb6\xba\x07\xb6\x6e\xdf\x48\x6d\x04\xdd\xe0\x08\x88\xbb\x7c\x92\xc1\x2b\x58\x4a\x65\x7a\x25\x56\xc1\xf7\x05\xed\xa2\x11\x64\x24\x0b\xec\xe6\xb6\xdc\x3d\x23\x5d\x4f\x04\xec\x61\xcc\xf4\xa0\x09\x9a\x2e\x44\x57\x0d\x32\x5e\x1d\x60\xbe\x37\xee\xe8\x85\xb7\xcb\x07\xb6\xba\x5e\x81\x51\x61\xaf\xf2\x0a\x6d\x3b\x54\x02\x35\xc0\x2b\x28\x70\xcd\x45\x09\xe7\xe3\x6b\xab\x06\x7b\xe9\xb7\xcb\x11\xec\x86\xfb\xe1\x61\xf8\xb5\x4b\x80\xb5\xba\xd5\x58\xde\xd7\x93\xf5\xba\xa6\x07\x54\x36\x0d\xce\x5c\xc7\x06\x6e\xf5\x35\xdf\xa0\x6c\x9d\x9b\x02\x64\x83\xa2\x7f\x5f\xe8\x9b\x21\xc7\x7e\xae\xc1\x1b\xc0\x71\xb8\x17\x19\xc1\x49\x48\xb4\x03\xdd\x45\x8b\x2d\x7e\xe3\xae\xdb\x9d\xea\x83\x60\x6b\x25\x85\x6c\xb5\x25\x54\x86\x5a\x73\xb1\x1a\x7c\xb1\x02\x5d\x30\xba\xd7\x11\xdd\xb9\xde\x6e\x0a\x54\x96\x92\x2d\x75\xa0\xd2\xa7\x4c\x0a\x6d\x59\xbe\xa7\xe7\x9d\xbd\x94\x16\xae\xdb\x93\x8c\x9a\x2e\x32\xda\x50\x65\xda\x66\x00\x56\xfe\xa6\x13\x1c\x41\xe7\xde\x42\x21\x6a\x68\x1b\x98\x2e\x3f\x00\x3b\xb0\x1a\x75\xe7\x6a\xb7\x81\x6d\xe4\x77\x94\xbb\x47\x15\x6b\x2f\x6e\xd1\xa2\x08\xfa\xe9\x1b\xca\x9d\xb7\xef\xaf\x46\xe0\x0f\xfa\x23\xa7\xb7\x50\xa1\x51\x1c\x5d\x43\x2a\x77\x7d\xb0\x29\x18\xaa\xed\x91\x63\xff\x5d\x76\x0b\x46\xe0\x13\x1b\xa3\x7b\xe6\xd4\x2e\xfb\x9c\x3d\x8e\xd7\xe0\xc8\x9b\x3d\x44\xb0\x46\x4b\x89\xbb\x35\x67\xeb\x7b\x4e\x85\x1e\xe7\x36\x29\xf6\x42\xd2\x9f\x7a\xd2\xc6\xaf\x3f\xae\x4a\xe0\x5d\xe7\xc9\x5a\x6d\xe4\xa6\xdf\xe4\x58\x84\xfd\xfb\x53\x5f\x5e\xe7\x0e\xef\x27\x1b\xca\xc5\xc9\xfd\x2b\x93\xab\xef\x5e\xf1\xfd\xbe\xac\xb6\x77\x85\x0e\x9a\x3f\xec\xd0\x5d\x95\xb8\x42\xd8\x69\x90\x0a\x78\xc3\xfa\xa7\x27\x5a\xd4\x68\x3f\x99\x3b\x28\xbb\x68\xda\x03\xd1\x0a\x7e\xb8\x3c\x1b\xc1\xda\x98\x66\x74\x7a\xea\x7a\x73\xdb\xd0\x8f\xf2\x38\x8a\x8f\x38\x70\x4f\x63\x2b\x6a\x7d\xe1\xcc\x9a\xbb\xa2\x7a\x69\x3f\x6d\x0c\x8f\x7f\x4f\x16\xd7\x7c\xc3\x4d\xb7\xf8\xcc\x7e\x8e\x20\x4a\xfd\x20\xcc\xb2\x47\xf8\x36\xd2\x25\xba\x4b\x93\xf8\xdd\x33\xa3\xa8\xd0\xf4\xbe\xf1\xb7\x3e\x94\x65\xf7\x94\x46\xc1\xdd\x8d\x1c\x71\x74\xae\x80\x51\x7c\xb5\x42\x85\x65\x57\x0d\x06\xf7\xe6\x88\x91\xae\x22\x12\x62\x4b\xe2\xb9\x8d\x15\xd2\x12\xa4\xa8\x0f\xb6\xd2\x8e\x75\x72\x7c\x4f\x3c\x9a\xf4\xbb\xea\x4b\xa4\xe5\x63\xf5\x7e\xdc\x6b\x3f\xb7\x99\x78\x68\x7b\x23\x65\x0d\x1b\xba\xbf\xc7\xa5\x91\xa0\x51\x94\x16\x93\x0f\x96\xc9\xad\x63\x81\x0d\xdd\xdf\xc3\x33\xe8\x63\xfa\x7d\x95\xee\x86\xb5\xa5\xb5\xd3\x7b\xe8\x6a\x87\x5a\x03\x59\xab\x94\x7b\xcb\x7a\x20\xb1\xa6\x1a\x0a\x44\x01\x25\x1a\x64\xc6\x85\xe9\xa8\xc0\xee\x67\x4f\xc5\xa0\xf7\x60\xc6\xb5\x43\x8b\xd3\xa8\xe5\xe6\x09\xda\x34\x94\xf2\xe1\x45\x1c\xcc\xde\x59\x44\x1b\x6e\x2b\x6c\xbf\x94\xb2\x1e\x33\xcb\x28\x73\x61\x35\x95\x23\x30\xaa\x45\x5b\x6b\x54\x1c\xa0\xc4\xa2\x5d\xad\x7a\x36\xb3\x25\xe0\xb8\x63\x25\xc1\x6e\x32\x70\xb3\x5d\xa9\x35\x8d\x92\x95\x4b\xcf\xbd\x88\xe5\x49\x3b\x3a\x82\x8a\xd6\x1a\x07\xff\x0e\x00\x00\xff\xff\x34\x74\x03\xb1\x11\x16\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,12 +84,12 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1548415387, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1551090705, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x88\x49\x71\xcd\x3e\xf8\x14\x1f\x5d\xca\xc0\x48\x9a\x04\x70\x3d\x24\x87\x7b\xc2\xde\x4a\x0a\x45\xdd\x79\x61\xf8\xbf\x07\x5a\xef\xe6\xdc\xf9\x0c\x35\x33\xa3\xef\x31\x23\x7d\x89\xc6\x56\x87\xb2\x9e\xe8\x2f\x6a\x6f\x53\x3d\x07\xd6\x68\x69\xc3\x78\xea\xa8\x3d\x53\xa5\xf5\x12\x3a\xc6\x30\xa5\x69\x1d\xdb\xb2\xd5\x8c\x5d\x70\x18\x03\xbb\x95\x8c\x9d\xe9\x1a\xd8\xd3\x57\xc0\x9c\x2b\x2d\x0b\x04\x70\x3e\x72\x74\xbd\x71\x2a\x69\xad\x35\xa6\x92\xad\x88\xba\x57\xc4\xb3\x4a\xc6\x20\x09\x2d\x24\x1a\xd8\x41\xaa\xd7\xb9\x4d\x10\xbe\x42\x1a\xe6\x67\xaa\x10\x00\x69\xd9\x0b\xe9\xf6\xa9\xd5\x0d\x70\x1b\x37\xfa\xd2\x20\x40\xb2\xd6\x17\xa7\xac\xcf\xd6\xf2\xec\x65\x2a\x49\xe4\x9c\x35\xba\xa2\x44\x36\xc8\x31\x27\x57\x24\xf2\x28\x51\x68\x2e\x94\xe5\x59\xf5\x8a\x17\xe5\x12\x4f\x0e\xff\xd7\x9b\xb1\xe2\x65\xd9\x6c\x87\x57\x08\xa0\xfa\x24\x7a\x47\x56\xc5\xe2\x1d\x2f\x64\x4d\xe4\x56\xda\xe2\x3c\x47\x2b\x30\xc3\xb7\x1d\x9c\x73\x81\x00\xcb\x6d\x61\xb8\xb5\xef\x22\xf9\xfc\x42\x23\x04\x25\x77\x30\x42\x90\xbd\x14\x5a\xef\x60\x86\x20\x76\x50\x21\xb8\x1d\x2c\xf8\xb2\x1d\x90\x49\x44\x12\x3d\xa9\xe4\x9d\xf0\x5a\x67\x41\x09\x65\x74\x51\x5a\xd2\xd4\x13\x8f\x26\x96\xa8\x55\x24\xae\x6c\x8f\x26\x3b\xe7\x7c\xc1\xde\x7a\x94\x4e\x48\xb9\x2d\x72\xc1\xb4\x7d\x8a\x24\xa4\x8b\x4e\x18\x63\x4c\x44\x41\x98\x6d\x42\xf2\xbc\xe7\xe4\x9c\x96\x58\x12\x3a\x65\xfa\xcc\x7b\x6d\x4c\xcc\x1e\x8d\x35\x32\x62\x5f\x52\xe2\x5e\x52\xd9\x94\x86\x0c\x01\xb4\x21\xde\x73\xec\xf7\x59\x22\xed\xb5\x8a\x6e\xef\xa5\x2c\x7b\xad\x9d\xf4\xda\xfb\xac\x6c\x86\x1d\xbc\x52\x5d\x86\x69\x3b\xf2\xdb\xd3\xfd\xc7\xcf\xb8\x2c\x6f\x53\xcd\x81\x3d\x3d\x46\xf7\x0c\x04\xf6\xd1\x08\x74\xdd\x90\x69\x6c\x43\xbb\xfe\x91\x03\x03\xfe\x85\x8b\xf7\x07\xba\xee\x37\xf6\xfb\x3d\x79\x5b\xce\xd8\xd2\xa6\x8a\x27\xea\x7e\x8c\xe3\x99\xae\xdb\x98\x02\x3b\xb6\xcb\x7c\x7c\xbc\xea\xba\x7f\x57\x5a\x69\x43\x8c\xeb\xe5\xf3\x54\xcf\x54\x97\xc0\x64\xc7\xd8\xdb\xad\xf9\x8c\x43\xfb\x67\xb8\xd0\x9f\x7f\x07\x26\xba\x6e\x93\xd9\xc0\xb3\x9c\xbf\x87\x7c\x5e\xe3\xcb\x90\x3e\x6d\xe9\x3e\x1c\x8e\x87\xc3\x31\xae\xc3\x4b\x3e\x56\x5a\xa6\xb5\x26\x5a\x8e\xb3\x9c\x3f\xd1\xf5\x30\xaf\xf1\x30\xd3\xe5\x3b\xa7\x0e\xaf\xd8\xe8\xe7\xa4\xf3\x46\xbc\x91\x96\xe1\x34\x0e\xe3\xe9\x83\x9e\x77\xf4\xaf\xfb\xfe\x40\x7c\xf7\xa6\xf6\x8c\x6b\x7b\xfe\xa0\xf7\x1d\xfd\x8b\xc6\x0f\xd6\xc3\xf5\xbf\x00\x00\x00\xff\xff\x7b\xa2\x4f\x3f\x71\x04\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x08\xa6\xb8\x66\x1f\x7c\x8a\x8f\x2e\x65\x60\x24\x4d\x02\xb8\x1e\x92\xc3\x3d\x62\x6f\x25\x85\xa4\xee\xbc\x30\xfc\xdf\x03\xad\xf7\x62\x77\xde\xeb\x66\x46\xdf\x63\x46\xfa\x14\x71\xea\xb5\xe4\xf5\x84\x7f\x61\x7f\x9b\xeb\xd9\x93\x8e\xad\x97\xe9\x34\x60\x7f\xc6\x8a\xeb\xc5\x0f\x84\x40\x8c\xf3\x3a\xf5\xb6\xd5\x84\x5c\xa0\x4c\x9e\xdc\x4a\x42\xce\x78\xf5\xe4\xe9\x2b\x85\x94\x2a\xb6\x46\x3d\xb5\x2e\x30\xb0\xa3\xb6\x32\x2a\xa5\x14\xc4\x9c\x0c\x0f\x6a\x94\xc8\x92\x8c\x5a\x03\x72\xc5\x05\x68\xba\xa3\xb1\x5e\x97\x3e\x53\xff\x95\xc6\xb2\x3c\x63\xa5\x9e\x02\xb6\x3d\x17\x76\x1f\x7b\xdd\x00\xb7\x71\xc7\x2f\x9d\x7a\x1a\x8d\x71\xd9\x4a\xe3\x92\x31\x2c\x39\x11\x73\xe4\x29\x25\x05\x36\x4b\x9e\x34\x30\x48\xd1\x66\x01\x2c\x08\xe0\x8a\x71\x69\x58\x92\xa3\x64\x59\xda\xc8\xa2\x85\xff\xf5\x16\xa8\x70\x69\x9b\x6d\x79\xa5\x9e\xca\x31\xf2\xd1\xa2\x91\x21\x3b\xcb\x32\x1a\x1d\x98\x11\x26\x5b\xc7\xc0\x70\x48\xf4\xdb\x8e\x9e\x53\xa6\x9e\xb6\xdb\xc2\xf4\xd6\xfe\x10\x49\xe7\x17\x9c\xa8\x97\x62\x47\x27\xea\xc5\x28\xb8\x52\x3b\xba\x50\xcf\x77\xb4\x52\x6f\x77\xb4\xc1\xcb\x76\x40\x42\x1e\x90\x8f\x28\xa3\xb3\xdc\x29\x95\x38\x46\x10\xc1\x06\x61\x50\xe1\x88\x2c\xe8\x90\x83\x92\x01\x99\x34\x23\xe8\x64\xad\x75\x19\x46\xe3\x40\x58\x2e\xc4\xb6\xc8\x05\xe2\xf6\x2a\x22\x17\x36\x58\xae\xb5\xd6\x01\x38\x42\x32\x11\xd0\xb1\x91\xa1\xb5\x4a\x40\x8e\x60\xa5\x1e\x13\x1b\x95\xd6\x21\x39\xd0\x46\x8b\x00\x63\x8e\x91\x39\x81\x79\x53\x2a\x89\x7a\xaa\x34\xb2\x91\xc1\xb8\x4f\x02\x70\xaf\x64\xb0\x7b\x27\x44\xde\x2b\x65\x85\x53\xce\x25\x69\x12\xdd\xd1\x57\xac\xad\xcc\xdb\x91\xdf\x9e\xee\x1f\x7e\x81\xd6\xde\xe6\x9a\x3c\x79\x7a\x1f\xdd\x33\xe0\xc9\xa3\x11\x18\x86\x92\x70\xea\xa5\x5f\xff\x48\x9e\x50\xf6\xe5\xe1\xec\x0c\xc3\x6f\xe4\xf7\x7b\x2a\xb7\x0c\x92\xd6\xe7\x0a\x27\x1c\x7e\x8e\xea\x19\xaf\xdb\x18\x3d\x39\xf6\xcb\x72\x7c\x7f\x34\x0c\xff\xae\xb8\xe2\x86\x98\xd6\xcb\xe7\xb9\x9e\xb1\x36\x4f\xc4\x40\xc8\xdb\xad\xf9\x0c\xa5\xff\x53\x2e\xf8\xe7\xdf\x9e\xf0\x61\xd8\x64\x36\xf0\x22\x96\xef\x3f\xc0\xb2\x86\x97\x12\x3f\x6d\xc9\x3f\x1c\x8e\x87\xc3\x31\xac\xe5\x25\x1d\x2b\xb6\x79\xad\x11\xdb\x71\x11\xcb\x27\xbc\x1e\x96\x35\x1c\x16\xbc\x7c\xe7\xd4\xf2\x0a\x1d\x7f\x4d\x3a\x6f\xc4\x1b\xa9\x95\xd3\x54\xa6\xd3\x83\x9e\x77\xf4\xc7\x7d\x7f\x22\xfe\xf0\xc6\xfe\x0c\x6b\x7f\x7e\xd0\xfb\x8e\xfe\xa0\xf1\x3b\xeb\xdd\xf5\xbf\x00\x00\x00\xff\xff\x84\x06\xaa\x14\x8d\x04\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1137, mode: os.FileMode(420), modTime: time.Unix(1548944078, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1165, mode: os.FileMode(420), modTime: time.Unix(1551084552, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testingutils/commons/mock_did_identity.go b/testingutils/commons/mock_did_identity.go new file mode 100644 index 000000000..aceb00f38 --- /dev/null +++ b/testingutils/commons/mock_did_identity.go @@ -0,0 +1,128 @@ +package testingcommons + +import ( + "context" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" + + "math/big" +) + +// MockIdentityService implements Service +type MockIdentityService struct { + mock.Mock +} + +// AddKey adds a key to identity contract +func (i *MockIdentityService) AddKey(ctx context.Context, key identity.KeyDID) error { + args := i.Called(ctx, key) + return args.Error(0) +} + +// AddKeysForAccount adds key from configuration +func (i *MockIdentityService) AddKeysForAccount(acc config.Account) error { + args := i.Called(acc) + return args.Error(0) +} + +// GetKey return a key from the identity contract +func (i *MockIdentityService) GetKey(did identity.DID, key [32]byte) (*identity.KeyResponse, error) { + args := i.Called(did, key) + return args.Get(0).(*identity.KeyResponse), args.Error(1) + +} + +// RawExecute calls the execute method on the identity contract +func (i *MockIdentityService) RawExecute(ctx context.Context, to common.Address, data []byte) error { + args := i.Called(ctx, to, data) + return args.Error(0) +} + +// Execute creates the abi encoding an calls the execute method on the identity contract +func (i *MockIdentityService) Execute(ctx context.Context, to common.Address, contractAbi, methodName string, args ...interface{}) error { + a := i.Called(ctx, to, contractAbi, methodName, args) + return a.Error(0) +} + +// IsSignedWithPurpose verifies if a message is signed with one of the identities specific purpose keys +func (i *MockIdentityService) IsSignedWithPurpose(did identity.DID, message [32]byte, signature []byte, purpose *big.Int) (bool, error) { + args := i.Called(did, message, signature, purpose) + return args.Get(0).(bool), args.Error(1) +} + +// AddMultiPurposeKey adds a key with multiple purposes +func (i *MockIdentityService) AddMultiPurposeKey(ctx context.Context, key [32]byte, purposes []*big.Int, keyType *big.Int) error { + args := i.Called(ctx, key, purposes, keyType) + return args.Error(0) +} + +// RevokeKey revokes an existing key in the smart contract +func (i *MockIdentityService) RevokeKey(ctx context.Context, key [32]byte) error { + args := i.Called(ctx, key) + return args.Error(0) + +} + +// GetClientP2PURL returns the p2p url associated with the did +func (i *MockIdentityService) GetClientP2PURL(did identity.DID) (string, error) { + args := i.Called(did) + return args.Get(0).(string), args.Error(1) + +} + +//Exists checks if an identity contract exists +func (i *MockIdentityService) Exists(ctx context.Context, did identity.DID) error { + args := i.Called(ctx, did) + return args.Error(0) +} + +// ValidateKey checks if a given key is valid for the given centrifugeID. +func (i *MockIdentityService) ValidateKey(ctx context.Context, did identity.DID, key []byte, purpose int64) error { + args := i.Called(ctx, did, key, purpose) + return args.Error(0) +} + +// ValidateSignature checks if signature is valid for given identity +func (i *MockIdentityService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { + args := i.Called(signature, message) + return args.Error(0) +} + +// CurrentP2PKey retrieves the last P2P key stored in the identity +func (i *MockIdentityService) CurrentP2PKey(did identity.DID) (ret string, err error) { + args := i.Called(did) + return args.Get(0).(string), args.Error(1) +} + +// GetClientsP2PURLs returns p2p urls associated with each centIDs +// will error out at first failure +func (i *MockIdentityService) GetClientsP2PURLs(dids []*identity.DID) ([]string, error) { + args := i.Called(dids) + return args.Get(0).([]string), args.Error(1) + +} + +// GetKeysByPurpose returns keys grouped by purpose from the identity contract. +func (i *MockIdentityService) GetKeysByPurpose(did identity.DID, purpose *big.Int) ([][32]byte, error) { + args := i.Called(did, purpose) + return args.Get(0).([][32]byte), args.Error(1) +} + +// MockIdentityFactory implements Service +type MockIdentityFactory struct { + mock.Mock +} + +func (s *MockIdentityFactory) CreateIdentity(ctx context.Context) (did *identity.DID, err error) { + args := s.Called(ctx) + return args.Get(0).(*identity.DID), args.Error(1) +} + +func (s *MockIdentityFactory) CalculateIdentityAddress(ctx context.Context) (*common.Address, error) { + args := s.Called(ctx) + return args.Get(0).(*common.Address), args.Error(1) +} diff --git a/testingutils/commons/mock_identity.go b/testingutils/commons/mock_identity.go deleted file mode 100644 index 1153d86db..000000000 --- a/testingutils/commons/mock_identity.go +++ /dev/null @@ -1,119 +0,0 @@ -// +build unit integration - -/* -The reason for this package is to avoid any kind of cyclic dependencies but share common mocking interfaces from identity packages across other packages -*/ -package testingcommons - -import ( - "context" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" -) - -// MockIDService implements Service -type MockIDService struct { - mock.Mock -} - -func (srv *MockIDService) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { - args := srv.Called(signature, message) - return args.Error(0) -} - -func (srv *MockIDService) GetClientP2PURL(centID identity.CentID) (url string, err error) { - args := srv.Called(centID) - addr := args.Get(0).(string) - return addr, args.Error(1) -} - -func (srv *MockIDService) GetClientsP2PURLs(centIDs []identity.CentID) ([]string, error) { - args := srv.Called(centIDs) - addr := args.Get(0).([]string) - return addr, args.Error(1) -} - -func (srv *MockIDService) GetIdentityKey(id identity.CentID, pubKey []byte) (keyInfo identity.Key, err error) { - args := srv.Called(id, pubKey) - addr := args.Get(0).(identity.Key) - return addr, args.Error(1) -} - -func (srv *MockIDService) ValidateKey(centrifugeId identity.CentID, key []byte, purpose int) error { - args := srv.Called(centrifugeId, key, purpose) - return args.Error(0) -} - -func (srv *MockIDService) AddKeyFromConfig(config identity.Config, purpose int) error { - args := srv.Called(config, purpose) - return args.Error(0) -} - -func (srv *MockIDService) GetIdentityAddress(centID identity.CentID) (common.Address, error) { - args := srv.Called(centID) - addr := args.Get(0).(common.Address) - return addr, args.Error(1) -} - -func (srv *MockIDService) LookupIdentityForID(centID identity.CentID) (identity.Identity, error) { - args := srv.Called(centID) - if id, ok := args.Get(0).(identity.Identity); ok { - return id, args.Error(1) - } - return nil, args.Error(1) -} - -func (srv *MockIDService) CreateIdentity(ctx context.Context, centrifugeID identity.CentID) (id identity.Identity, confirmations chan *identity.WatchIdentity, err error) { - args := srv.Called(centrifugeID) - id, _ = args.Get(0).(identity.Identity) - watch, _ := args.Get(1).(chan *identity.WatchIdentity) - return id, watch, args.Error(2) -} - -func (srv *MockIDService) CheckIdentityExists(centID identity.CentID) (exists bool, err error) { - args := srv.Called(centID) - return args.Bool(0), args.Error(1) -} - -// MockID implements Identity -type MockID struct { - mock.Mock -} - -func (i *MockID) String() string { - args := i.Called() - return args.String(0) -} - -func (i *MockID) CentID() identity.CentID { - args := i.Called() - return args.Get(0).(identity.CentID) -} - -func (i *MockID) SetCentrifugeID(centId identity.CentID) { - i.Called(centId) -} - -func (i *MockID) CurrentP2PKey() (ret string, err error) { - args := i.Called() - return args.String(0), args.Error(1) -} - -func (i *MockID) LastKeyForPurpose(keyPurpose int) (key []byte, err error) { - args := i.Called(keyPurpose) - return args.Get(0).([]byte), args.Error(1) -} - -func (i *MockID) AddKeyToIdentity(ctx context.Context, keyPurpose int, key []byte) (confirmations chan *identity.WatchIdentity, err error) { - args := i.Called(ctx, keyPurpose, key) - return args.Get(0).(chan *identity.WatchIdentity), args.Error(1) -} - -func (i *MockID) FetchKey(key []byte) (identity.Key, error) { - args := i.Called(key) - idKey, _ := args.Get(0).(identity.Key) - return idKey, args.Error(1) -} diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 91528e99d..06bc340d4 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -70,6 +70,11 @@ func (m *MockModel) PackCoreDocument() (*documents.CoreDocumentModel, error) { return dm, args.Error(1) } +func (m *MockModel) UnpackCoreDocument(model *documents.CoreDocumentModel) error { + args := m.Called(model) + return args.Error(0) +} + func (m *MockModel) JSON() ([]byte, error) { args := m.Called() data, _ := args.Get(0).([]byte) diff --git a/testingutils/documents/invoice.go b/testingutils/documents/invoice.go index c8853bd98..6f768be50 100644 --- a/testingutils/documents/invoice.go +++ b/testingutils/documents/invoice.go @@ -4,16 +4,18 @@ package testingdocuments import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/testingutils/identity" ) func CreateInvoiceData() invoicepb.InvoiceData { + recipient := testingidentity.GenerateRandomDID() + sender := testingidentity.GenerateRandomDID() + payee := testingidentity.GenerateRandomDID() return invoicepb.InvoiceData{ - Recipient: utils.RandomSlice(identity.CentIDLength), - Sender: utils.RandomSlice(identity.CentIDLength), - Payee: utils.RandomSlice(identity.CentIDLength), + Recipient: recipient[:], + Sender: sender[:], + Payee: payee[:], GrossAmount: 42, } } @@ -21,13 +23,13 @@ func CreateInvoiceData() invoicepb.InvoiceData { func CreateInvoicePayload() *clientinvoicepb.InvoiceCreatePayload { return &clientinvoicepb.InvoiceCreatePayload{ Data: &clientinvoicepb.InvoiceData{ - Sender: "0x010101010101", - Recipient: "0x010203040506", - Payee: "0x010203020406", + Sender: "0xed03fa80291ff5ddc284de6b51e716b130b05e20", + Recipient: "0xea939d5c0494b072c51565b191ee59b5d34fbf79", + Payee: "0x087d8ca6a16e6ce8d9ff55672e551a2828ab8e8c", GrossAmount: 42, ExtraData: "0x01020302010203", Currency: "EUR", }, - Collaborators: []string{"0x010101010101"}, + Collaborators: []string{testingidentity.GenerateRandomDID().String()}, } } diff --git a/testingutils/documents/purchaseorder.go b/testingutils/documents/purchaseorder.go index 06e229a1e..b502e3836 100644 --- a/testingutils/documents/purchaseorder.go +++ b/testingutils/documents/purchaseorder.go @@ -4,14 +4,14 @@ package testingdocuments import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" - "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" - "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/go-centrifuge/testingutils/identity" ) func CreatePOData() purchaseorderpb.PurchaseOrderData { + recipient := testingidentity.GenerateRandomDID() return purchaseorderpb.PurchaseOrderData{ - Recipient: utils.RandomSlice(identity.CentIDLength), + Recipient: recipient[:], OrderAmount: 42, } } @@ -19,11 +19,11 @@ func CreatePOData() purchaseorderpb.PurchaseOrderData { func CreatePOPayload() *clientpurchaseorderpb.PurchaseOrderCreatePayload { return &clientpurchaseorderpb.PurchaseOrderCreatePayload{ Data: &clientpurchaseorderpb.PurchaseOrderData{ - Recipient: "0x010203040506", + Recipient: "0xea939d5c0494b072c51565b191ee59b5d34fbf79", OrderAmount: 42, ExtraData: "0x01020302010203", Currency: "EUR", }, - Collaborators: []string{"0x010101010101"}, + Collaborators: []string{testingidentity.GenerateRandomDID().String()}, } } diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 204228eb6..13957de12 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -4,75 +4,76 @@ package testingidentity import ( "context" - "testing" + "math/big" "time" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/testingutils/config" ) -func CreateIdentityWithKeys(cfg config.Configuration, idService identity.Service) identity.CentID { - idConfig, _ := identity.GetIdentityConfig(cfg) +func CreateAccountIDWithKeys(contextTimeout time.Duration, acc *configstore.Account, idService identity.ServiceDID, idFactory identity.Factory) (identity.DID, error) { + ctxh, _ := contextutil.New(context.Background(), acc) + idConfig, err := identity.GetIdentityConfig(acc) + if err != nil { + return identity.DID{}, err + } + var did *identity.DID // only create identity if it doesn't exist - id, err := idService.LookupIdentityForID(idConfig.ID) + err = idService.Exists(ctxh, identity.NewDIDFromBytes(acc.IdentityID)) if err != nil { - _, confirmations, _ := idService.CreateIdentity(testingconfig.CreateAccountContext(&testing.T{}, cfg), idConfig.ID) - <-confirmations + did, err = idFactory.CreateIdentity(ctxh) + if err != nil { + return identity.DID{}, err + } // LookupIdentityForId - id, _ = idService.LookupIdentityForID(idConfig.ID) + err = idService.Exists(ctxh, *did) } // only add key if it doesn't exist - _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(cfg.GetEthereumContextWaitTimeout()) - defer cancel() + ctx, cancel := defaultWaitForTransactionMiningContext(contextTimeout) + ctxh, err = contextutil.New(ctx, acc) if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) - <-confirmations + return identity.DID{}, nil } - _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) - ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext(cfg.GetEthereumContextWaitTimeout()) - defer cancel() + keys, err := idService.GetKeysByPurpose(*did, big.NewInt(identity.KeyPurposeEthMsgAuth)) if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) - <-confirmations + return identity.DID{}, nil } - - return idConfig.ID -} - -func CreateAccountIDWithKeys(contextTimeout time.Duration, cfg *configstore.Account, idService identity.Service) identity.Identity { - ctxh, _ := contextutil.New(context.Background(), cfg) - idConfig, _ := identity.GetIdentityConfig(cfg) - // only create identity if it doesn't exist - id, err := idService.LookupIdentityForID(idConfig.ID) - if err != nil { - _, confirmations, _ := idService.CreateIdentity(ctxh, idConfig.ID) - <-confirmations - // LookupIdentityForId - id, _ = idService.LookupIdentityForID(idConfig.ID) - } - - // only add key if it doesn't exist - _, err = id.LastKeyForPurpose(identity.KeyPurposeEthMsgAuth) - ctx, cancel := ethereum.DefaultWaitForTransactionMiningContext(contextTimeout) defer cancel() - if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeEthMsgAuth, idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) - <-confirmations + if err != nil || len(keys) == 0 { + pk, _ := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) + keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeEthMsgAuth), big.NewInt(identity.KeyTypeECDSA)) + err = idService.AddKey(ctxh, keyDID) + if err != nil { + return identity.DID{}, nil + } } - _, err = id.LastKeyForPurpose(identity.KeyPurposeSigning) - ctx, cancel = ethereum.DefaultWaitForTransactionMiningContext(contextTimeout) + keys, err = idService.GetKeysByPurpose(*did, big.NewInt(identity.KeyPurposeSigning)) + ctx, cancel = defaultWaitForTransactionMiningContext(contextTimeout) + ctxh, _ = contextutil.New(ctx, acc) defer cancel() - if err != nil { - confirmations, _ := id.AddKeyToIdentity(ctx, identity.KeyPurposeSigning, idConfig.Keys[identity.KeyPurposeSigning].PublicKey) - <-confirmations + if err != nil || len(keys) == 0 { + pk, _ := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeSigning].PublicKey) + keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeSigning), big.NewInt(identity.KeyTypeECDSA)) + err = idService.AddKey(ctxh, keyDID) + if err != nil { + return identity.DID{}, nil + } } - return id + return *did, nil +} + +func GenerateRandomDID() identity.DID { + r := utils.RandomSlice(identity.DIDLength) + return identity.NewDIDFromBytes(r) +} + +// defaultWaitForTransactionMiningContext returns context with timeout for write operations +func defaultWaitForTransactionMiningContext(d time.Duration) (ctx context.Context, cancelFunc context.CancelFunc) { + toBeDone := time.Now().Add(d) + return context.WithDeadline(context.Background(), toBeDone) } diff --git a/testingutils/setup.go b/testingutils/setup.go index cde119210..989217683 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -1,4 +1,4 @@ -// +build integration unit cmd +// +build integration unit cmd testworld package testingutils @@ -54,12 +54,10 @@ func GetSmartContractAddresses() *config.SmartContractAddresses { panic(err) } idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") - idRegistryAddrOp := getOpForContract(".contracts.IdentityRegistry.address") anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") return &config.SmartContractAddresses{ IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), - IdentityRegistryAddr: getOpAddr(idRegistryAddrOp, dat), AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), PaymentObligationAddr: getOpAddr(payObAddrOp, dat), } diff --git a/testingutils/testingtx/mocktx.go b/testingutils/testingtx/mocktx.go index 1ead8ddbe..a0706fa69 100644 --- a/testingutils/testingtx/mocktx.go +++ b/testingutils/testingtx/mocktx.go @@ -20,23 +20,23 @@ func (m MockTxManager) GetDefaultTaskTimeout() time.Duration { panic("implement me") } -func (m MockTxManager) UpdateTaskStatus(accountID identity.CentID, id transactions.TxID, status transactions.Status, taskName, message string) error { +func (m MockTxManager) UpdateTaskStatus(accountID identity.DID, id transactions.TxID, status transactions.Status, taskName, message string) error { panic("implement me") } -func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID transactions.TxID, desc string, work func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { +func (m MockTxManager) ExecuteWithinTX(ctx context.Context, accountID identity.DID, existingTxID transactions.TxID, desc string, work func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { args := m.Called(ctx, accountID, existingTxID, desc, work) return args.Get(0).(transactions.TxID), args.Get(1).(chan bool), args.Error(2) } -func (MockTxManager) GetTransaction(accountID identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { +func (MockTxManager) GetTransaction(accountID identity.DID, id transactions.TxID) (*transactions.Transaction, error) { panic("implement me") } -func (MockTxManager) GetTransactionStatus(accountID identity.CentID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { +func (MockTxManager) GetTransactionStatus(accountID identity.DID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { panic("implement me") } -func (MockTxManager) WaitForTransaction(accountID identity.CentID, txID transactions.TxID) error { +func (MockTxManager) WaitForTransaction(accountID identity.DID, txID transactions.TxID) error { panic("implement me") } diff --git a/testingutils/utils.go b/testingutils/utils.go index de1646d2f..261db4060 100644 --- a/testingutils/utils.go +++ b/testingutils/utils.go @@ -1,4 +1,4 @@ -// +build integration unit +// +build integration unit testworld package testingutils diff --git a/testworld/config_test.go b/testworld/config_test.go index 3f075ed29..6d439a8bb 100644 --- a/testworld/config_test.go +++ b/testworld/config_test.go @@ -14,6 +14,7 @@ func TestConfig_Happy(t *testing.T) { // check charlies node config res := getNodeConfig(charlie.httpExpect, charlie.id.String(), http.StatusOK) accountID := res.Value("main_identity").Path("$.identity_id").String().NotEmpty() + accountID.Equal(charlie.id.String()) // check charlies main account diff --git a/testworld/park.go b/testworld/park.go index 2b7f21db1..14ce83cad 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -45,7 +45,7 @@ const defaultP2PTimeout = "10s" type hostTestSuite struct { name string host *host - id identity.CentID + id identity.DID httpExpect *httpexpect.Expect } @@ -153,7 +153,7 @@ func (r *hostManager) init(createConfig bool) error { if err != nil { return err } - fmt.Printf("CentID for %s is %s \n", name, i) + fmt.Printf("DID for %s is %s \n", name, i) if createConfig { _ = host.createAccounts(r.getHostTestSuite(&testing.T{}, host.name).httpExpect) } @@ -234,7 +234,8 @@ type host struct { txPoolAccess bool smartContractAddrs *config.SmartContractAddresses config config.Configuration - identity identity.Identity + identity identity.DID + idService identity.ServiceDID node *node.Node canc context.CancelFunc createConfig bool @@ -269,7 +270,7 @@ func newHost( func (h *host) init() error { if h.createConfig { - err := cmd.CreateConfigDeprecated(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) + err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) if err != nil { return err } @@ -285,16 +286,12 @@ func (h *host) init() error { return err } h.config = h.bootstrappedCtx[bootstrap.BootstrappedConfig].(config.Configuration) - idService := h.bootstrappedCtx[identity.BootstrappedIDService].(identity.Service) idBytes, err := h.config.GetIdentityID() if err != nil { return err } - id, err := identity.ToCentID(idBytes) - if err != nil { - return err - } - h.identity, err = idService.LookupIdentityForID(id) + h.identity = identity.NewDIDFromBytes(idBytes) + h.idService = h.bootstrappedCtx[identity.BootstrappedDIDService].(identity.ServiceDID) if err != nil { return err } @@ -378,14 +375,14 @@ func (h *host) createAccounts(e *httpexpect.Expect) error { } // create 3 accounts for i := 0; i < 3; i++ { - res := generateAccount(e, h.identity.CentID().String(), http.StatusOK) + res := generateAccount(e, h.identity.String(), http.StatusOK) res.Value("identity_id").String().NotEmpty() } return nil } func (h *host) loadAccounts(e *httpexpect.Expect) error { - res := getAllAccounts(e, h.identity.CentID().String(), http.StatusOK) + res := getAllAccounts(e, h.identity.String(), http.StatusOK) accounts := res.Value("data").Array() accIDs := getAccounts(accounts) keys := make([]string, 0, len(accIDs)) @@ -400,12 +397,12 @@ func (h *host) createHttpExpectation(t *testing.T) *httpexpect.Expect { return createInsecureClientWithExpect(t, fmt.Sprintf("https://localhost:%d", h.config.GetServerPort())) } -func (h *host) id() (identity.CentID, error) { - return h.identity.CentID(), nil +func (h *host) id() (identity.DID, error) { + return h.identity, nil } func (h *host) p2pURL() (string, error) { - lastB58Key, err := h.identity.CurrentP2PKey() + lastB58Key, err := h.idService.CurrentP2PKey(h.identity) if err != nil { return "", err } diff --git a/testworld/start_test.go b/testworld/start_test.go index d141c1cb2..e313a321f 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils" + "github.com/centrifuge/go-centrifuge/config" ) @@ -31,14 +33,14 @@ func TestMain(m *testing.M) { } if c.RunPOAGeth { // NOTE that we don't bring down geth automatically right now because this must only be used for local testing purposes - startPOAGeth() + testingutils.StartPOAGeth() } if c.RunMigrations { - runSmartContractMigrations() + testingutils.RunSmartContractMigrations() } var contractAddresses *config.SmartContractAddresses if c.Network == "testing" { - contractAddresses = getSmartContractAddresses() + contractAddresses = testingutils.GetSmartContractAddresses() } doctorFord = newHostManager(c.EthNodeURL, c.AccountKeyPath, c.AccountPassword, c.Network, configName, c.TxPoolAccess, contractAddresses) err = doctorFord.init(c.CreateHostConfigs) diff --git a/testworld/util.go b/testworld/util.go deleted file mode 100644 index ea2f30d03..000000000 --- a/testworld/util.go +++ /dev/null @@ -1,108 +0,0 @@ -// +build testworld - -package testworld - -import ( - "io/ioutil" - "os" - "os/exec" - "path" - - "fmt" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/savaki/jq" -) - -// startPOAGeth runs the proof of authority geth for tests -func startPOAGeth() { - // don't run if its already running - if IsPOAGethRunning() { - return - } - projDir := getProjectDir() - gethRunScript := path.Join(projDir, "build", "scripts", "docker", "run.sh") - o, err := exec.Command(gethRunScript, "dev").Output() - if err != nil { - log.Fatal(err) - } - fmt.Printf("%s", string(o)) -} - -// runSmartContractMigrations migrates smart contracts to localgeth -func runSmartContractMigrations() { - projDir := getProjectDir() - migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") - _, err := exec.Command(migrationScript, projDir).Output() - if err != nil { - log.Fatal(err) - } -} - -// getSmartContractAddresses finds migrated smart contract addresses for localgeth -func getSmartContractAddresses() *config.SmartContractAddresses { - dat, err := findContractDeployJSON() - if err != nil { - panic(err) - } - idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") - idRegistryAddrOp := getOpForContract(".contracts.IdentityRegistry.address") - anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") - payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") - return &config.SmartContractAddresses{ - IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), - IdentityRegistryAddr: getOpAddr(idRegistryAddrOp, dat), - AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), - PaymentObligationAddr: getOpAddr(payObAddrOp, dat), - } -} - -func findContractDeployJSON() ([]byte, error) { - projDir := getProjectDir() - deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") - dat, err := ioutil.ReadFile(deployJSONFile) - if err != nil { - return nil, err - } - return dat, nil -} - -func getOpAddr(addrOp jq.Op, dat []byte) string { - addr, err := addrOp.Apply(dat) - if err != nil { - panic(err) - } - - // remove extra quotes inside the string - addrStr := string(addr) - if len(addrStr) > 0 && addrStr[0] == '"' { - addrStr = addrStr[1:] - } - if len(addrStr) > 0 && addrStr[len(addrStr)-1] == '"' { - addrStr = addrStr[:len(addrStr)-1] - } - return addrStr -} - -func getOpForContract(selector string) jq.Op { - addrOp, err := jq.Parse(selector) - if err != nil { - panic(err) - } - return addrOp -} - -func getProjectDir() string { - gp := os.Getenv("GOPATH") - projDir := path.Join(gp, "src", "github.com", "centrifuge", "go-centrifuge") - return projDir -} - -func IsPOAGethRunning() bool { - cmd := "docker ps -a --filter \"name=geth-node\" --filter \"status=running\" --quiet" - o, err := exec.Command("/bin/sh", "-c", cmd).Output() - if err != nil { - panic(err) - } - return len(o) != 0 -} diff --git a/transactions/transaction.go b/transactions/transaction.go index b7a4f5b50..c84943c70 100644 --- a/transactions/transaction.go +++ b/transactions/transaction.go @@ -98,7 +98,7 @@ func TxIDEqual(t1 TxID, t2 TxID) bool { // Transaction contains details of transaction. type Transaction struct { ID TxID - CID identity.CentID + DID identity.DID Description string // Status is the overall status of the transaction @@ -128,10 +128,10 @@ func (t *Transaction) Type() reflect.Type { } // NewTransaction returns a new transaction with a pending state -func NewTransaction(identity identity.CentID, description string) *Transaction { +func NewTransaction(identity identity.DID, description string) *Transaction { return &Transaction{ ID: NewTxID(), - CID: identity, + DID: identity, Description: description, Status: Pending, TaskStatus: make(map[string]Status), @@ -147,16 +147,16 @@ type Config interface { // Manager is a manager for centrifuge transactions. type Manager interface { // ExecuteWithinTX executes the given unit of work within a transaction - ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID TxID, desc string, work func(accountID identity.CentID, txID TxID, txMan Manager, err chan<- error)) (txID TxID, done chan bool, err error) - GetTransaction(accountID identity.CentID, id TxID) (*Transaction, error) - UpdateTaskStatus(accountID identity.CentID, id TxID, status Status, taskName, message string) error - GetTransactionStatus(accountID identity.CentID, id TxID) (*transactionspb.TransactionStatusResponse, error) - WaitForTransaction(accountID identity.CentID, txID TxID) error + ExecuteWithinTX(ctx context.Context, accountID identity.DID, existingTxID TxID, desc string, work func(accountID identity.DID, txID TxID, txMan Manager, err chan<- error)) (txID TxID, done chan bool, err error) + GetTransaction(accountID identity.DID, id TxID) (*Transaction, error) + UpdateTaskStatus(accountID identity.DID, id TxID, status Status, taskName, message string) error + GetTransactionStatus(accountID identity.DID, id TxID) (*transactionspb.TransactionStatusResponse, error) + WaitForTransaction(accountID identity.DID, txID TxID) error GetDefaultTaskTimeout() time.Duration } // Repository can be implemented by a type that handles storage for transactions. type Repository interface { - Get(cid identity.CentID, id TxID) (*Transaction, error) + Get(cid identity.DID, id TxID) (*Transaction, error) Save(transaction *Transaction) error } diff --git a/transactions/txv1/base_task.go b/transactions/txv1/base_task.go index 65c629437..bd0a23c5e 100644 --- a/transactions/txv1/base_task.go +++ b/transactions/txv1/base_task.go @@ -37,7 +37,7 @@ func (b *BaseTask) ParseTransactionID(taskTypeName string, kwargs map[string]int } // UpdateTransaction add a new log and updates the status of the transaction based on the error. -func (b *BaseTask) UpdateTransaction(accountID identity.CentID, taskTypeName string, err error) error { +func (b *BaseTask) UpdateTransaction(accountID identity.DID, taskTypeName string, err error) error { if err == gocelery.ErrTaskRetryable { return err } diff --git a/transactions/txv1/base_task_test.go b/transactions/txv1/base_task_test.go index 86b1349fc..893e5b24c 100644 --- a/transactions/txv1/base_task_test.go +++ b/transactions/txv1/base_task_test.go @@ -5,8 +5,9 @@ package txv1 import ( "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/transactions" "github.com/stretchr/testify/assert" @@ -15,7 +16,7 @@ import ( func TestDocumentAnchorTask_updateTransaction(t *testing.T) { task := new(BaseTask) - accountID := identity.RandomCentID() + accountID := testingidentity.GenerateRandomDID() name := "some task" task.TxID = transactions.NewTxID() task.TxManager = NewManager(&mockConfig{}, NewRepository(ctx[storage.BootstrappedDB].(storage.Repository))) diff --git a/transactions/txv1/handler.go b/transactions/txv1/handler.go index 9db8bebb6..4bcdfee96 100644 --- a/transactions/txv1/handler.go +++ b/transactions/txv1/handler.go @@ -53,10 +53,6 @@ func (h grpcHandler) GetTransactionStatus(ctx context.Context, req *transactions if err != nil { return nil, ErrInvalidAccountID } - cid, err := identity.ToCentID(accID) - if err != nil { - return nil, ErrInvalidAccountID - } - return h.srv.GetTransactionStatus(cid, id) + return h.srv.GetTransactionStatus(identity.NewDIDFromBytes(accID), id) } diff --git a/transactions/txv1/handler_test.go b/transactions/txv1/handler_test.go index 8432a9601..3ccf1bf14 100644 --- a/transactions/txv1/handler_test.go +++ b/transactions/txv1/handler_test.go @@ -36,7 +36,7 @@ func TestGRPCHandler_GetTransactionStatus(t *testing.T) { // missing err tcs, _ := cService.GetAllAccounts() accID, _ := tcs[0].GetIdentityID() - cid, err := identity.ToCentID(accID) + cid := identity.NewDIDFromBytes(accID) tx := transactions.NewTransaction(cid, "") req.TransactionId = tx.ID.String() res, err = h.GetTransactionStatus(ctxl, req) diff --git a/transactions/txv1/manager.go b/transactions/txv1/manager.go index a9e9805d8..9c1c6ce35 100644 --- a/transactions/txv1/manager.go +++ b/transactions/txv1/manager.go @@ -23,7 +23,7 @@ type extendedManager interface { // createTransaction only exposed for testing within package. // DO NOT use this outside of the package, use ExecuteWithinTX to initiate a transaction with management. - createTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) + createTransaction(accountID identity.DID, desc string) (*transactions.Transaction, error) } // NewManager returns a Manager implementation. @@ -42,7 +42,7 @@ func (s *manager) GetDefaultTaskTimeout() time.Duration { return s.config.GetEthereumContextWaitTimeout() } -func (s *manager) UpdateTaskStatus(accountID identity.CentID, id transactions.TxID, status transactions.Status, taskName, message string) error { +func (s *manager) UpdateTaskStatus(accountID identity.DID, id transactions.TxID, status transactions.Status, taskName, message string) error { tx, err := s.GetTransaction(accountID, id) if err != nil { return err @@ -55,7 +55,7 @@ func (s *manager) UpdateTaskStatus(accountID identity.CentID, id transactions.Tx } // ExecuteWithinTX executes a transaction within a transaction. -func (s *manager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID, existingTxID transactions.TxID, desc string, work func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { +func (s *manager) ExecuteWithinTX(ctx context.Context, accountID identity.DID, existingTxID transactions.TxID, desc string, work func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, err chan<- error)) (txID transactions.TxID, done chan bool, err error) { t, err := s.repo.Get(accountID, existingTxID) if err != nil { t = transactions.NewTransaction(accountID, desc) @@ -90,7 +90,7 @@ func (s *manager) ExecuteWithinTX(ctx context.Context, accountID identity.CentID log.Error(e) } case <-ctx.Done(): - msg := fmt.Sprintf("Transaction %s for account %s with description \"%s\" is stopped because of context close", t.ID.String(), t.CID, t.Description) + msg := fmt.Sprintf("Transaction %s for account %s with description \"%s\" is stopped because of context close", t.ID.String(), t.DID, t.Description) log.Warningf(msg) tempTx, err := s.repo.Get(accountID, t.ID) if err != nil { @@ -118,19 +118,19 @@ func (s *manager) saveTransaction(tx *transactions.Transaction) error { } // GetTransaction returns the transaction associated with identity and id. -func (s *manager) GetTransaction(accountID identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { +func (s *manager) GetTransaction(accountID identity.DID, id transactions.TxID) (*transactions.Transaction, error) { return s.repo.Get(accountID, id) } // createTransaction creates a new transaction and saves it to the DB. -func (s *manager) createTransaction(accountID identity.CentID, desc string) (*transactions.Transaction, error) { +func (s *manager) createTransaction(accountID identity.DID, desc string) (*transactions.Transaction, error) { tx := transactions.NewTransaction(accountID, desc) return tx, s.saveTransaction(tx) } // WaitForTransaction blocks until transaction status is moved from pending state. // Note: use it with caution as this will block. -func (s *manager) WaitForTransaction(accountID identity.CentID, txID transactions.TxID) error { +func (s *manager) WaitForTransaction(accountID identity.DID, txID transactions.TxID) error { // TODO change this to use a pre-saved done channel from ExecuteWithinTX, instead of a for loop, may require significant refactoring to handle the case of restarted node for { resp, err := s.GetTransactionStatus(accountID, txID) @@ -151,7 +151,7 @@ func (s *manager) WaitForTransaction(accountID identity.CentID, txID transaction } // GetTransactionStatus returns the transaction status associated with identity and id. -func (s *manager) GetTransactionStatus(accountID identity.CentID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { +func (s *manager) GetTransactionStatus(accountID identity.DID, id transactions.TxID) (*transactionspb.TransactionStatusResponse, error) { tx, err := s.GetTransaction(accountID, id) if err != nil { return nil, err diff --git a/transactions/txv1/manager_test.go b/transactions/txv1/manager_test.go index 903e646b4..00b2587c9 100644 --- a/transactions/txv1/manager_test.go +++ b/transactions/txv1/manager_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/transactions" @@ -21,9 +23,9 @@ func (mockConfig) GetEthereumContextWaitTimeout() time.Duration { } func TestService_ExecuteWithinTX_happy(t *testing.T) { - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() srv := ctx[transactions.BootstrappedService].(transactions.Manager) - tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { err <- nil }) <-done @@ -35,9 +37,9 @@ func TestService_ExecuteWithinTX_happy(t *testing.T) { } func TestService_ExecuteWithinTX_err(t *testing.T) { - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() srv := ctx[transactions.BootstrappedService].(transactions.Manager) - tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { + tid, done, err := srv.ExecuteWithinTX(context.Background(), cid, transactions.NilTxID(), "", func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { err <- errors.New("dummy") }) <-done @@ -49,10 +51,10 @@ func TestService_ExecuteWithinTX_err(t *testing.T) { } func TestService_ExecuteWithinTX_ctxDone(t *testing.T) { - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() srv := ctx[transactions.BootstrappedService].(transactions.Manager) ctx, canc := context.WithCancel(context.Background()) - tid, done, err := srv.ExecuteWithinTX(ctx, cid, transactions.NilTxID(), "", func(accountID identity.CentID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { + tid, done, err := srv.ExecuteWithinTX(ctx, cid, transactions.NilTxID(), "", func(accountID identity.DID, txID transactions.TxID, txMan transactions.Manager, err chan<- error) { // doing nothing }) canc() @@ -69,7 +71,7 @@ func TestService_GetTransaction(t *testing.T) { repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) srv := ctx[transactions.BootstrappedService].(transactions.Manager) - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() bytes := utils.RandomSlice(identity.CentIDLength) assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) txn := transactions.NewTransaction(cid, "Some transaction") @@ -109,23 +111,23 @@ func TestService_GetTransaction(t *testing.T) { func TestService_CreateTransaction(t *testing.T) { srv := ctx[transactions.BootstrappedService].(extendedManager) - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() tx, err := srv.createTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) - assert.Equal(t, cid.String(), tx.CID.String()) + assert.Equal(t, cid.String(), tx.DID.String()) } func TestService_WaitForTransaction(t *testing.T) { srv := ctx[transactions.BootstrappedService].(extendedManager) repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() // failed tx, err := srv.createTransaction(cid, "test") assert.NoError(t, err) assert.NotNil(t, tx) - assert.Equal(t, cid.String(), tx.CID.String()) + assert.Equal(t, cid.String(), tx.DID.String()) tx.Status = transactions.Failed assert.NoError(t, repo.Save(tx)) assert.Error(t, srv.WaitForTransaction(cid, tx.ID)) diff --git a/transactions/txv1/repository.go b/transactions/txv1/repository.go index 28307afb2..ae98e5665 100644 --- a/transactions/txv1/repository.go +++ b/transactions/txv1/repository.go @@ -21,7 +21,7 @@ func NewRepository(repo storage.Repository) transactions.Repository { // getKey appends identity with id. // With identity coming at first, we can even fetch transactions belonging to specific identity through prefix. -func getKey(cid identity.CentID, id transactions.TxID) ([]byte, error) { +func getKey(cid identity.DID, id transactions.TxID) ([]byte, error) { if transactions.TxIDEqual(transactions.NilTxID(), id) { return nil, errors.New("transaction ID is not valid") } @@ -30,7 +30,7 @@ func getKey(cid identity.CentID, id transactions.TxID) ([]byte, error) { } // Get returns the transaction associated with identity and id. -func (r *txRepository) Get(cid identity.CentID, id transactions.TxID) (*transactions.Transaction, error) { +func (r *txRepository) Get(cid identity.DID, id transactions.TxID) (*transactions.Transaction, error) { key, err := getKey(cid, id) if err != nil { return nil, errors.NewTypedError(transactions.ErrKeyConstructionFailed, err) @@ -46,7 +46,7 @@ func (r *txRepository) Get(cid identity.CentID, id transactions.TxID) (*transact // Save saves the transaction to the repository. func (r *txRepository) Save(tx *transactions.Transaction) error { - key, err := getKey(tx.CID, tx.ID) + key, err := getKey(tx.DID, tx.ID) if err != nil { return errors.NewTypedError(transactions.ErrKeyConstructionFailed, err) } diff --git a/transactions/txv1/repository_test.go b/transactions/txv1/repository_test.go index 4fa198be2..8ddde57d3 100644 --- a/transactions/txv1/repository_test.go +++ b/transactions/txv1/repository_test.go @@ -6,6 +6,8 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" @@ -29,7 +31,8 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, Bootstrapper{}, } - ctx[identity.BootstrappedIDService] = &testingcommons.MockIDService{} + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} + ctx[identity.BootstrappedDIDService] = &testingcommons.MockIdentityService{} bootstrap.RunTestBootstrappers(ibootstappers, ctx) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) @@ -37,7 +40,7 @@ func TestMain(m *testing.M) { } func Test_getKey(t *testing.T) { - cid := identity.RandomCentID() + cid := testingidentity.GenerateRandomDID() id := transactions.NilTxID() // empty id @@ -52,14 +55,14 @@ func Test_getKey(t *testing.T) { } func TestRepository(t *testing.T) { - cid := identity.RandomCentID() - bytes := utils.RandomSlice(identity.CentIDLength) - assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) + cid := testingidentity.GenerateRandomDID() + bytes := utils.RandomSlice(identity.DIDLength) + assert.Equal(t, identity.DIDLength, copy(cid[:], bytes)) repo := ctx[transactions.BootstrappedRepo].(transactions.Repository) tx := transactions.NewTransaction(cid, "Some transaction") assert.NotNil(t, tx.ID) - assert.NotNil(t, tx.CID) + assert.NotNil(t, tx.DID) assert.Equal(t, transactions.Pending, tx.Status) // get tx from repo @@ -75,6 +78,6 @@ func TestRepository(t *testing.T) { tx, err = repo.Get(cid, tx.ID) assert.Nil(t, err) assert.NotNil(t, tx) - assert.Equal(t, cid, tx.CID) + assert.Equal(t, cid, tx.DID) assert.Equal(t, transactions.Success, tx.Status) } From c82033c0fb7d0a96285aa7c77d0afaa65950b520 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Mon, 25 Feb 2019 18:22:12 +0100 Subject: [PATCH 198/220] Add prefixes to Signing and CoreDoc trees (#770) * Add prefixes to Signing and CoreDoc trees * remove commented * Fix tests * Fix tests * Lint * review * Review comments * Fix test * Fix test --- documents/documents_test/service_test.go | 6 +- documents/invoice/model.go | 7 ++- documents/invoice/model_test.go | 2 +- documents/model.go | 70 +++++++++++++++--------- documents/model_test.go | 50 +++++++++++++---- documents/purchaseorder/model.go | 7 ++- documents/purchaseorder/model_test.go | 2 +- p2p/client.go | 15 ++--- p2p/receiver/handler_integration_test.go | 2 +- testingutils/documents/documents.go | 2 +- testworld/proof_test.go | 4 +- 11 files changed, 106 insertions(+), 61 deletions(-) diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index 6475ffd4e..eb0d99e96 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -99,7 +99,7 @@ func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, return nil, err } - cds, err := documents.GenerateNewSalts(corDocMod.Document, "", nil) + cds, err := documents.GenerateCoreDocSalts(corDocMod.Document) assert.Nil(t, err) corDocMod.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cds) @@ -198,7 +198,7 @@ func TestService_CreateProofs(t *testing.T) { assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() @@ -247,7 +247,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index a9a60f037..398f32f67 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -21,7 +21,8 @@ import ( const prefix string = "invoice" -var compactPrefix = []byte{1, 0, 0, 0} +// tree prefixes use the first byte of a 4 byte slice by convention +func compactPrefix() []byte { return []byte{3, 0, 0, 0} } // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { @@ -258,7 +259,7 @@ func (i *Invoice) loadFromP2PProtobuf(invoiceData *invoicepb.InvoiceData) { // getInvoiceSalts returns the invoice salts. Initialises if not present func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) (*proofs.Salts, error) { if i.InvoiceSalts == nil { - invoiceSalts, err := documents.GenerateNewSalts(invoiceData, prefix, compactPrefix) + invoiceSalts, err := documents.GenerateNewSalts(invoiceData, prefix, compactPrefix()) if err != nil { return nil, errors.New("getInvoiceSalts error %v", err) } @@ -374,7 +375,7 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { if err != nil { return nil, err } - t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix) + t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix()) err = t.AddLeavesFromDocument(invProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index fa38f5f9d..c402971f0 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -275,7 +275,7 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { func TestInvoiceModel_createProofs(t *testing.T) { i, err := createMockInvoice(t) assert.Nil(t, err) - proof, err := i.CreateProofs([]string{"invoice.invoice_number", "collaborators[0]", "document_type"}) + proof, err := i.CreateProofs([]string{"invoice.invoice_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) tree, err := i.CoreDocumentModel.GetDocumentRootTree() diff --git a/documents/model.go b/documents/model.go index ccabc86a6..7397a2c5f 100644 --- a/documents/model.go +++ b/documents/model.go @@ -3,6 +3,7 @@ package documents import ( "bytes" "crypto/sha256" + "encoding/binary" "fmt" "strings" @@ -31,14 +32,25 @@ const ( SignaturesField = "signatures" // SigningRootField represents the signature root property of a tree SigningRootField = "signing_root" + // CDTreePrefix is the human readable prefix for core doc tree props + CDTreePrefix = "cd_tree" + // SigningTreePrefix is the human readable prefix for signing tree props + SigningTreePrefix = "signing_tree" ) -var compactProperties = map[string][]byte{ - CDRootField: {0, 0, 0, 7}, - DataRootField: {0, 0, 0, 5}, - DocumentTypeField: {0, 0, 0, 100}, - SignaturesField: {0, 0, 0, 6}, - SigningRootField: {0, 0, 0, 10}, +func compactProperties(key string) []byte { + m := map[string][]byte{ + CDRootField: {0, 0, 0, 7}, + DataRootField: {0, 0, 0, 5}, + DocumentTypeField: {0, 0, 0, 100}, + SignaturesField: {0, 0, 0, 6}, + SigningRootField: {0, 0, 0, 10}, + + // tree prefixes use the first byte of a 4 byte slice by convention + CDTreePrefix: {1, 0, 0, 0}, + SigningTreePrefix: {2, 0, 0, 0}, + } + return m[key] } // Model is an interface to abstract away model specificness like invoice or purchaseOrder @@ -218,7 +230,7 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ return nil, errors.New("createProofs error %v", err) } - cdtree, err := m.GetDocumentTree() + cdtree, err := m.GetCoreDocumentTree() if err != nil { return nil, errors.New("createProofs error %v", err) } @@ -250,10 +262,10 @@ func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields [ return proofs, nil } -// GetDocumentTree returns the merkle tree for the coredoc root -func (m *CoreDocumentModel) GetDocumentTree() (tree *proofs.DocumentTree, err error) { +// GetCoreDocumentTree returns the merkle tree for the coredoc root +func (m *CoreDocumentModel) GetCoreDocumentTree() (tree *proofs.DocumentTree, err error) { document := m.Document - tree = NewDefaultTree(ConvertToProofSalts(m.Document.CoredocumentSalts)) + tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(m.Document.CoredocumentSalts), CDTreePrefix, compactProperties(CDTreePrefix)) err = tree.AddLeavesFromDocument(document) if err != nil { return nil, err @@ -262,9 +274,10 @@ func (m *CoreDocumentModel) GetDocumentTree() (tree *proofs.DocumentTree, err er if document.EmbeddedData == nil { return nil, errors.New("EmbeddedData cannot be nil when generating signing tree") } + prefixProp := NewLeafProperty(CDTreePrefix, compactProperties(CDTreePrefix)) // Adding document type as it is an excluded field in the tree documentTypeNode := proofs.LeafNode{ - Property: NewLeafProperty(DocumentTypeField, compactProperties[DocumentTypeField]), + Property: prefixProp.FieldProp(DocumentTypeField, binary.LittleEndian.Uint32(compactProperties(DocumentTypeField))), Salt: make([]byte, 32), Value: []byte(document.EmbeddedData.TypeUrl), } @@ -290,21 +303,23 @@ func (m *CoreDocumentModel) GetDocumentTree() (tree *proofs.DocumentTree, err er // GetDocumentSigningTree returns the merkle tree for the signing root func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proofs.DocumentTree, err error) { // coredoc tree - coreDocTree, err := m.GetDocumentTree() + coreDocTree, err := m.GetCoreDocumentTree() if err != nil { return nil, err } // create the signing tree with data root and coredoc root as siblings - tree = NewDefaultTree(ConvertToProofSalts(m.Document.CoredocumentSalts)) + tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(m.Document.CoredocumentSalts), SigningTreePrefix, compactProperties(SigningTreePrefix)) + prefixProp := NewLeafProperty(SigningTreePrefix, compactProperties(SigningTreePrefix)) + err = tree.AddLeaves([]proofs.LeafNode{ { - Property: NewLeafProperty(DataRootField, compactProperties[DataRootField]), + Property: prefixProp.FieldProp(DataRootField, binary.LittleEndian.Uint32(compactProperties(DataRootField))), Hash: dataRoot, Hashed: true, }, { - Property: NewLeafProperty(CDRootField, compactProperties[CDRootField]), + Property: prefixProp.FieldProp(CDRootField, binary.LittleEndian.Uint32(compactProperties(CDRootField))), Hash: coreDocTree.RootHash(), Hashed: true, }, @@ -328,13 +343,13 @@ func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, er tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties[SigningRootField])}) + err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties(SigningRootField))}) if err != nil { return nil, err } // For every signature we create a LeafNode - sigProperty := NewLeafProperty(SignaturesField, compactProperties[SignaturesField]) + sigProperty := NewLeafProperty(SignaturesField, compactProperties(SignaturesField)) sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) sigLengthNode := proofs.LeafNode{ Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), @@ -398,7 +413,7 @@ func (m *CoreDocumentModel) getDataProofHashes(dataRoot []byte) (hashes [][]byte return } - signingProof, err := tree.CreateProof("data_root") + signingProof, err := tree.CreateProof(SigningTreePrefix + ".data_root") if err != nil { return } @@ -448,6 +463,11 @@ func (m *CoreDocumentModel) AccountCanRead(account identity.DID) bool { }, coredocumentpb.Action_ACTION_READ, coredocumentpb.Action_ACTION_READ_SIGN) } +// GenerateCoreDocSalts generates coredoc salts +func GenerateCoreDocSalts(document proto.Message) (*proofs.Salts, error) { + return GenerateNewSalts(document, CDTreePrefix, compactProperties(CDTreePrefix)) +} + // GenerateNewSalts generates salts for new document func GenerateNewSalts(document proto.Message, prefix string, compactPrefix []byte) (*proofs.Salts, error) { docSalts := &proofs.Salts{} @@ -490,7 +510,7 @@ func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salt // setCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet func (m *CoreDocumentModel) setCoreDocumentSalts() error { if m.Document.CoredocumentSalts == nil { - pSalts, err := GenerateNewSalts(m.Document, "", nil) + pSalts, err := GenerateCoreDocSalts(m.Document) if err != nil { return err } @@ -863,7 +883,7 @@ func (m *CoreDocumentModel) GetNFTProofs( return nil, errors.New("failed to generate signing root proofs: %v", err) } - cdtree, err := m.GetDocumentTree() + cdtree, err := m.GetCoreDocumentTree() if err != nil { return nil, errors.New("failed to generate document tree: %v", err) } @@ -905,9 +925,9 @@ func getReadAccessProofKeys(m *CoreDocumentModel, registry common.Address, token } return []string{ - fmt.Sprintf("read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role - fmt.Sprintf("roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists - fmt.Sprintf("read_rules[%d].action", rridx), // proof that this read rule has read access + fmt.Sprintf(CDTreePrefix+".read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role + fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists + fmt.Sprintf(CDTreePrefix+".read_rules[%d].action", rridx), // proof that this read rule has read access }, nil } @@ -918,7 +938,7 @@ func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) ( } key := hexutil.Encode(nft.RegistryId) - return fmt.Sprintf("nfts[%s]", key), nil + return fmt.Sprintf(CDTreePrefix+".nfts[%s]", key), nil } func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.DID) (pk string, err error) { @@ -932,5 +952,5 @@ func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account ident return pk, ErrNFTRoleMissing } - return fmt.Sprintf("roles[%s].collaborators[%d]", hexutil.Encode(role.RoleKey), idx), nil + return fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[%d]", hexutil.Encode(role.RoleKey), idx), nil } diff --git a/documents/model_test.go b/documents/model_test.go index 28979141b..8d2912f91 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -271,10 +271,10 @@ func TestGetDocumentSigningTree(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, tree) - _, leaf := tree.GetLeafByProperty("data_root") + _, leaf := tree.GetLeafByProperty(SigningTreePrefix + ".data_root") assert.NotNil(t, leaf) - _, leaf = tree.GetLeafByProperty("cd_root") + _, leaf = tree.GetLeafByProperty(SigningTreePrefix + ".cd_root") assert.NotNil(t, leaf) } @@ -288,6 +288,28 @@ func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { assert.Nil(t, tree) } +func TestCoreDocumentTree(t *testing.T) { + dm := NewCoreDocModel() + cd := dm.Document + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + cd.EmbeddedData = docAny + cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} + err := dm.setCoreDocumentSalts() + assert.NoError(t, err) + tree1, err := dm.GetCoreDocumentTree() + assert.NoError(t, err) + assert.NotNil(t, tree1) + root1 := tree1.RootHash() + + tree2, err := dm.GetCoreDocumentTree() + assert.NoError(t, err) + root2 := tree2.RootHash() + assert.Equal(t, root1, root2) +} + // TestGetDocumentRootTree tests that the documentroottree is properly calculated func TestGetDocumentRootTree(t *testing.T) { dm := NewCoreDocModel() @@ -296,7 +318,7 @@ func TestGetDocumentRootTree(t *testing.T) { tree, err := dm.GetDocumentRootTree() // Manually constructing the two node tree: - signaturesLengthLeaf := sha256.Sum256(append(append(compactProperties[SignaturesField], []byte{48}...), make([]byte, 32)...)) + signaturesLengthLeaf := sha256.Sum256(append(append(compactProperties(SignaturesField), []byte{48}...), make([]byte, 32)...)) expectedRootHash := sha256.Sum256(append(dm.Document.SigningRoot, signaturesLengthLeaf[:]...)) assert.Nil(t, err) assert.Equal(t, expectedRootHash[:], tree.RootHash()) @@ -327,7 +349,7 @@ func TestCreateProofs(t *testing.T) { assert.NoError(t, err) err = dm.CalculateDocumentRoot() assert.NoError(t, err) - cdTree, err := dm.GetDocumentTree() + cdTree, err := dm.GetCoreDocumentTree() assert.NoError(t, err) tests := []struct { fieldName string @@ -340,7 +362,7 @@ func TestCreateProofs(t *testing.T) { 3, }, { - "document_identifier", + CDTreePrefix + ".document_identifier", true, 6, }, @@ -350,7 +372,7 @@ func TestCreateProofs(t *testing.T) { 3, }, { - "collaborators[0]", + CDTreePrefix + ".collaborators[0]", true, 6, }, @@ -363,9 +385,15 @@ func TestCreateProofs(t *testing.T) { var l *proofs.LeafNode if test.fromCoreDoc { _, l = cdTree.GetLeafByProperty(test.fieldName) + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:4], cdTree.RootHash(), h) + assert.NoError(t, err) + assert.True(t, valid) } else { _, l = testTree.GetLeafByProperty(test.fieldName) assert.Contains(t, compactProps, l.Property.CompactName()) + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:1], testTree.RootHash(), h) + assert.NoError(t, err) + assert.True(t, valid) } valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) assert.NoError(t, err) @@ -575,9 +603,9 @@ func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { pfs, err = getReadAccessProofKeys(ndm, registry, tokenID) assert.NoError(t, err) assert.Len(t, pfs, 3) - assert.Equal(t, "read_rules[0].roles[0]", pfs[0]) - assert.Equal(t, fmt.Sprintf("roles[%s].nfts[0]", hexutil.Encode(make([]byte, 32, 32))), pfs[1]) - assert.Equal(t, "read_rules[0].action", pfs[2]) + assert.Equal(t, CDTreePrefix+".read_rules[0].roles[0]", pfs[0]) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(make([]byte, 32, 32))), pfs[1]) + assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[2]) } func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { @@ -595,7 +623,7 @@ func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { pf, err = getNFTUniqueProofKey(ndm.Document.Nfts, registry) assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf("nfts[%s]", hexutil.Encode(append(registry.Bytes(), make([]byte, 12, 12)...))), pf) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".nfts[%s]", hexutil.Encode(append(registry.Bytes(), make([]byte, 12, 12)...))), pf) } func TestCoreDocument_getRoleProofKey(t *testing.T) { @@ -616,7 +644,7 @@ func TestCoreDocument_getRoleProofKey(t *testing.T) { pf, err = getRoleProofKey(dm.Document.Roles, roleKey, account) assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf("roles[%s].collaborators[0]", hexutil.Encode(roleKey)), pf) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[0]", hexutil.Encode(roleKey)), pf) } func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index ed36845b5..fdab79ac6 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -22,7 +22,8 @@ import ( const prefix string = "po" -var compactPrefix = []byte{2, 0, 0, 0} +// tree prefixes use the first byte of a 4 byte slice by convention +func compactPrefix() []byte { return []byte{4, 0, 0, 0} } // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { @@ -253,7 +254,7 @@ func (p *PurchaseOrder) loadFromP2PProtobuf(data *purchaseorderpb.PurchaseOrderD // getPurchaseOrderSalts returns the purchase oder salts. Initialises if not present func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb.PurchaseOrderData) (*proofs.Salts, error) { if p.PurchaseOrderSalts == nil { - poSalts, err := documents.GenerateNewSalts(purchaseOrderData, prefix, compactPrefix) + poSalts, err := documents.GenerateNewSalts(purchaseOrderData, prefix, compactPrefix()) if err != nil { return nil, errors.New("getPOSalts error %v", err) } @@ -358,7 +359,7 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er if err != nil { return nil, err } - t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix) + t := documents.NewDefaultTreeWithPrefix(salts, prefix, compactPrefix()) err = t.AddLeavesFromDocument(poProto) if err != nil { return nil, errors.New("getDocumentDataTree error %v", err) diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index fb8d109cc..7c6204221 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -249,7 +249,7 @@ func TestPOModel_calculateDataRoot(t *testing.T) { func TestPOModel_createProofs(t *testing.T) { poModel, err := createMockPurchaseOrder(t) assert.Nil(t, err) - proof, err := poModel.CreateProofs([]string{"po.po_number", "collaborators[0]", "document_type"}) + proof, err := poModel.CreateProofs([]string{"po.po_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) tree, err := poModel.CoreDocumentModel.GetDocumentRootTree() diff --git a/p2p/client.go b/p2p/client.go index a6630ac9d..89cca7220 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,23 +4,18 @@ import ( "context" "fmt" - "github.com/centrifuge/go-centrifuge/identity/ideth" - - "github.com/centrifuge/go-centrifuge/documents" - - "github.com/centrifuge/go-centrifuge/p2p/common" - - "github.com/golang/protobuf/proto" - - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/code" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/version" + "github.com/golang/protobuf/proto" libp2pPeer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" ma "github.com/multiformats/go-multiaddr" diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 8e2070fb1..124036634 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -392,7 +392,7 @@ func updateDocumentForP2Phandler(t *testing.T, model *documents.CoreDocumentMode Value: serializedInv, } doc.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) - cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) + cdSalts, _ := documents.GenerateCoreDocSalts(doc) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 06bc340d4..c73346858 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -98,7 +98,7 @@ func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) *documen }, EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), } - cdSalts, _ := documents.GenerateNewSalts(doc, "", nil) + cdSalts, _ := documents.GenerateCoreDocSalts(doc) doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) dm := documents.NewCoreDocModel() mockModel := MockModel{ diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 29a85c2f3..1371b56e0 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -46,12 +46,12 @@ func proofWithMultipleFields_successful(t *testing.T, documentType string) { } func checkProof(objProof *httpexpect.Object, documentType string, docIdentifier string) { - compactPrefix := "0x01000000" // invoice prefix + compactPrefix := "0x03000000" // invoice prefix prop1 := "0000000f" // invoice.net_amount prop2 := "0000000d" // invoice.currency if documentType == typePO { - compactPrefix = "0x02000000" // po prefix + compactPrefix = "0x04000000" // po prefix prop1 = "0000000e" // po.net_amount prop2 = "0000000c" // po.currency } From 24bebe0d2ca72e62b144f07d5ab51d144c55f413 Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 25 Feb 2019 19:13:01 +0100 Subject: [PATCH 199/220] fix typos (#766) --- cmd/common_test.go | 2 +- identity/ideth/factory_integration_test.go | 2 +- identity/ideth/service_integration_test.go | 2 +- nft/ethereum_payment_obligation.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/common_test.go b/cmd/common_test.go index 40252d2bc..6e6b70506 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -73,7 +73,7 @@ func TestCreateConfig(t *testing.T) { assert.Nil(t, err, "did should exists") contractCode, err := client.GetEthClient().CodeAt(context.Background(), common.BytesToAddress(id), nil) assert.Nil(t, err, "should be successful to get the contract code") - assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be around 3378 bytes") // Keys exists // type KeyPurposeEthMsgAuth diff --git a/identity/ideth/factory_integration_test.go b/identity/ideth/factory_integration_test.go index 6972eefba..ad44af8ea 100644 --- a/identity/ideth/factory_integration_test.go +++ b/identity/ideth/factory_integration_test.go @@ -65,6 +65,6 @@ func TestCreateIdentity_successful(t *testing.T) { contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.ToAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") - assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be around 3378 bytes") } diff --git a/identity/ideth/service_integration_test.go b/identity/ideth/service_integration_test.go index 9c8330d69..883b928a1 100644 --- a/identity/ideth/service_integration_test.go +++ b/identity/ideth/service_integration_test.go @@ -60,7 +60,7 @@ func deployIdentityContract(t *testing.T) *id.DID { contractCode, err := client.GetEthClient().CodeAt(context.Background(), did.ToAddress(), nil) assert.Nil(t, err, "should be successful to get the contract code") - assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be arround 3378 bytes") + assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be around 3378 bytes") return did } diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 1b1113e0d..e9c64b05c 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -200,7 +200,7 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, isDone := <-done if !isDone { - // some problem occured in a child task + // some problem occurred in a child task errOut <- errors.New("update document failed for document %s and transaction %s", hexutil.Encode(req.DocumentID), txID) return } From af597f867f41fb98357648c8920dcac1934fb30f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 26 Feb 2019 12:05:59 +0100 Subject: [PATCH 200/220] Correcting convention for document trees (#779) * Correcting convention for document trees * Correcting convention for document trees --- documents/documents_test/service_test.go | 4 ++-- documents/invoice/model.go | 4 ++-- documents/purchaseorder/model.go | 4 ++-- testworld/proof_test.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index eb0d99e96..c5292036e 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -198,7 +198,7 @@ func TestService_CreateProofs(t *testing.T) { assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() @@ -247,7 +247,7 @@ func TestService_CreateProofsForVersion(t *testing.T) { assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) assert.Equal(t, olderVersion, proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) - assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) + assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 398f32f67..8a3f8a7ad 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -21,8 +21,8 @@ import ( const prefix string = "invoice" -// tree prefixes use the first byte of a 4 byte slice by convention -func compactPrefix() []byte { return []byte{3, 0, 0, 0} } +// tree prefixes for specific to documents use the second byte of a 4 byte slice by convention +func compactPrefix() []byte { return []byte{0, 1, 0, 0} } // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index fdab79ac6..f36cc93cc 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -22,8 +22,8 @@ import ( const prefix string = "po" -// tree prefixes use the first byte of a 4 byte slice by convention -func compactPrefix() []byte { return []byte{4, 0, 0, 0} } +// tree prefixes for specific to documents use the second byte of a 4 byte slice by convention +func compactPrefix() []byte { return []byte{0, 2, 0, 0} } // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { diff --git a/testworld/proof_test.go b/testworld/proof_test.go index 1371b56e0..d3ce607a2 100644 --- a/testworld/proof_test.go +++ b/testworld/proof_test.go @@ -46,12 +46,12 @@ func proofWithMultipleFields_successful(t *testing.T, documentType string) { } func checkProof(objProof *httpexpect.Object, documentType string, docIdentifier string) { - compactPrefix := "0x03000000" // invoice prefix + compactPrefix := "0x00010000" // invoice prefix prop1 := "0000000f" // invoice.net_amount prop2 := "0000000d" // invoice.currency if documentType == typePO { - compactPrefix = "0x04000000" // po prefix + compactPrefix = "0x00020000" // po prefix prop1 = "0000000e" // po.net_amount prop2 = "0000000c" // po.currency } From 33bdbf227129ddcf77edd11ad48f0cbefafba5a9 Mon Sep 17 00:00:00 2001 From: Charly Date: Tue, 26 Feb 2019 13:04:35 +0100 Subject: [PATCH 201/220] Feat/acls access token read acls (#752) --- documents/invoice/model.go | 3 +- documents/invoice/service.go | 3 + documents/model.go | 254 +++++++++++++++++++---- documents/model_test.go | 117 ++++++++++- documents/purchaseorder/model.go | 2 +- documents/purchaseorder/model_test.go | 9 +- documents/purchaseorder/service.go | 3 + documents/registry_test.go | 15 +- p2p/client_integration_test.go | 10 +- p2p/client_test.go | 9 +- p2p/receiver/handler.go | 36 +++- p2p/receiver/handler_integration_test.go | 147 +++++++++---- testingutils/documents/documents.go | 64 ++++-- utils/tools.go | 2 +- 14 files changed, 543 insertions(+), 131 deletions(-) diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 8a3f8a7ad..5edda6b67 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -155,8 +155,7 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload } collaborators := append([]string{self}, payload.Collaborators...) - - i.CoreDocumentModel, err = i.CoreDocumentModel.NewWithCollaborators(collaborators) + i.CoreDocumentModel, err = documents.NewWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 70aa89c55..9db88ea5c 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -79,6 +79,9 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv } invoiceModel := new(Invoice) + if invoiceModel.CoreDocumentModel == nil { + invoiceModel.CoreDocumentModel = documents.NewCoreDocModel() + } err = invoiceModel.InitInvoiceInput(payload, id.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) diff --git a/documents/model.go b/documents/model.go index 7397a2c5f..e0be73bc4 100644 --- a/documents/model.go +++ b/documents/model.go @@ -2,15 +2,22 @@ package documents import ( "bytes" + "context" "crypto/sha256" "encoding/binary" "fmt" "strings" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/golang/protobuf/ptypes/any" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -18,7 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" ) const ( @@ -32,6 +38,21 @@ const ( SignaturesField = "signatures" // SigningRootField represents the signature root property of a tree SigningRootField = "signing_root" + + // ErrZeroCollaborators error when no collaborators are passed + ErrZeroCollaborators = errors.Error("require at least one collaborator") + // nftByteCount is the length of combined bytes of registry and tokenID + nftByteCount = 52 + // ErrNFTRoleMissing errors when role to generate proof doesn't exist + ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") + //IDByteCount represents the byte length of valid identifiers + IDByteCount = 32 + + // ACLReadSign represents the read/sign action for ACLS + ACLReadSign = coredocumentpb.Action_ACTION_READ_SIGN + // ACLRead represents the read action for ACLS + ACLRead = coredocumentpb.Action_ACTION_READ + // CDTreePrefix is the human readable prefix for core doc tree props CDTreePrefix = "cd_tree" // SigningTreePrefix is the human readable prefix for signing tree props @@ -89,17 +110,6 @@ type CoreDocumentModel struct { TokenRegistry } -const ( - // ErrZeroCollaborators error when no collaborators are passed - ErrZeroCollaborators = errors.Error("require at least one collaborator") - - // ErrNFTRoleMissing errors when role to generate proof doesn't exist - ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") - - // nftByteCount is the length of combined bytes of registry and tokenID - nftByteCount = 52 -) - // NewDefaultTree returns a DocumentTree with default opts func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { return NewDefaultTreeWithPrefix(salts, "", nil) @@ -197,30 +207,35 @@ func (m *CoreDocumentModel) prepareNewVersion(collaborators []string) (*CoreDocu ncd.PreviousRoot = ocd.DocumentRoot // copy over token registry ndm.TokenRegistry = m.TokenRegistry + + // copy over embedded data + ncd.EmbeddedData = ocd.EmbeddedData + ncd.EmbeddedDataSalts = ocd.EmbeddedDataSalts + return ndm, nil } // NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts -func (m *CoreDocumentModel) NewWithCollaborators(collaborators []string) (*CoreDocumentModel, error) { - dm := NewCoreDocModel() +func NewWithCollaborators(collaborators []string) (*CoreDocumentModel, error) { + m := NewCoreDocModel() ids, err := identity.NewDIDsFromStrings(collaborators) if err != nil { return nil, errors.New("failed to decode collaborator: %v", err) } for i := range ids { - dm.Document.Collaborators = append(dm.Document.Collaborators, ids[i][:]) + m.Document.Collaborators = append(m.Document.Collaborators, ids[i][:]) } - err = dm.initReadRules(ids) + err = m.initReadRules(ids) if err != nil { return nil, errors.New("failed to init read rules: %v", err) } - if err := dm.setCoreDocumentSalts(); err != nil { + if err := m.setCoreDocumentSalts(); err != nil { return nil, err } - return dm, nil + return m, nil } // CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs @@ -460,7 +475,7 @@ func (m *CoreDocumentModel) AccountCanRead(account identity.DID) bool { return m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { _, found := isAccountInRole(role, account) return found - }, coredocumentpb.Action_ACTION_READ, coredocumentpb.Action_ACTION_READ_SIGN) + }, ACLRead, ACLReadSign) } // GenerateCoreDocSalts generates coredoc salts @@ -614,24 +629,25 @@ func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, er return nil, errors.New("role %d not found", key) } +func newRole() *coredocumentpb.Role { + role := new(coredocumentpb.Role) + rk := utils.RandomSlice(32) + role.RoleKey = rk[:] + return role +} + func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.DID) error { if len(collabs) == 0 { return nil } // create a role for given collaborators - role := new(coredocumentpb.Role) - cd := m.Document - rk, err := utils.ConvertIntToByte32(len(cd.Roles)) - if err != nil { - return err - } - role.RoleKey = rk[:] + role := newRole() for _, c := range collabs { c := c role.Collaborators = append(role.Collaborators, c[:]) } - m.addNewRule(role, coredocumentpb.Action_ACTION_READ_SIGN) + m.addNewRule(role, ACLReadSign) return nil } @@ -728,18 +744,12 @@ func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { // AddNFTToReadRules adds NFT token to the read rules of core document. func (m *CoreDocumentModel) AddNFTToReadRules(registry common.Address, tokenID []byte) error { - cd := m.Document nft, err := ConstructNFT(registry, tokenID) if err != nil { return errors.New("failed to construct NFT: %v", err) } - role := new(coredocumentpb.Role) - rk, err := utils.ConvertIntToByte32(len(cd.Roles)) - if err != nil { - return err - } - role.RoleKey = rk[:] + role := newRole() role.Nfts = append(role.Nfts, nft) m.addNewRule(role, coredocumentpb.Action_ACTION_READ) if err := m.setCoreDocumentSalts(); err != nil { @@ -749,22 +759,24 @@ func (m *CoreDocumentModel) AddNFTToReadRules(registry common.Address, tokenID [ } //ValidateDocumentAccess validates the GetDocument request against the AccessType indicated in the request -func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, requesterCentID identity.DID) error { +func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, peer identity.DID) error { // checks which access type is relevant for the request switch docReq.GetAccessType() { case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: - if m.AccountCanRead(requesterCentID) { + if !m.AccountCanRead(peer) { return errors.New("requester does not have access") } case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: registry := common.BytesToAddress(docReq.NftRegistryAddress) - if m.NFTOwnerCanRead(registry, docReq.NftTokenId, requesterCentID) != nil { + if m.NFTOwnerCanRead(registry, docReq.NftTokenId, peer) != nil { return errors.New("requester does not have access") } - //// case AccessTokenValidation - // case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: - // - // case p2ppb.AccessType_ACCESS_TYPE_INVALID: + case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: + reqID := peer[:] + err := m.accessTokenOwnerCanRead(docReq, reqID) + if err != nil { + return err + } default: return errors.New("invalid access type ") } @@ -846,11 +858,165 @@ func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.DID if err != nil { return false } - _, found := isAccountInRole(role, account) return found } +// assembleTokenMessage assembles a token message +func assembleTokenMessage(tokenIdentifier []byte, granterID identity.DID, granteeID identity.DID, roleID []byte, docID []byte) ([]byte, error) { + tokenIdentifiers := [][]byte{tokenIdentifier, roleID, docID} + for _, id := range tokenIdentifiers { + if len(id) != IDByteCount { + return nil, errors.New("invalid identifier length") + } + } + + tm := append(tokenIdentifier, granterID[:]...) + tm = append(tm, granteeID[:]...) + tm = append(tm, roleID...) + tm = append(tm, docID...) + return tm, nil +} + +// assembleAccessToken assembles a Read Access Token from the payload received +func (m *CoreDocumentModel) assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenParams, roleKey []byte) (*coredocumentpb.AccessToken, error) { + account, err := contextutil.Account(ctx) + if err != nil { + return nil, err + } + tokenIdentifier := utils.RandomSlice(32) + id, err := account.GetIdentityID() + if err != nil { + return nil, err + } + granterID := identity.NewDIDFromByte(id) + roleID := roleKey + granteeID, err := identity.NewDIDFromString(payload.Grantee) + if err != nil { + return nil, err + } + // assemble access token message to be signed + docID, err := hexutil.Decode(payload.DocumentIdentifier) + if err != nil { + return nil, err + } + + tm, err := assembleTokenMessage(tokenIdentifier, granterID, granteeID, roleID[:], docID) + if err != nil { + return nil, err + } + + // fetch key pair from identity + // TODO: change to signing key pair once secp scheme is available + sig, err := account.SignMsg(tm) + if err != nil { + return nil, err + } + keys, err := account.GetKeys() + if err != nil { + return nil, err + } + // assemble the access token, appending the signature and public keys + at := &coredocumentpb.AccessToken{ + Identifier: tokenIdentifier, + Granter: granterID[:], + Grantee: granteeID[:], + RoleIdentifier: roleID[:], + DocumentIdentifier: docID, + Signature: sig.Signature, + Key: keys[identity.KeyPurposeSigning].PublicKey, + } + return at, nil + +} + +// AddAccessTokenToReadRules adds the AccessToken(s) to the read rules of the document +func (m *CoreDocumentModel) AddAccessTokenToReadRules(ctx context.Context, payload documentpb.AccessTokenParams) (*CoreDocumentModel, error) { + role := newRole() + at, err := m.assembleAccessToken(ctx, payload, role.RoleKey) + if err != nil { + return nil, errors.New("failed to construct AT: %v", err) + } + role.AccessTokens = append(role.AccessTokens, at) + m.addNewRule(role, ACLRead) + cdSalts, _ := GenerateNewSalts(m.Document, "", nil) + m.Document.CoredocumentSalts = ConvertToProtoSalts(cdSalts) + return m, nil +} + +// ATOwnerCanRead checks that the owner AT can read the document requested +func (m *CoreDocumentModel) accessTokenOwnerCanRead(docReq *p2ppb.GetDocumentRequest, requesterID []byte) error { + // check if the access token is present in read rules of the document indicated in the AT request + token, err := m.findAT(ACLRead, docReq.AccessTokenRequest.AccessTokenId) + if err != nil { + return err + } + // check if the requested document is the document indicated in the access token + if !bytes.Equal(token.DocumentIdentifier, docReq.DocumentIdentifier) { + return errors.New("the document requested does not match the document to which the access token grants access") + } + // validate the access token + // TODO: fetch public key from Ethereum chain + err = validateAT(token.Key, token, requesterID) + if err != nil { + return err + } + return nil + +} + +// validateAT validates that given access token against its signature +func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID []byte) error { + // assemble token message from the token for validation + reqID := identity.NewDIDFromByte(requesterID) + granterID := identity.NewDIDFromByte(token.Granter) + tm, err := assembleTokenMessage(token.Identifier, granterID, reqID, token.RoleIdentifier, token.DocumentIdentifier) + if err != nil { + return err + } + validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1, true) + if !validated { + return errors.New("access token is invalid") + } + return nil +} + +// isATInRole checks if the given access token is part of the core document role. +func isATInRole(role *coredocumentpb.Role, tokenID []byte) (*coredocumentpb.AccessToken, error) { + for _, a := range role.AccessTokens { + if bytes.Equal(tokenID, a.Identifier) { + return a, nil + } + } + return nil, errors.New("access token not found") +} + +// findAT calls OnRole for every role, returns the access token if it is found in the Roles of the document +func (m *CoreDocumentModel) findAT(action coredocumentpb.Action, tokenID []byte) (*coredocumentpb.AccessToken, error) { + cd := m.Document + var token coredocumentpb.AccessToken + for _, rule := range cd.ReadRules { + if rule.Action != action { + continue + } + ruleRoles := rule.GetRoles() + for _, rk := range ruleRoles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + at, err := isATInRole(role, tokenID) + if err != nil { + return nil, err + } + token = *at + } + } + return &token, nil +} + // GetNFTProofs generate proofs required to mint an NFT func (m *CoreDocumentModel) GetNFTProofs( dataRoot []byte, @@ -918,7 +1084,7 @@ func getReadAccessProofKeys(m *CoreDocumentModel, registry common.Address, token } return found - }, coredocumentpb.Action_ACTION_READ) + }, ACLRead) if !found { return nil, ErrNFTRoleMissing diff --git a/documents/model_test.go b/documents/model_test.go index 8d2912f91..c3a11ab88 100644 --- a/documents/model_test.go +++ b/documents/model_test.go @@ -8,6 +8,11 @@ import ( "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/storage/leveldb" @@ -461,7 +466,8 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { tr := mockRegistry{} tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() dm.TokenRegistry = tr - dm.AddNFTToReadRules(registry, tokenID) + err = dm.AddNFTToReadRules(registry, tokenID) + assert.NoError(t, err) err = dm.NFTOwnerCanRead(registry, tokenID, account) assert.Error(t, err) assert.Contains(t, err, "failed to get owner of") @@ -476,6 +482,99 @@ func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { tr.AssertExpectations(t) } +func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { + m := NewCoreDocModel() + m.Document.DocumentRoot = utils.RandomSlice(32) + ctx := testingconfig.CreateAccountContext(t, cfg) + account, err := contextutil.Account(ctx) + assert.NoError(t, err) + + cd := m.Document + assert.Len(t, cd.ReadRules, 0) + assert.Len(t, cd.Roles, 0) + + // invalid centID format + payload := documentpb.AccessTokenParams{ + // invalid grantee format + Grantee: "randomCentID", + DocumentIdentifier: "randomDocID", + } + _, err = m.AddAccessTokenToReadRules(ctx, payload) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to construct AT: malformed address provided") + // invalid centID length + invalidCentID := utils.RandomSlice(25) + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(invalidCentID), + DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), + } + _, err = m.AddAccessTokenToReadRules(ctx, payload) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to construct AT: malformed address provided") + // invalid docID length + id, err := account.GetIdentityID() + assert.NoError(t, err) + invalidDocID := utils.RandomSlice(33) + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(id), + DocumentIdentifier: hexutil.Encode(invalidDocID), + } + + _, err = m.AddAccessTokenToReadRules(ctx, payload) + assert.Contains(t, err.Error(), "failed to construct AT: invalid identifier length") + // valid + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(id), + DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), + } + _, err = m.AddAccessTokenToReadRules(ctx, payload) + assert.NoError(t, err) + assert.Len(t, m.Document.ReadRules, 1) + assert.Equal(t, m.Document.ReadRules[0].Action, ACLRead) + assert.Len(t, m.Document.Roles, 1) +} + +func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { + ctx := testingconfig.CreateAccountContext(t, cfg) + account, _ := contextutil.Account(ctx) + m := NewCoreDocModel() + m.Document.DocumentRoot = utils.RandomSlice(32) + id, err := account.GetIdentityID() + granteeID := identity.NewDIDFromByte(id) + assert.NoError(t, err) + payload := documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(granteeID[:]), + DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), + } + dm, err := m.AddAccessTokenToReadRules(ctx, payload) + assert.NoError(t, err) + dm.Document.DocumentRoot = utils.RandomSlice(32) + docRoles := dm.Document.GetRoles() + at := docRoles[0].AccessTokens[0] + assert.NotNil(t, at) + // wrong token identifier + tr := &p2ppb.AccessTokenRequest{ + DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, + AccessTokenId: []byte("randomtokenID"), + } + dr := &p2ppb.GetDocumentRequest{ + DocumentIdentifier: m.Document.DocumentIdentifier, + AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, + AccessTokenRequest: tr, + } + err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) + assert.Error(t, err, "access token not found") + // valid access token + // TODO: this will always fail until validation for signatures is secp + //tr = &p2ppb.AccessTokenRequest{ + // DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, + // AccessTokenId: at.Identifier, + //} + //dr.AccessTokenRequest = tr + //err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) + //assert.NoError(t, err) +} + func TestGetCoreDocumentSalts(t *testing.T) { dm := NewCoreDocModel() // From empty @@ -583,7 +682,9 @@ func TestCoreDocumentModel_IsAccountInRole(t *testing.T) { err := dm.initReadRules([]identity.DID{account}) assert.NoError(t, err) - assert.True(t, dm.IsAccountInRole(roleKey, account)) + roles := dm.Document.Roles + rk := roles[0].RoleKey + assert.True(t, dm.IsAccountInRole(rk, account)) } func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { @@ -599,12 +700,14 @@ func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { ndm, err := dm.AddNFT(true, registry, tokenID) assert.NoError(t, err) assert.NotNil(t, ndm) + role := ndm.Document.Roles[0] + rk := role.RoleKey pfs, err = getReadAccessProofKeys(ndm, registry, tokenID) assert.NoError(t, err) assert.Len(t, pfs, 3) assert.Equal(t, CDTreePrefix+".read_rules[0].roles[0]", pfs[0]) - assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(make([]byte, 32, 32))), pfs[1]) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(rk)), pfs[1]) assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[2]) } @@ -627,16 +730,20 @@ func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { } func TestCoreDocument_getRoleProofKey(t *testing.T) { + dm := NewCoreDocModel() - roleKey := make([]byte, 32, 32) + rk := utils.RandomSlice(32) account := testingidentity.GenerateRandomDID() - pf, err := getRoleProofKey(dm.Document.Roles, roleKey, account) + pf, err := getRoleProofKey(dm.Document.Roles, rk, account) assert.Error(t, err) assert.Empty(t, pf) err = dm.initReadRules([]identity.DID{account}) assert.NoError(t, err) + role := dm.Document.Roles[0] + roleKey := role.RoleKey + pf, err = getRoleProofKey(dm.Document.Roles, roleKey, testingidentity.GenerateRandomDID()) assert.Error(t, err) assert.True(t, errors.IsOfType(ErrNFTRoleMissing, err)) diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index f36cc93cc..f84eed81f 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -159,7 +159,7 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu } collaborators := append([]string{self}, payload.Collaborators...) - p.CoreDocumentModel, err = p.CoreDocumentModel.NewWithCollaborators(collaborators) + p.CoreDocumentModel, err = documents.NewWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 7c6204221..66e0fd763 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -115,7 +115,8 @@ func TestPO_CoreDocument_successful(t *testing.T) { coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) poModel.CoreDocumentModel = coreDocumentModel - poModel.UnpackCoreDocument(coreDocumentModel) + err := poModel.UnpackCoreDocument(coreDocumentModel) + assert.NoError(t, err) returnedCoreDocumentModel, err := poModel.PackCoreDocument() assert.Nil(t, err, "transformation from purchase order to CoreDoc failed") @@ -141,7 +142,8 @@ func TestPO_JSON(t *testing.T) { poData := testingdocuments.CreatePOData() coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) poModel.CoreDocumentModel = coreDocumentModel - poModel.UnpackCoreDocument(coreDocumentModel) + err := poModel.UnpackCoreDocument(coreDocumentModel) + assert.NoError(t, err) jsonBytes, err := poModel.JSON() assert.Nil(t, err, "marshal to json didn't work correctly") @@ -310,6 +312,7 @@ func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, error) { if err != nil { return nil, err } - poModel.UnpackCoreDocument(corDocModel) + err = poModel.UnpackCoreDocument(corDocModel) + assert.NoError(t, err) return poModel, nil } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index dbe43c251..d1f4bc8ec 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -163,6 +163,9 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientpop } po := new(PurchaseOrder) + if po.CoreDocumentModel == nil { + po.CoreDocumentModel = documents.NewCoreDocModel() + } err = po.InitPurchaseOrderInput(payload, idConf.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) diff --git a/documents/registry_test.go b/documents/registry_test.go index a94b75ef6..c1c361279 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -13,9 +13,10 @@ import ( func TestRegistry_Register_LocateService_successful(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - dm := testingdocuments.GenerateCoreDocumentModel() + dm, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) documentType := dm.Document.EmbeddedData.TypeUrl - err := registry.Register(documentType, a) + err = registry.Register(documentType, a) assert.Nil(t, err, "register didn't work with unused id") b, err := registry.LocateService(documentType) @@ -26,11 +27,12 @@ func TestRegistry_Register_LocateService_successful(t *testing.T) { func TestRegistry_Register_invalidId(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - dm := testingdocuments.GenerateCoreDocumentModel() + dm, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) cd := dm.Document cd.EmbeddedData.TypeUrl = "testID_1" - err := registry.Register(cd.EmbeddedData.TypeUrl, a) + err = registry.Register(cd.EmbeddedData.TypeUrl, a) assert.Nil(t, err, "register didn't work with unused id") err = registry.Register(cd.EmbeddedData.TypeUrl, a) @@ -42,10 +44,11 @@ func TestRegistry_Register_invalidId(t *testing.T) { func TestRegistry_LocateService_invalid(t *testing.T) { registry := documents.NewServiceRegistry() - dm := testingdocuments.GenerateCoreDocumentModel() + dm, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) cd := dm.Document cd.EmbeddedData.TypeUrl = "testID_2" documentType := cd.EmbeddedData.TypeUrl - _, err := registry.LocateService(documentType) + _, err = registry.LocateService(documentType) assert.Error(t, err, "should throw an error because no services is registered") } diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index f75810cf2..bfb92d441 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -8,6 +8,8 @@ import ( "os" "testing" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/ethereum/go-ethereum/common" @@ -120,7 +122,8 @@ func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte, localID idConfig, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) idConfig.ID = localID - dm := testingdocuments.GenerateCoreDocumentModelWithCollaborators(collaborators) + dm, err := testingdocuments.GenerateCoreDocumentModelWithCollaborators(collaborators) + assert.NoError(t, err) m, err := docService.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err) @@ -133,8 +136,11 @@ func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte, localID tree, err := dm.GetDocumentSigningTree(droot) assert.NoError(t, err) dm.Document.SigningRoot = tree.RootHash() + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, dm.Document.SigningRoot) - dm.Document.Signatures = append(dm.Document.Signatures, sig) + assert.NoError(t, err) + dm.Document.Signatures = []*coredocumentpb.Signature{sig} + tree, err = dm.GetDocumentRootTree() assert.NoError(t, err) dm.Document.DocumentRoot = tree.RootHash() diff --git a/p2p/client_test.go b/p2p/client_test.go index 7871c0db1..a83d405c1 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -51,7 +51,8 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) coreDoc := coreDocModel.Document assert.Nil(t, err, "centrifugeId not initialized correctly ") @@ -76,7 +77,8 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) coreDoc := coreDocModel.Document _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) @@ -100,7 +102,8 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel := testingdocuments.GenerateCoreDocumentModel() + coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() + assert.NoError(t, err) coreDoc := coreDocModel.Document assert.Nil(t, err, "centrifugeId not initialized correctly ") diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 4e13841e2..c962cb57c 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -202,8 +202,33 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc // GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.DID) (*p2ppb.GetDocumentResponse, error) { + // if the document request contains an access token request, check the document indicated by the delegating document identifier for the access token + if docReq.AccessTokenRequest != nil { + model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.AccessTokenRequest.DelegatingDocumentIdentifier) + if err != nil { + return nil, err + } + dm, err := model.PackCoreDocument() + if err != nil { + return nil, err + } + err = dm.ValidateDocumentAccess(docReq, requesterCentID) + if err != nil { + return nil, err + } + // if the access token passes validation, return the requested document indicated in the parent GetDocumentRequest + reqModel, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) + if err != nil { + return nil, err + } + reqDm, err := reqModel.PackCoreDocument() + if err != nil { + return nil, err + } + return &p2ppb.GetDocumentResponse{Document: reqDm.Document}, nil + } + // if the document request requires NFT or Peer validation, validate the request based on the document identifier in the GetDocumentRequest model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) - if err != nil { return nil, err } @@ -211,10 +236,11 @@ func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRe if err != nil { return nil, err } - //err = dm.ValidateDocumentAccess(docReq, requesterCentID) - //if err != nil { - // return nil, err - //} + err = dm.ValidateDocumentAccess(docReq, requesterCentID) + if err != nil { + return nil, err + } + // return requested document if validation checks pass return &p2ppb.GetDocumentResponse{Document: dm.Document}, nil } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 124036634..c61808f97 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -9,9 +9,14 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/ethereum/go-ethereum/common" "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" @@ -73,48 +78,87 @@ func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { assert.Nil(t, resp, "must be nil") } -func TestHandler_GetDocumentSucceeds(t *testing.T) { - tc, err := configstore.NewAccount("", cfg) - assert.Nil(t, err) - centrifugeId := createIdentity(t) - acc := tc.(*configstore.Account) - acc.IdentityID = centrifugeId[:] +func updateDocument(t *testing.T, dm *documents.CoreDocumentModel, centrifugeId identity.DID, ctxh context.Context) { - ctxh, err := contextutil.New(context.Background(), tc) - assert.Nil(t, err) + dm = prepareDocumentForP2PHandler(t, dm, centrifugeId) + + ed := dm.Document.EmbeddedData + edsalts := dm.Document.EmbeddedDataSalts - dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) - assert.Nil(t, err) - assert.NotNil(t, resp) + assert.NoError(t, err) + dm.Document.EmbeddedData = ed + dm.Document.EmbeddedDataSalts = edsalts // Add signature received - doc := dm.Document - doc.Signatures = append(doc.Signatures, resp.Signature) + dm.Document.Signatures = append(dm.Document.Signatures, resp.Signature) tree, err := dm.GetDocumentRootTree() assert.NoError(t, err) - doc.DocumentRoot = tree.RootHash() + dm.Document.DocumentRoot = tree.RootHash() - // Anchor document - anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) - docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) - anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) + cdSalts, _ := documents.GenerateNewSalts(dm.Document, "", nil) + dm.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) +} + +func TestHandler_GetDocumentSucceeds(t *testing.T) { + // generate identity for testing + didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) + assert.NoError(t, err) + did := identity.NewDID(*didAddr) + tc, err := configstore.TempAccount("", cfg) + assert.NoError(t, err) + tcr := tc.(*configstore.Account) + tcr.IdentityID = did[:] + cid, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService, idFactory) + assert.NoError(t, err) + + // generate initial core doc with collaborators + ctxh := testingconfig.CreateAccountContext(t, cfg) + dm, err := testingdocuments.GenerateCoreDocumentModelWithCollaborators([][]byte{cid[:]}) assert.Nil(t, err) - watchCommittedAnchor := <-anchorConfirmations - assert.True(t, watchCommittedAnchor, "No error should be thrown by context") + updateDocument(t, dm, cid, ctxh) - anchorReq := getAnchoredRequest(dm) - anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, centrifugeId[:]) + // Retrieve document from repository with requester verification access type + getReq := getDocumentRequestPeer(dm) + getDocResp, err := handler.GetDocument(ctxh, getReq, cid) assert.Nil(t, err) - assert.NotNil(t, anchorResp, "must be non nil") + assert.ObjectsAreEqual(getDocResp.Document, dm.Document) + + // Retrieve document from repository with access token verification access type + // TODO : will fail until signature validation scheme is changed + //docID := hexutil.Encode(dm.Document.DocumentIdentifier) + //at := documentpb.AccessTokenParams{ + // Grantee: cid.String(), + // DocumentIdentifier: docID, + //} + //dm, err = dm.AddAccessTokenToReadRules(ctxh, at) + //assert.NoError(t, err) + //dm, err = dm.PrepareNewVersion(nil) + //assert.NoError(t, err) + //updateDocument(t, dm, cid, ctxh) + // + //role := dm.Document.Roles[1] + //token := role.AccessTokens[0] + //accessTokenReq := getDocumentRequestAccessToken(dm, token.Identifier) + //getDocResp, err = handler.GetDocument(ctxh, accessTokenReq, cid) + //assert.Nil(t, err) + //assert.ObjectsAreEqual(getDocResp.Document, dm.Document) + + // Retrieve document from repository with nft verification access type + // TODO: will currently always work because token owner is a collaborator + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(32) + err = dm.AddNFTToReadRules(registry, tokenID) + dm, err = dm.PrepareNewVersion(nil) + assert.NoError(t, err) + updateDocument(t, dm, cid, ctxh) - // Retrieve document from anchor repository with document_identifier - getReq := getGetDocumentRequest(dm) - getDocResp, err := handler.GetDocument(ctxh, getReq, centrifugeId) + nftReq := getDocumentRequestNft(dm, registry, tokenID) + getDocResp, err = handler.GetDocument(ctxh, nftReq, cid) assert.Nil(t, err) - assert.ObjectsAreEqual(getDocResp.Document, doc) + assert.ObjectsAreEqual(getDocResp.Document, dm.Document) } func TestHandler_HandleInterceptorReqSignature(t *testing.T) { @@ -163,6 +207,8 @@ func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { dm := prepareDocumentForP2PHandler(t, nil, defaultDID) + ed := dm.Document.EmbeddedData + edsalts := dm.Document.EmbeddedDataSalts req := getSignatureRequest(dm) tc, err := configstore.NewAccount("", cfg) assert.Nil(t, err) @@ -175,6 +221,9 @@ func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") + dm.Document.EmbeddedData = ed + dm.Document.EmbeddedDataSalts = edsalts + req = getSignatureRequest(dm) resp, err = handler.RequestDocumentSignature(ctxh, req) assert.NotNil(t, err, "must not be nil") @@ -240,7 +289,6 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { centrifugeId := createIdentity(t) - dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) // Anchor document @@ -285,10 +333,14 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { assert.Nil(t, err) dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) + ed := dm.Document.EmbeddedData + edsalts := dm.Document.EmbeddedDataSalts req := getSignatureRequest(dm) resp, err := handler.RequestDocumentSignature(ctxh, req) assert.Nil(t, err) assert.NotNil(t, resp) + dm.Document.EmbeddedData = ed + dm.Document.EmbeddedDataSalts = edsalts // Add signature received doc := dm.Document @@ -354,11 +406,11 @@ func createIdentity(t *testing.T) identity.DID { func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel, did identity.DID) *documents.CoreDocumentModel { idConfig, err := identity.GetIdentityConfig(cfg) idConfig.ID = did - assert.Nil(t, err) + assert.NoError(t, err) if dm == nil { - dm = testingdocuments.GenerateCoreDocumentModel() + dm, err = testingdocuments.GenerateCoreDocumentModel() + assert.Nil(t, err) } - m, err := docSrv.DeriveFromCoreDocumentModel(dm) assert.Nil(t, err) @@ -368,12 +420,12 @@ func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel, dm, err = m.PackCoreDocument() assert.NoError(t, err) + doc := dm.Document tree, err := dm.GetDocumentSigningTree(droot) assert.NoError(t, err) - doc := dm.Document doc.SigningRoot = tree.RootHash() sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) - doc.Signatures = append(doc.Signatures, sig) + doc.Signatures = []*coredocumentpb.Signature{sig} tree, err = dm.GetDocumentRootTree() assert.NoError(t, err) doc.DocumentRoot = tree.RootHash() @@ -406,9 +458,32 @@ func getSignatureRequest(dm *documents.CoreDocumentModel) *p2ppb.SignatureReques return &p2ppb.SignatureRequest{Document: &doc} } -func getGetDocumentRequest(dm *documents.CoreDocumentModel) *p2ppb.GetDocumentRequest { - doc := dm.Document - return &p2ppb.GetDocumentRequest{DocumentIdentifier: doc.DocumentIdentifier} +func getDocumentRequestPeer(dm *documents.CoreDocumentModel) *p2ppb.GetDocumentRequest { + return &p2ppb.GetDocumentRequest{ + DocumentIdentifier: dm.Document.DocumentIdentifier, + AccessType: p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION, + } +} + +func getDocumentRequestNft(dm *documents.CoreDocumentModel, registry common.Address, tokenID []byte) *p2ppb.GetDocumentRequest { + return &p2ppb.GetDocumentRequest{ + DocumentIdentifier: dm.Document.DocumentIdentifier, + AccessType: p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION, + NftRegistryAddress: registry[:], + NftTokenId: tokenID, + } +} + +func getDocumentRequestAccessToken(dm *documents.CoreDocumentModel, tokenID []byte) *p2ppb.GetDocumentRequest { + atr := &p2ppb.AccessTokenRequest{ + DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, + AccessTokenId: tokenID, + } + return &p2ppb.GetDocumentRequest{ + DocumentIdentifier: dm.Document.DocumentIdentifier, + AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, + AccessTokenRequest: atr, + } } func resolveSignatureResponse(t *testing.T, p2pEnv *protocolpb.P2PEnvelope) *p2ppb.SignatureResponse { diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index c73346858..3a6633209 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -2,15 +2,16 @@ package testingdocuments import ( "context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/gogo/protobuf/proto" "github.com/golang/protobuf/ptypes/any" + "github.com/golang/protobuf/ptypes/timestamp" "github.com/stretchr/testify/mock" + "time" ) type MockService struct { @@ -81,33 +82,50 @@ func (m *MockModel) JSON() ([]byte, error) { return data, args.Error(1) } -func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) *documents.CoreDocumentModel { - identifier := utils.RandomSlice(32) - invData := &invoicepb.InvoiceData{} +func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) (*documents.CoreDocumentModel, error) { + dueDate := time.Now().Add(4 * 24 * time.Hour) + invData := &invoicepb.InvoiceData{ + InvoiceNumber: "2132131", + GrossAmount: 123, + NetAmount: 123, + Currency: "EUR", + DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, + } dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) - serializedInv, _ := proto.Marshal(invData) - doc := &coredocumentpb.CoreDocument{ - Collaborators: collaborators, - DocumentIdentifier: identifier, - CurrentVersion: identifier, - NextVersion: utils.RandomSlice(32), - EmbeddedData: &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInv, - }, - EmbeddedDataSalts: documents.ConvertToProtoSalts(dataSalts), + var dm *documents.CoreDocumentModel + if collaborators != nil { + var collabs []string + for _, c := range collaborators { + encoded := hexutil.Encode(c) + collabs = append(collabs, encoded) + } + m, err := documents.NewWithCollaborators(collabs) + if err != nil { + return nil, err + } + dm = m + } else { + dm = documents.NewCoreDocModel() + } + dm.Document.EmbeddedData = &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: serializedInv, } - cdSalts, _ := documents.GenerateCoreDocSalts(doc) - doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) - dm := documents.NewCoreDocModel() + dm.Document.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) + + cdSalts, _ := documents.GenerateCoreDocSalts(dm.Document) + dm.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) mockModel := MockModel{ CoreDocumentModel: dm, } - dm.Document = doc - return mockModel.CoreDocumentModel + return mockModel.CoreDocumentModel, nil } -func GenerateCoreDocumentModel() *documents.CoreDocumentModel { - return GenerateCoreDocumentModelWithCollaborators(nil) +func GenerateCoreDocumentModel() (*documents.CoreDocumentModel, error) { + dm, err := GenerateCoreDocumentModelWithCollaborators(nil) + if err != nil { + return nil, err + } + return dm, nil } diff --git a/utils/tools.go b/utils/tools.go index 119bb225b..8cd682e66 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -22,7 +22,7 @@ func ContainsBigIntInSlice(value *big.Int, list []*big.Int) bool { return false } -// SliceToByte32 converts a 32 byte slice to an array. Will thorw error if the slice is too long +// SliceToByte32 converts a 32 byte slice to an array. Will throw error if the slice is too long func SliceToByte32(in []byte) (out [32]byte, err error) { if len(in) > 32 { return [32]byte{}, errors.New("input exceeds length of 32") From 4ea5e67e3029b65b6848f4932a41191cacbcb5a0 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 26 Feb 2019 16:51:26 +0100 Subject: [PATCH 202/220] Fix NFT tests (#782) --- nft/ethereum_payment_obligation.go | 6 +++++- nft/payment_obligation_integration_test.go | 15 +++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index e9c64b05c..95cfec5a5 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -109,7 +109,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return mreq, err } - requestData, err := NewMintRequest(tokenID, req.DepositAddress, anchorID, pfs, rootHash) + requestData, err := NewMintRequest(tokenID, req.DepositAddress, anchorID, docProofs.FieldProofs, rootHash) if err != nil { return mreq, err } @@ -319,6 +319,10 @@ func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { var salts = make([][32]byte, len(proofspb)) var proofs = make([][][32]byte, len(proofspb)) + // TODO remove later + //proof, _ := documents.ConvertDocProofToClientFormat(&documents.DocumentProof{FieldProofs: proofspb}) + //log.Info(json.MarshalIndent(proof, "", " ")) + for i, p := range proofspb { values[i] = p.Value salt32, err := utils.SliceToByte32(p.Salt) diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index d2ac3e6ca..9ed65ed30 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -8,19 +8,18 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/bootstrap" cc "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common" @@ -31,6 +30,7 @@ import ( var registry *documents.ServiceRegistry var cfg config.Configuration +var cfgService config.Service var idService identity.ServiceDID var idFactory identity.Factory var payOb nft.PaymentObligation @@ -44,6 +44,7 @@ func TestMain(m *testing.M) { idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + cfgService = ctx[config.BootstrappedConfigStorage].(config.Service) payOb = ctx[nft.BootstrappedPayObService].(nft.PaymentObligation) txManager = ctx[transactions.BootstrappedService].(transactions.Manager) tokenRegistry = ctx[nft.BootstrappedPayObService].(documents.TokenRegistry) @@ -62,13 +63,16 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address assert.NoError(t, err) tcr := tc.(*configstore.Account) tcr.IdentityID = did[:] + _, err = cfgService.CreateAccount(tcr) + assert.NoError(t, err) cid, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService, idFactory) assert.NoError(t, err) // create invoice (anchor) service, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Nil(t, err, "should not error out when getting invoice service") - ctx := testingconfig.CreateAccountContext(t, cfg) + ctx, err := contextutil.New(context.Background(), tcr) + assert.NoError(t, err) invSrv := service.(invoice.Service) dueDate := time.Now().Add(4 * 24 * time.Hour) model, err := invSrv.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ @@ -171,7 +175,7 @@ func mintNFTWithProofs(t *testing.T, grantAccess, tokenProof, readAccessProof bo DocumentID: id, RegistryAddress: registry, DepositAddress: common.HexToAddress(depositAddr), - ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "next_version"}, + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "cd_tree.next_version"}, GrantNFTReadAccess: grantAccess, SubmitTokenProof: tokenProof, SubmitNFTReadAccessProof: readAccessProof, @@ -210,7 +214,6 @@ func TestEthereumPaymentObligation_MintNFT(t *testing.T) { grantAccess: true, readAccessProof: true, }, - { grantAccess: true, tokenProof: true, From 05bf9cf7ed5e7b2cd296012b374396226c11cb97 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 27 Feb 2019 13:56:12 +0100 Subject: [PATCH 203/220] Feat/cleanup Core document (#768) --- api/server_test.go | 7 +- bootstrap/bootstrappers/bootstrapper.go | 4 +- .../testingbootstrap/testing_bootstrap.go | 4 +- crypto/sign.go | 4 +- documents/anchor.go | 11 +- documents/coredocument.go | 523 ++++++++ documents/coredocument_test.go | 308 +++++ documents/documents_test/anchor_test.go | 40 +- documents/documents_test/service_test.go | 273 ++-- documents/invoice/handler_test.go | 21 +- documents/invoice/model.go | 147 ++- documents/invoice/model_test.go | 187 +-- documents/invoice/service.go | 92 +- documents/invoice/service_test.go | 513 +++----- documents/invoice/utils_test.go | 26 - documents/model.go | 1136 +---------------- documents/model_test.go | 844 ------------ documents/processor.go | 115 +- documents/processor_test.go | 551 ++++---- documents/purchaseorder/model.go | 138 +- documents/purchaseorder/model_test.go | 192 +-- documents/purchaseorder/service.go | 89 +- documents/purchaseorder/service_test.go | 296 +---- documents/purchaseorder/utils_test.go | 26 - documents/read_acls.go | 477 +++++++ documents/read_acls_test.go | 422 ++++++ documents/registry_test.go | 28 +- documents/service.go | 117 +- documents/tree.go | 69 + documents/tree_test.go | 32 + documents/validator.go | 191 +-- documents/validator_test.go | 435 ++----- nft/ethereum_payment_obligation.go | 44 +- nft/ethereum_payment_obligation_test.go | 13 +- nft/payment_obligation_integration_test.go | 8 +- p2p/bootstrapper.go | 8 +- p2p/bootstrapper_test.go | 3 + p2p/client.go | 70 +- p2p/client_integration_test.go | 82 +- p2p/client_test.go | 67 +- p2p/receiver/handler.go | 96 +- p2p/receiver/handler_integration_test.go | 319 +---- p2p/receiver/handler_test.go | 13 +- p2p/receiver/validator_test.go | 6 +- p2p/server_test.go | 10 +- queue/server.go | 16 +- testingutils/documents/documents.go | 79 +- 47 files changed, 3510 insertions(+), 4642 deletions(-) create mode 100644 documents/coredocument.go create mode 100644 documents/coredocument_test.go delete mode 100644 documents/invoice/utils_test.go delete mode 100644 documents/model_test.go delete mode 100644 documents/purchaseorder/utils_test.go create mode 100644 documents/read_acls.go create mode 100644 documents/read_acls_test.go create mode 100644 documents/tree.go create mode 100644 documents/tree_test.go diff --git a/api/server_test.go b/api/server_test.go index c2b80595e..a1584d89d 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -9,8 +9,6 @@ import ( "sync" "testing" - "github.com/centrifuge/go-centrifuge/identity/ideth" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" @@ -21,6 +19,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity/ideth" "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" "github.com/centrifuge/go-centrifuge/queue" @@ -50,13 +49,13 @@ func TestMain(m *testing.M) { &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, - documents.PostBootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, ðereum.Bootstrapper{}, &nft.Bootstrapper{}, &queue.Starter{}, + p2p.Bootstrapper{}, + documents.PostBootstrapper{}, } bootstrap.RunTestBootstrappers(ibootstappers, ctx) diff --git a/bootstrap/bootstrappers/bootstrapper.go b/bootstrap/bootstrappers/bootstrapper.go index 6a4d525e3..4ce6acd2d 100644 --- a/bootstrap/bootstrappers/bootstrapper.go +++ b/bootstrap/bootstrappers/bootstrapper.go @@ -41,12 +41,12 @@ func (m *MainBootstrapper) PopulateBaseBootstrappers() { &configstore.Bootstrapper{}, &anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, api.Bootstrapper{}, - documents.PostBootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, + p2p.Bootstrapper{}, + documents.PostBootstrapper{}, } } diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index 00b3d0661..bbacda0bb 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -35,12 +35,12 @@ var bootstappers = []bootstrap.TestBootstrapper{ &configstore.Bootstrapper{}, anchors.Bootstrapper{}, documents.Bootstrapper{}, - p2p.Bootstrapper{}, &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, - documents.PostBootstrapper{}, &nft.Bootstrapper{}, &queue.Starter{}, + p2p.Bootstrapper{}, + documents.PostBootstrapper{}, } func TestFunctionalEthereumBootstrap() map[string]interface{} { diff --git a/crypto/sign.go b/crypto/sign.go index d69c408bb..e50339229 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -43,9 +43,9 @@ func VerifySignature(pubKey, message, signature []byte) error { // Sign the document with the private key and return the signature along with the public key for the verification // assumes that signing root for the document is generated // Deprecated -func Sign(didBytes []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { +func Sign(id []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { return &coredocumentpb.Signature{ - EntityId: didBytes, + EntityId: id, PublicKey: pubKey, Signature: ed25519.Sign(privateKey, payload), Timestamp: utils.ToTimestamp(time.Now().UTC()), diff --git a/documents/anchor.go b/documents/anchor.go index cb9bc7e08..5d30ee7f4 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -3,6 +3,7 @@ package documents import ( "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" ) @@ -10,7 +11,7 @@ import ( // AnchorProcessor identifies an implementation, which can do a bunch of things with a CoreDocument. // E.g. send, anchor, etc. type AnchorProcessor interface { - Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.DID) (err error) + Send(ctx context.Context, cd coredocumentpb.CoreDocument, recipient identity.DID) (err error) PrepareForSignatureRequests(ctx context.Context, model Model) error RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error @@ -24,12 +25,8 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, updater updaterFunc) (Model, error) { - dm, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - id := dm.Document.CurrentVersion - err = proc.PrepareForSignatureRequests(ctx, model) + id := model.CurrentVersion() + err := proc.PrepareForSignatureRequests(ctx, model) if err != nil { return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to prepare document for signatures: %v", err)) } diff --git a/documents/coredocument.go b/documents/coredocument.go new file mode 100644 index 000000000..095c0996f --- /dev/null +++ b/documents/coredocument.go @@ -0,0 +1,523 @@ +package documents + +import ( + "crypto/sha256" + "encoding/binary" + "fmt" + "strings" + + "github.com/golang/protobuf/ptypes/any" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +const ( + // CDRootField represents the coredocument root property of a tree + CDRootField = "cd_root" + + // DataRootField represents the data root property of a tree + DataRootField = "data_root" + + // DocumentTypeField represents the doc type property of a tree + DocumentTypeField = "document_type" + + // SignaturesField represents the signatures property of a tree + SignaturesField = "signatures" + + // SigningRootField represents the signature root property of a tree + SigningRootField = "signing_root" + + // idSize represents the size of identifiers, roots etc.. + idSize = 32 + + // ErrNFTRoleMissing errors when role to generate proof doesn't exist + ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") + + // nftByteCount is the length of combined bytes of registry and tokenID + nftByteCount = 52 + + // CDTreePrefix is the human readable prefix for core doc tree props + CDTreePrefix = "cd_tree" + + // SigningTreePrefix is the human readable prefix for signing tree props + SigningTreePrefix = "signing_tree" +) + +func compactProperties(key string) []byte { + m := map[string][]byte{ + CDRootField: {0, 0, 0, 7}, + DataRootField: {0, 0, 0, 5}, + DocumentTypeField: {0, 0, 0, 100}, + SignaturesField: {0, 0, 0, 6}, + SigningRootField: {0, 0, 0, 10}, + + // tree prefixes use the first byte of a 4 byte slice by convention + CDTreePrefix: {1, 0, 0, 0}, + SigningTreePrefix: {2, 0, 0, 0}, + } + return m[key] +} + +// CoreDocument is a wrapper for CoreDocument Protobuf. +type CoreDocument struct { + Document coredocumentpb.CoreDocument +} + +// newCoreDocument returns a new CoreDocument. +func newCoreDocument() *CoreDocument { + id := utils.RandomSlice(idSize) + cd := coredocumentpb.CoreDocument{ + DocumentIdentifier: id, + CurrentVersion: id, + NextVersion: utils.RandomSlice(idSize), + } + + return &CoreDocument{cd} +} + +// NewCoreDocumentFromProtobuf returns CoreDocument from the CoreDocument Protobuf. +func NewCoreDocumentFromProtobuf(cd coredocumentpb.CoreDocument) *CoreDocument { + cd.EmbeddedDataSalts = nil + cd.EmbeddedData = nil + return &CoreDocument{Document: cd} +} + +// NewCoreDocumentWithCollaborators generates new core Document, adds collaborators, adds read rules and fills salts +func NewCoreDocumentWithCollaborators(collaborators []string) (*CoreDocument, error) { + cd := newCoreDocument() + ids, err := identity.NewDIDsFromStrings(collaborators) + if err != nil { + return nil, errors.New("failed to decode collaborators: %v", err) + } + + for i := range ids { + cd.Document.Collaborators = append(cd.Document.Collaborators, ids[i][:]) + } + + cd.initReadRules(ids) + if err := cd.setSalts(); err != nil { + return nil, err + } + + return cd, nil +} + +// ID returns the Document identifier +func (cd *CoreDocument) ID() []byte { + return cd.Document.DocumentIdentifier +} + +// CurrentVersion returns the current version of the Document +func (cd *CoreDocument) CurrentVersion() []byte { + return cd.Document.CurrentVersion +} + +// PreviousVersion returns the previous version of the Document. +func (cd *CoreDocument) PreviousVersion() []byte { + return cd.Document.PreviousVersion +} + +// NextVersion returns the next version of the Document. +func (cd *CoreDocument) NextVersion() []byte { + return cd.Document.NextVersion +} + +// PreviousDocumentRoot returns the Document root of the previous version. +func (cd *CoreDocument) PreviousDocumentRoot() []byte { + return cd.Document.PreviousRoot +} + +// AppendSignatures appends signatures to core Document. +func (cd *CoreDocument) AppendSignatures(signs ...*coredocumentpb.Signature) { + cd.Document.Signatures = append(cd.Document.Signatures, signs...) +} + +// setSalts generate salts for core Document. +// This is no-op if the salts are already generated. +func (cd *CoreDocument) setSalts() error { + if cd.Document.CoredocumentSalts != nil { + return nil + } + + pSalts, err := GenerateNewSalts(&cd.Document, CDTreePrefix, compactProperties(CDTreePrefix)) + if err != nil { + return err + } + + cd.Document.CoredocumentSalts = ConvertToProtoSalts(pSalts) + return nil +} + +// PrepareNewVersion prepares the next version of the CoreDocument +// Note: salts needs to be filled by the caller +func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool) (*CoreDocument, error) { + if len(cd.Document.DocumentRoot) != idSize { + return nil, errors.New("Document root is invalid") + } + + ucs, err := fetchNewUniqueCollaborators(cd.Document.Collaborators, collaborators) + if err != nil { + return nil, errors.New("failed to fetch new collaborators: %v", err) + } + + cs := cd.Document.Collaborators + for _, c := range ucs { + c := c + cs = append(cs, c[:]) + } + + cdp := coredocumentpb.CoreDocument{ + DocumentIdentifier: cd.Document.DocumentIdentifier, + PreviousVersion: cd.Document.CurrentVersion, + CurrentVersion: cd.Document.NextVersion, + NextVersion: utils.RandomSlice(32), + PreviousRoot: cd.Document.DocumentRoot, + Collaborators: cs, + Roles: cd.Document.Roles, + ReadRules: cd.Document.ReadRules, + Nfts: cd.Document.Nfts, + } + + ncd := &CoreDocument{Document: cdp} + ncd.addCollaboratorsToReadSignRules(ucs) + + if !initSalts { + return ncd, nil + } + + err = ncd.setSalts() + if err != nil { + return nil, errors.New("failed to init salts: %v", err) + } + + return ncd, nil +} + +// addCollaboratorsToReadSignRules adds the given collaborators to a new read rule with READ_SIGN capability. +// The operation is no-op if no collaborators is provided. +// The operation is not idempotent. So calling twice with same accounts will lead to read rules duplication. +func (cd *CoreDocument) addCollaboratorsToReadSignRules(collaborators []identity.DID) { + if len(collaborators) == 0 { + return + } + + // create a role for given collaborators + role := new(coredocumentpb.Role) + role.RoleKey = utils.RandomSlice(idSize) + for _, c := range collaborators { + c := c + role.Collaborators = append(role.Collaborators, c[:]) + } + + cd.addNewRule(role, coredocumentpb.Action_ACTION_READ_SIGN) +} + +// addNewRule creates a new rule as per the role and action. +func (cd *CoreDocument) addNewRule(role *coredocumentpb.Role, action coredocumentpb.Action) { + cd.Document.Roles = append(cd.Document.Roles, role) + rule := new(coredocumentpb.ReadRule) + rule.Roles = append(rule.Roles, role.RoleKey) + rule.Action = action + cd.Document.ReadRules = append(cd.Document.ReadRules, rule) +} + +// CreateProofs takes Document data tree and list to fields and generates proofs. +// we will try generating proofs from the dataTree. If failed, we will generate proofs from CoreDocument. +// errors out when the proof generation is failed on core Document tree. +func (cd *CoreDocument) CreateProofs(docType string, dataTree *proofs.DocumentTree, fields []string) (proofs []*proofspb.Proof, err error) { + srpHashes, err := cd.getSigningRootProofHashes() + if err != nil { + return nil, errors.New("failed to generate signing root proofs: %v", err) + } + + cdTree, err := cd.documentTree(docType) + if err != nil { + return nil, errors.New("failed to generate core Document tree: %v", err) + } + + dataRoot := dataTree.RootHash() + cdRoot := cdTree.RootHash() + + // try generating proofs from data root first + proofs, missedPfs := generateProofs(dataTree, fields, append([][]byte{cdRoot}, srpHashes...)) + if len(missedPfs) == 0 { + return proofs, nil + } + + // generate proofs from cdTree. fail if any proofs are missed after this + pfs, missedPfs := generateProofs(cdTree, missedPfs, append([][]byte{dataRoot}, srpHashes...)) + if len(missedPfs) > 0 { + return nil, errors.New("failed to generate proofs for %v", missedPfs) + } + + proofs = append(proofs, pfs...) + return proofs, nil +} + +func generateProofs(tree *proofs.DocumentTree, fields []string, appendHashes [][]byte) (proofs []*proofspb.Proof, missedProofs []string) { + for _, f := range fields { + proof, err := tree.CreateProof(f) + if err != nil { + // add the missed proof to the map + missedProofs = append(missedProofs, f) + continue + } + + proof.SortedHashes = append(proof.SortedHashes, appendHashes...) + proofs = append(proofs, &proof) + } + + return proofs, missedProofs +} + +// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. +// The returned proofs are appended to the proofs generated from the data tree and core Document tree for a successful verification. +func (cd *CoreDocument) getSigningRootProofHashes() (hashes [][]byte, err error) { + tree, err := cd.DocumentRootTree() + if err != nil { + return + } + + rootProof, err := tree.CreateProof("signing_root") + if err != nil { + return + } + + return rootProof.SortedHashes, err +} + +// DocumentRootTree returns the merkle tree for the Document root. +func (cd *CoreDocument) DocumentRootTree() (tree *proofs.DocumentTree, err error) { + if len(cd.Document.SigningRoot) != idSize { + return nil, errors.New("signing root is invalid") + } + + tree = NewDefaultTree(ConvertToProofSalts(cd.Document.CoredocumentSalts)) + + // The first leave added is the signing_root + err = tree.AddLeaf(proofs.LeafNode{ + Hash: cd.Document.SigningRoot, + Hashed: true, + Property: NewLeafProperty(SigningRootField, compactProperties(SigningRootField))}) + if err != nil { + return nil, err + } + + // For every signature we create a LeafNode + sigProperty := NewLeafProperty(SignaturesField, compactProperties(SignaturesField)) + sigLeafList := make([]proofs.LeafNode, len(cd.Document.Signatures)+1) + sigLengthNode := proofs.LeafNode{ + Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), + Salt: make([]byte, idSize), + Value: []byte(fmt.Sprintf("%d", len(cd.Document.Signatures))), + } + h := sha256.New() + err = sigLengthNode.HashNode(h, true) + if err != nil { + return nil, err + } + + sigLeafList[0] = sigLengthNode + for i, sig := range cd.Document.Signatures { + payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) + leaf := proofs.LeafNode{ + Hash: payload[:], + Hashed: true, + Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), + } + + err = leaf.HashNode(h, true) + if err != nil { + return nil, err + } + + sigLeafList[i+1] = leaf + } + + err = tree.AddLeaves(sigLeafList) + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + + return tree, nil +} + +// signingRootTree returns the merkle tree for the signing root. +func (cd *CoreDocument) signingRootTree(docType string) (tree *proofs.DocumentTree, err error) { + if len(cd.Document.DataRoot) != idSize { + return nil, errors.New("data root is invalid") + } + + cdTree, err := cd.documentTree(docType) + if err != nil { + return nil, err + } + + // create the signing tree with data root and coredoc root as siblings + tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(cd.Document.CoredocumentSalts), SigningTreePrefix, compactProperties(SigningTreePrefix)) + prefixProp := NewLeafProperty(SigningTreePrefix, compactProperties(SigningTreePrefix)) + + err = tree.AddLeaves([]proofs.LeafNode{ + { + Property: prefixProp.FieldProp(DataRootField, binary.LittleEndian.Uint32(compactProperties(DataRootField))), + Hash: cd.Document.DataRoot, + Hashed: true, + }, + { + Property: prefixProp.FieldProp(CDRootField, binary.LittleEndian.Uint32(compactProperties(CDRootField))), + Hash: cdTree.RootHash(), + Hashed: true, + }, + }) + + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + + return tree, nil +} + +// documentTree returns the merkle tree of the core Document. +func (cd *CoreDocument) documentTree(docType string) (tree *proofs.DocumentTree, err error) { + tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(cd.Document.CoredocumentSalts), CDTreePrefix, compactProperties(CDTreePrefix)) + err = tree.AddLeavesFromDocument(&cd.Document) + if err != nil { + return nil, err + } + + prefixProp := NewLeafProperty(CDTreePrefix, compactProperties(CDTreePrefix)) + // Adding document type as it is an excluded field in the tree + documentTypeNode := proofs.LeafNode{ + Property: prefixProp.FieldProp(DocumentTypeField, binary.LittleEndian.Uint32(compactProperties(DocumentTypeField))), + Salt: make([]byte, 32), + Value: []byte(docType), + } + + err = documentTypeNode.HashNode(sha256.New(), true) + if err != nil { + return nil, err + } + + err = tree.AddLeaf(documentTypeNode) + if err != nil { + return nil, err + } + + err = tree.Generate() + if err != nil { + return nil, err + } + + return tree, nil + +} + +// GetCollaborators returns the collaborators from the role with READ_SIGN ability. +func (cd *CoreDocument) GetCollaborators(filterIDs ...identity.DID) (ids []identity.DID, err error) { + exclude := make(map[string]struct{}) + for _, id := range filterIDs { + exclude[id.String()] = struct{}{} + } + + for _, c := range cd.Document.Collaborators { + id := identity.NewDIDFromBytes(c) + if _, ok := exclude[id.String()]; ok { + continue + } + + ids = append(ids, id) + } + + return ids, nil +} + +// fetchNewUniqueCollaborators returns the unique collaborators from newCollabs in reference to oldCollabs. +func fetchNewUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.DID, err error) { + ocsm := make(map[string]struct{}) + for _, c := range oldCollabs { + cs := strings.ToLower(hexutil.Encode(c)) + ocsm[cs] = struct{}{} + } + + var uc []string + for _, c := range newCollabs { + cs := strings.ToLower(c) + if _, ok := ocsm[cs]; ok { + continue + } + + uc = append(uc, c) + } + + for _, c := range uc { + id, err := identity.NewDIDFromString(c) + if err != nil { + return nil, err + } + + ids = append(ids, id) + } + + return ids, nil +} + +// CalculateDocumentRoot calculates the Document root of the core Document. +func (cd *CoreDocument) CalculateDocumentRoot() ([]byte, error) { + tree, err := cd.DocumentRootTree() + if err != nil { + return nil, err + } + + cd.Document.DocumentRoot = tree.RootHash() + return cd.Document.DocumentRoot, nil +} + +// SetDataRoot sets the document data root to core document. +func (cd *CoreDocument) SetDataRoot(dr []byte) { + cd.Document.DataRoot = dr +} + +// CalculateSigningRoot calculates the signing root of the core Document. +func (cd *CoreDocument) CalculateSigningRoot(docType string) ([]byte, error) { + tree, err := cd.signingRootTree(docType) + if err != nil { + return nil, err + } + + cd.Document.SigningRoot = tree.RootHash() + return cd.Document.SigningRoot, nil +} + +// PackCoreDocument prepares the document into a core document. +func (cd *CoreDocument) PackCoreDocument(data *any.Any, salts []*coredocumentpb.DocumentSalt) coredocumentpb.CoreDocument { + // lets copy the value so that mutations on the returned doc wont be reflected on Document we are holding + cdp := cd.Document + cdp.EmbeddedData = data + cdp.EmbeddedDataSalts = salts + return cdp +} + +// Signatures returns the copy of the signatures on the Document. +func (cd *CoreDocument) Signatures() (signatures []coredocumentpb.Signature) { + for _, s := range cd.Document.Signatures { + signatures = append(signatures, *s) + } + + return signatures +} diff --git a/documents/coredocument_test.go b/documents/coredocument_test.go new file mode 100644 index 000000000..d1a2e3d52 --- /dev/null +++ b/documents/coredocument_test.go @@ -0,0 +1,308 @@ +// +build unit + +package documents + +import ( + "crypto/sha256" + "os" + "testing" + + "github.com/centrifuge/go-centrifuge/testingutils/identity" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/go-centrifuge/anchors" + "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" + "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/ethereum" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/storage/leveldb" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/transactions/txv1" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/golang/protobuf/ptypes/any" + "github.com/stretchr/testify/assert" +) + +var ctx map[string]interface{} +var ConfigService config.Service +var cfg config.Configuration + +func TestMain(m *testing.M) { + ctx = make(map[string]interface{}) + ethClient := &testingcommons.MockEthClient{} + ethClient.On("GetEthClient").Return(nil) + ctx[ethereum.BootstrappedEthereumClient] = ethClient + ibootstappers := []bootstrap.TestBootstrapper{ + &testlogging.TestLoggingBootstrapper{}, + &config.Bootstrapper{}, + &leveldb.Bootstrapper{}, + &configstore.Bootstrapper{}, + txv1.Bootstrapper{}, + &queue.Bootstrapper{}, + &anchors.Bootstrapper{}, + &Bootstrapper{}, + } + ctx[identity.BootstrappedDIDService] = &testingcommons.MockIdentityService{} + ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} + bootstrap.RunTestBootstrappers(ibootstappers, ctx) + ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) + cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) + + cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") + cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") + cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") + cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") + cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") + cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") + result := m.Run() + bootstrap.RunTestTeardown(ibootstappers) + os.Exit(result) +} + +func Test_fetchUniqueCollaborators(t *testing.T) { + o1 := testingidentity.GenerateRandomDID() + o2 := testingidentity.GenerateRandomDID() + n1 := testingidentity.GenerateRandomDID() + tests := []struct { + old [][]byte + new []string + result []identity.DID + err bool + }{ + { + new: []string{n1.String()}, + result: []identity.DID{n1}, + }, + + { + old: [][]byte{o1[:]}, + new: []string{n1.String()}, + result: []identity.DID{n1}, + }, + + { + old: [][]byte{o1[:], n1[:]}, + new: []string{n1.String()}, + }, + + { + old: [][]byte{o1[:], o2[:]}, + }, + + // new collaborator with wrong format + { + old: [][]byte{o1[:], o2[:]}, + new: []string{"0x0102030405"}, + err: true, + }, + } + + for _, c := range tests { + uc, err := fetchNewUniqueCollaborators(c.old, c.new) + if err != nil { + if c.err { + continue + } + + t.Fatal(err) + } + + assert.Equal(t, c.result, uc) + } +} + +func TestCoreDocument_PrepareNewVersion(t *testing.T) { + cd := newCoreDocument() + + //collaborators need to be hex string + collabs := []string{"some ID"} + ncd, err := cd.PrepareNewVersion(collabs, false) + assert.Error(t, err) + assert.Nil(t, ncd) + + // missing DocumentRoot + c1 := testingidentity.GenerateRandomDID() + c2 := testingidentity.GenerateRandomDID() + c := []string{c1.String(), c2.String()} + ncd, err = cd.PrepareNewVersion(c, false) + assert.Error(t, err) + assert.Nil(t, ncd) + + // successful preparation of new version upon addition of DocumentRoot + cd.Document.DocumentRoot = utils.RandomSlice(32) + ncd, err = cd.PrepareNewVersion(c, false) + assert.NoError(t, err) + assert.NotNil(t, ncd) + assert.Len(t, ncd.Document.Collaborators, 2) + assert.Nil(t, ncd.Document.CoredocumentSalts) + + ncd, err = cd.PrepareNewVersion(c, true) + assert.NoError(t, err) + assert.NotNil(t, ncd) + assert.Len(t, ncd.Document.Collaborators, 2) + assert.NotNil(t, ncd.Document.CoredocumentSalts) + + assert.Equal(t, cd.Document.NextVersion, ncd.Document.CurrentVersion) + assert.Equal(t, cd.Document.CurrentVersion, ncd.Document.PreviousVersion) + assert.Equal(t, cd.Document.DocumentIdentifier, ncd.Document.DocumentIdentifier) + assert.Equal(t, cd.Document.DocumentRoot, ncd.Document.PreviousRoot) +} + +func TestGetSigningProofHashes(t *testing.T) { + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + + cd := newCoreDocument() + cd.Document.EmbeddedData = docAny + cd.Document.DataRoot = utils.RandomSlice(32) + err := cd.setSalts() + assert.NoError(t, err) + + _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) + assert.Nil(t, err) + + _, err = cd.CalculateDocumentRoot() + assert.Nil(t, err) + + hashes, err := cd.getSigningRootProofHashes() + assert.Nil(t, err) + assert.Equal(t, 1, len(hashes)) + + valid, err := proofs.ValidateProofSortedHashes(cd.Document.SigningRoot, hashes, cd.Document.DocumentRoot, sha256.New()) + assert.True(t, valid) + assert.Nil(t, err) +} + +func TestGetDocumentSigningTree(t *testing.T) { + cd := newCoreDocument() + + // no data root + _, err := cd.signingRootTree(documenttypes.InvoiceDataTypeUrl) + assert.Error(t, err) + + // successful tree generation + + cd.Document.DataRoot = utils.RandomSlice(32) + assert.NoError(t, cd.setSalts()) + tree, err := cd.signingRootTree(documenttypes.InvoiceDataTypeUrl) + assert.Nil(t, err) + assert.NotNil(t, tree) + + _, leaf := tree.GetLeafByProperty(SigningTreePrefix + ".data_root") + assert.NotNil(t, leaf) + + _, leaf = tree.GetLeafByProperty(SigningTreePrefix + ".cd_root") + assert.NotNil(t, leaf) +} + +// TestGetDocumentRootTree tests that the documentroottree is properly calculated +func TestGetDocumentRootTree(t *testing.T) { + cd := newCoreDocument() + + // no signing root generated + _, err := cd.DocumentRootTree() + assert.Error(t, err) + + // successful Document root generation + cd.Document.SigningRoot = utils.RandomSlice(32) + tree, err := cd.DocumentRootTree() + assert.NoError(t, err) + _, leaf := tree.GetLeafByProperty("signing_root") + assert.NotNil(t, leaf) + assert.Equal(t, cd.Document.SigningRoot, leaf.Hash) +} + +func TestCoreDocument_GenerateProofs(t *testing.T) { + h := sha256.New() + testTree := NewDefaultTree(nil) + props := []proofs.Property{NewLeafProperty("sample_field", []byte{0, 0, 0, 200}), NewLeafProperty("sample_field2", []byte{0, 0, 0, 202})} + compactProps := [][]byte{props[0].Compact, props[1].Compact} + err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[0]}) + assert.NoError(t, err) + err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[1]}) + assert.NoError(t, err) + err = testTree.Generate() + assert.NoError(t, err) + docAny := &any.Any{ + TypeUrl: documenttypes.InvoiceDataTypeUrl, + Value: []byte{}, + } + + cd := newCoreDocument() + cd.Document.EmbeddedData = docAny + cd.Document.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} + assert.NoError(t, cd.setSalts()) + cd.Document.DataRoot = testTree.RootHash() + _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) + assert.NoError(t, err) + _, err = cd.CalculateDocumentRoot() + assert.NoError(t, err) + + cdTree, err := cd.documentTree(documenttypes.InvoiceDataTypeUrl) + assert.NoError(t, err) + tests := []struct { + fieldName string + fromCoreDoc bool + proofLength int + }{ + { + "sample_field", + false, + 3, + }, + { + CDTreePrefix + ".document_identifier", + true, + 6, + }, + { + "sample_field2", + false, + 3, + }, + { + CDTreePrefix + ".collaborators[0]", + true, + 6, + }, + } + for _, test := range tests { + t.Run(test.fieldName, func(t *testing.T) { + p, err := cd.CreateProofs(documenttypes.InvoiceDataTypeUrl, testTree, []string{test.fieldName}) + assert.NoError(t, err) + assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) + var l *proofs.LeafNode + if test.fromCoreDoc { + _, l = cdTree.GetLeafByProperty(test.fieldName) + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:4], cdTree.RootHash(), h) + assert.NoError(t, err) + assert.True(t, valid) + } else { + _, l = testTree.GetLeafByProperty(test.fieldName) + assert.Contains(t, compactProps, l.Property.CompactName()) + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:1], testTree.RootHash(), h) + assert.NoError(t, err) + assert.True(t, valid) + } + valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.Document.DocumentRoot, h) + assert.NoError(t, err) + assert.True(t, valid) + }) + } +} + +func TestCoreDocument_setSalts(t *testing.T) { + cd := newCoreDocument() + assert.Nil(t, cd.Document.CoredocumentSalts) + + assert.NoError(t, cd.setSalts()) + salts := cd.Document.CoredocumentSalts + assert.Nil(t, cd.setSalts()) + assert.Equal(t, salts, cd.Document.CoredocumentSalts) +} diff --git a/documents/documents_test/anchor_test.go b/documents/documents_test/anchor_test.go index aac5fa601..325b57dae 100644 --- a/documents/documents_test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -7,12 +7,12 @@ import ( "errors" "testing" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -21,8 +21,8 @@ type mockAnchorProcessor struct { mock.Mock } -func (m *mockAnchorProcessor) Send(ctx context.Context, coreDocumentModel *documents.CoreDocumentModel, recipient identity.DID) (err error) { - args := m.Called(coreDocumentModel, ctx, recipient) +func (m *mockAnchorProcessor) Send(ctx context.Context, cd coredocumentpb.CoreDocument, recipient identity.DID) (err error) { + args := m.Called(ctx, cd, recipient) return args.Error(0) } @@ -65,33 +65,19 @@ func (m *mockAnchorProcessor) SendDocument(ctx context.Context, model documents. return args.Error(0) } -func (m *mockAnchorProcessor) GetDataProofHashes(coreDocument *coredocumentpb.CoreDocument) (hashes [][]byte, err error) { - args := m.Called(coreDocument) - return args.Get(0).([][]byte), args.Error(1) -} - func TestAnchorDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) updater := func(id []byte, model documents.Model) error { return nil } - // pack fails - m := &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(nil, errors.New("pack failed")).Once() - model, err := documents.AnchorDocument(ctxh, m, nil, updater) - m.AssertExpectations(t) - assert.Nil(t, model) - assert.Error(t, err) - assert.Contains(t, err.Error(), "pack failed") - // prepare fails - m = &testingdocuments.MockModel{} - dm := documents.NewCoreDocModel() - m.On("PackCoreDocument").Return(dm, nil).Once() + id := utils.RandomSlice(32) + m := &testingdocuments.MockModel{} + m.On("CurrentVersion").Return(id).Once() proc := &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(errors.New("error")).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + model, err := documents.AnchorDocument(ctxh, m, proc, updater) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -100,7 +86,7 @@ func TestAnchorDocument(t *testing.T) { // request signatures failed m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() + m.On("CurrentVersion").Return(id).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(errors.New("error")).Once() @@ -113,7 +99,7 @@ func TestAnchorDocument(t *testing.T) { // prepare for anchoring fails m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() + m.On("CurrentVersion").Return(id).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -127,7 +113,7 @@ func TestAnchorDocument(t *testing.T) { // anchor fails m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() + m.On("CurrentVersion").Return(id).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -142,7 +128,7 @@ func TestAnchorDocument(t *testing.T) { // send failed m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() + m.On("CurrentVersion").Return(id).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() @@ -158,7 +144,7 @@ func TestAnchorDocument(t *testing.T) { // success m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() + m.On("CurrentVersion").Return(id).Once() proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index c5292036e..cd635180a 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -3,11 +3,10 @@ package documents_test import ( + "context" "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -21,6 +20,8 @@ import ( "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -56,8 +57,9 @@ func TestMain(m *testing.M) { func TestService_ReceiveAnchoredDocumentFailed(t *testing.T) { poSrv := documents.DefaultService(nil, nil, documents.NewServiceRegistry(), nil) - ctxh := testingconfig.CreateAccountContext(t, cfg) - err := poSrv.ReceiveAnchoredDocument(ctxh, nil, nil) + + // self failed + err := poSrv.ReceiveAnchoredDocument(context.Background(), nil, nil) assert.Error(t, err) } @@ -82,145 +84,48 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D return docRoot, args.Error(1) } -func createAnchoredMockDocument(t *testing.T, skipSave bool) (*invoice.Invoice, error) { - cdm := documents.NewCoreDocModel() - i := &invoice.Invoice{ - InvoiceNumber: "test_invoice", - GrossAmount: 60, - CoreDocumentModel: cdm, - } - dataRoot, err := i.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the invoice - corDocMod, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - - cds, err := documents.GenerateCoreDocSalts(corDocMod.Document) - assert.Nil(t, err) - corDocMod.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cds) - - err = corDocMod.CalculateSigningRoot(dataRoot) - if err != nil { - return nil, err - } - signKey := identity.IDKey{ - PublicKey: key1Pub[:], - PrivateKey: key1, - } - idConfig := &identity.IDConfig{ - ID: cid, - Keys: map[int]identity.IDKey{ - identity.KeyPurposeSigning: signKey, - }, - } - - cd := corDocMod.Document - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, cd.SigningRoot) - - cd.Signatures = append(cd.Signatures, sig) - - err = corDocMod.CalculateDocumentRoot() - if err != nil { - return nil, err - } - err = i.UnpackCoreDocument(corDocMod) - if err != nil { - return nil, err - } - - if !skipSave { - err = testRepo().Create(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) - if err != nil { - return nil, err - } - } - - return i, nil -} - -func updatedAnchoredMockDocument(t *testing.T, i *invoice.Invoice) (*invoice.Invoice, error) { - i.GrossAmount = 50 - dataRoot, err := i.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the invoice - corDocModel, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - // hacky update to version - corDoc := corDocModel.Document - corDoc.CurrentVersion = corDoc.NextVersion - corDoc.NextVersion = utils.RandomSlice(32) - if err != nil { - return nil, err - } - err = corDocModel.CalculateSigningRoot(dataRoot) - if err != nil { - return nil, err - } - err = corDocModel.CalculateDocumentRoot() - if err != nil { - return nil, err - } - err = i.UnpackCoreDocument(corDocModel) - if err != nil { - return nil, err - } - err = testRepo().Create(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) - if err != nil { - return nil, err - } - return i, nil -} - // Functions returns service mocks -func mockSignatureCheck(i *invoice.Invoice, idService testingcommons.MockIdentityService, s documents.Service) testingcommons.MockIdentityService { - anchorID, _ := anchors.ToAnchorID(i.CoreDocumentModel.Document.DocumentIdentifier) - docRoot, _ := anchors.ToDocumentRoot(i.CoreDocumentModel.Document.DocumentRoot) +func mockSignatureCheck(t *testing.T, i *invoice.Invoice, idService testingcommons.MockIdentityService) testingcommons.MockIdentityService { + anchorID, _ := anchors.ToAnchorID(i.ID()) + dr, err := i.CalculateDocumentRoot() + assert.NoError(t, err) + docRoot, err := anchors.ToDocumentRoot(dr) + assert.NoError(t, err) mockAnchor.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() return idService } func TestService_CreateProofs(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) + i, _ := createCDWithEmbeddedInvoice(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) - idService = mockSignatureCheck(i, idService, service) - proof, err := service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invoice.invoice_number"}) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) + proof, err := service.CreateProofs(ctxh, i.ID(), []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.VersionID) + assert.Equal(t, i.ID(), proof.DocumentID) + assert.Equal(t, i.CurrentVersion(), proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - i.CoreDocumentModel.Document.SigningRoot = nil - err = testRepo().Update(tenantID, i.CoreDocumentModel.Document.CurrentVersion, i) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, service) + i, _ := createCDWithEmbeddedInvoice(t, false) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) + i.(*invoice.Invoice).Document.DataRoot = nil + i.(*invoice.Invoice).Document.SigningRoot = nil + assert.Nil(t, testRepo().Update(tenantID, i.CurrentVersion(), i)) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invoice.invoice_number"}) - assert.NotNil(t, err) - assert.Contains(t, err.Error(), "signing root missing") + _, err := service.CreateProofs(ctxh, i.ID(), []string{"invoice.invoice_number"}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get signing root") } func TestService_CreateProofsInvalidField(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, service) + i, _ := createCDWithEmbeddedInvoice(t, false) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = service.CreateProofs(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, []string{"invalid_field"}) + _, err := service.CreateProofs(ctxh, i.CurrentVersion(), []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) } @@ -235,27 +140,23 @@ func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { func TestService_CreateProofsForVersion(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, false) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, service) - olderVersion := i.CoreDocumentModel.Document.CurrentVersion - i, err = updatedAnchoredMockDocument(t, i) - assert.Nil(t, err) + i, _ := createCDWithEmbeddedInvoice(t, false) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) ctxh := testingconfig.CreateAccountContext(t, cfg) - proof, err := service.CreateProofsForVersion(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, olderVersion, []string{"invoice.invoice_number"}) + proof, err := service.CreateProofsForVersion(ctxh, i.ID(), i.CurrentVersion(), []string{"invoice.invoice_number"}) assert.Nil(t, err) - assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, proof.DocumentID) - assert.Equal(t, olderVersion, proof.VersionID) + assert.Equal(t, i.ID(), proof.DocumentID) + assert.Equal(t, i.CurrentVersion(), proof.VersionID) assert.Equal(t, len(proof.FieldProofs), 1) assert.Equal(t, proof.FieldProofs[0].GetCompactName(), []byte{0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}) } func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, err := createAnchoredMockDocument(t, true) - assert.Nil(t, err) - idService = mockSignatureCheck(i, idService, service) - i.CoreDocumentModel.Document.SigningRoot = nil + i, _ := createCDWithEmbeddedInvoice(t, true) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) + i.(*invoice.Invoice).Document.DataRoot = nil + i.(*invoice.Invoice).Document.SigningRoot = nil ctxh := testingconfig.CreateAccountContext(t, cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) @@ -264,11 +165,10 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { - i, err := createAnchoredMockDocument(t, false) + i, _ := createCDWithEmbeddedInvoice(t, false) s, _ := getServiceWithMockedLayers() - assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = s.CreateProofsForVersion(ctxh, i.CoreDocumentModel.Document.DocumentIdentifier, utils.RandomSlice(32), []string{"invoice.invoice_number"}) + _, err := s.CreateProofsForVersion(ctxh, i.ID(), utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) } @@ -292,18 +192,15 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { next = nonExistingVersion } - cd := &coredocumentpb.CoreDocument{ + cd := coredocumentpb.CoreDocument{ DocumentIdentifier: documentIdentifier, CurrentVersion: version, NextVersion: next, } inv := &invoice.Invoice{ - GrossAmount: int64(i + 1), - CoreDocumentModel: &documents.CoreDocumentModel{ - Document: cd, - TokenRegistry: nil, - }, + GrossAmount: int64(i + 1), + CoreDocument: documents.NewCoreDocumentFromProtobuf(cd), } err := testRepo().Create(tenantID, version, inv) @@ -316,13 +213,8 @@ func TestService_GetCurrentVersion_successful(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) model, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.Nil(t, err) - - dm, err := model.PackCoreDocument() - cd := dm.Document - assert.Nil(t, err) - - assert.Equal(t, cd.CurrentVersion, currentVersion, "should return latest version") - assert.Equal(t, cd.NextVersion, nonExistingVersion, "latest version should have a non existing id as nextVersion ") + assert.Equal(t, model.CurrentVersion(), currentVersion, "should return latest version") + assert.Equal(t, model.NextVersion(), nonExistingVersion, "latest version should have a non existing id as nextVersion ") } @@ -330,16 +222,13 @@ func TestService_GetVersion_successful(t *testing.T) { service, _ := getServiceWithMockedLayers() documentIdentifier := utils.RandomSlice(32) currentVersion := utils.RandomSlice(32) - cd := &coredocumentpb.CoreDocument{ + cd := coredocumentpb.CoreDocument{ DocumentIdentifier: documentIdentifier, CurrentVersion: currentVersion, } inv := &invoice.Invoice{ - GrossAmount: 60, - CoreDocumentModel: &documents.CoreDocumentModel{ - cd, - nil, - }, + GrossAmount: 60, + CoreDocument: documents.NewCoreDocumentFromProtobuf(cd), } ctxh := testingconfig.CreateAccountContext(t, cfg) @@ -349,11 +238,8 @@ func TestService_GetVersion_successful(t *testing.T) { mod, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.Nil(t, err) - dm, err := mod.PackCoreDocument() - assert.Nil(t, err) - - assert.Equal(t, documentIdentifier, dm.Document.DocumentIdentifier, "should be same document Identifier") - assert.Equal(t, currentVersion, dm.Document.CurrentVersion, "should be same version") + assert.Equal(t, documentIdentifier, mod.ID(), "should be same document Identifier") + assert.Equal(t, currentVersion, mod.CurrentVersion(), "should be same version") } func TestService_GetCurrentVersion_error(t *testing.T) { @@ -365,17 +251,14 @@ func TestService_GetCurrentVersion_error(t *testing.T) { _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) - cd := &coredocumentpb.CoreDocument{ + cd := coredocumentpb.CoreDocument{ DocumentIdentifier: documentIdentifier, CurrentVersion: documentIdentifier, } inv := &invoice.Invoice{ - GrossAmount: 60, - CoreDocumentModel: &documents.CoreDocumentModel{ - cd, - nil, - }, + GrossAmount: 60, + CoreDocument: documents.NewCoreDocumentFromProtobuf(cd), } err = testRepo().Create(tenantID, documentIdentifier, inv) @@ -397,16 +280,13 @@ func TestService_GetVersion_error(t *testing.T) { _, err := service.GetVersion(ctxh, documentIdentifier, currentVersion) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) - cd := &coredocumentpb.CoreDocument{ + cd := coredocumentpb.CoreDocument{ DocumentIdentifier: documentIdentifier, CurrentVersion: currentVersion, } inv := &invoice.Invoice{ - GrossAmount: 60, - CoreDocumentModel: &documents.CoreDocumentModel{ - cd, - nil, - }, + GrossAmount: 60, + CoreDocument: documents.NewCoreDocumentFromProtobuf(cd), } err = testRepo().Create(tenantID, currentVersion, inv) assert.Nil(t, err) @@ -441,16 +321,13 @@ func TestService_Exists(t *testing.T) { _, err := service.GetCurrentVersion(ctxh, documentIdentifier) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) - cd := &coredocumentpb.CoreDocument{ + cd := coredocumentpb.CoreDocument{ DocumentIdentifier: documentIdentifier, CurrentVersion: documentIdentifier, } inv := &invoice.Invoice{ - GrossAmount: 60, - CoreDocumentModel: &documents.CoreDocumentModel{ - cd, - nil, - }, + GrossAmount: 60, + CoreDocument: documents.NewCoreDocumentFromProtobuf(cd), } err = testRepo().Create(tenantID, documentIdentifier, inv) @@ -462,3 +339,37 @@ func TestService_Exists(t *testing.T) { assert.False(t, exists, "document should not exist") } + +func createCDWithEmbeddedInvoice(t *testing.T, skipSave bool) (documents.Model, coredocumentpb.CoreDocument) { + i := new(invoice.Invoice) + err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), cid.String()) + assert.NoError(t, err) + _, err = i.CalculateDataRoot() + assert.NoError(t, err) + sr, err := i.CalculateSigningRoot() + assert.NoError(t, err) + + signKey := identity.IDKey{ + PublicKey: key1Pub[:], + PrivateKey: key1, + } + idConfig := &identity.IDConfig{ + ID: cid, + Keys: map[int]identity.IDKey{ + identity.KeyPurposeSigning: signKey, + }, + } + + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) + i.AppendSignatures(sig) + _, err = i.CalculateDocumentRoot() + assert.NoError(t, err) + cd, err := i.PackCoreDocument() + assert.NoError(t, err) + + if !skipSave { + err = testRepo().Create(tenantID, i.CurrentVersion(), i) + assert.NoError(t, err) + } + return i, cd +} diff --git a/documents/invoice/handler_test.go b/documents/invoice/handler_test.go index a9351d5f0..2a626f0ae 100644 --- a/documents/invoice/handler_test.go +++ b/documents/invoice/handler_test.go @@ -6,16 +6,13 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/transactions" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -107,16 +104,10 @@ type mockModel struct { CoreDocument *coredocumentpb.CoreDocument } -func (m *mockModel) PackCoreDocument() (*documents.CoreDocumentModel, error) { - args := m.Called() - dm, _ := args.Get(0).(*documents.CoreDocumentModel) - return dm, args.Error(1) -} - -func (m *mockModel) JSON() ([]byte, error) { +func (m *mockModel) ID() []byte { args := m.Called() - data, _ := args.Get(0).([]byte) - return data, args.Error(1) + id, _ := args.Get(0).([]byte) + return id } func TestGRPCHandler_Create_DeriveInvoiceResponse_fail(t *testing.T) { diff --git a/documents/invoice/model.go b/documents/invoice/model.go index 5edda6b67..a228f226a 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -4,15 +4,16 @@ import ( "encoding/json" "reflect" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" @@ -26,6 +27,8 @@ func compactPrefix() []byte { return []byte{0, 1, 0, 0} } // Invoice implements the documents.Model keeps track of invoice related fields and state type Invoice struct { + *documents.CoreDocument + InvoiceNumber string // invoice number or reference number SenderName string // name of the sender company SenderStreet string // street and address details of the sender company @@ -50,8 +53,7 @@ type Invoice struct { DateCreated *timestamp.Timestamp ExtraData []byte - InvoiceSalts *proofs.Salts - CoreDocumentModel *documents.CoreDocumentModel + InvoiceSalts *proofs.Salts } // getClientData returns the client data from the invoice model @@ -155,11 +157,12 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload } collaborators := append([]string{self}, payload.Collaborators...) - i.CoreDocumentModel, err = documents.NewWithCollaborators(collaborators) + cd, err := documents.NewCoreDocumentWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } + i.CoreDocument = cd return nil } @@ -268,79 +271,52 @@ func (i *Invoice) getInvoiceSalts(invoiceData *invoicepb.InvoiceData) (*proofs.S return i.InvoiceSalts, nil } -// ID returns document identifier. -// Note: this is not a unique identifier for each version of the document. -func (i *Invoice) ID() ([]byte, error) { - coreDocModel, err := i.PackCoreDocument() +// PackCoreDocument packs the Invoice into a CoreDocument. +func (i *Invoice) PackCoreDocument() (cd coredocumentpb.CoreDocument, err error) { + invData := i.createP2PProtobuf() + data, err := proto.Marshal(invData) if err != nil { - return []byte{}, err + return cd, errors.New("couldn't serialise InvoiceData: %v", err) } - return coreDocModel.Document.DocumentIdentifier, nil -} -// PackCoreDocument packs the Invoice into a Core Document -// If the, Invoice is new, it creates a valid identifiers -func (i *Invoice) PackCoreDocument() (*documents.CoreDocumentModel, error) { - invoiceData := i.createP2PProtobuf() - serializedInvoice, err := proto.Marshal(invoiceData) - if err != nil { - return nil, errors.NewTypedError(err, errors.New("couldn't serialise InvoiceData")) - } - - invoiceAny := any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInvoice, - } - - invoiceSalts, err := i.getInvoiceSalts(invoiceData) - if err != nil { - return nil, errors.NewTypedError(err, errors.New("couldn't get InvoiceSalts")) + embedData := &any.Any{ + TypeUrl: i.DocumentType(), + Value: data, } - err = i.CoreDocumentModel.PackCoreDocument(&invoiceAny, documents.ConvertToProtoSalts(invoiceSalts)) + salts, err := i.getInvoiceSalts(invData) if err != nil { - return nil, err + return cd, errors.New("couldn't get InvoiceSalts: %v", err) } - return i.CoreDocumentModel, nil + return i.CoreDocument.PackCoreDocument(embedData, documents.ConvertToProtoSalts(salts)), nil } -// UnpackCoreDocument unpacks the core document into Invoice -func (i *Invoice) UnpackCoreDocument(coreDocModel *documents.CoreDocumentModel) error { - if coreDocModel == nil { - return errors.New("coredocmodel is nil %v", coreDocModel) - } - if coreDocModel.Document == nil { - return errors.New("core document provided is nil %v", coreDocModel.Document) - } - - coreDoc := coreDocModel.Document - - if coreDoc.EmbeddedData == nil || - coreDoc.EmbeddedData.TypeUrl != documenttypes.InvoiceDataTypeUrl { +// UnpackCoreDocument unpacks the core document into Invoice. +func (i *Invoice) UnpackCoreDocument(cd coredocumentpb.CoreDocument) error { + if cd.EmbeddedData == nil || + cd.EmbeddedData.TypeUrl != i.DocumentType() { return errors.New("trying to convert document with incorrect schema") } - invoiceData := &invoicepb.InvoiceData{} - err := proto.Unmarshal(coreDoc.EmbeddedData.Value, invoiceData) + invoiceData := new(invoicepb.InvoiceData) + err := proto.Unmarshal(cd.EmbeddedData.Value, invoiceData) if err != nil { return err } i.loadFromP2PProtobuf(invoiceData) - - if coreDoc.EmbeddedDataSalts == nil { + if cd.EmbeddedDataSalts == nil { i.InvoiceSalts, err = i.getInvoiceSalts(invoiceData) if err != nil { return err } } else { - i.InvoiceSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) + i.InvoiceSalts = documents.ConvertToProofSalts(cd.EmbeddedDataSalts) } - err = i.CoreDocumentModel.UnpackCoreDocument() - return err - + i.CoreDocument = documents.NewCoreDocumentFromProtobuf(cd) + return nil } // JSON marshals Invoice into a json bytes @@ -358,13 +334,16 @@ func (i *Invoice) Type() reflect.Type { return reflect.TypeOf(i) } -// CalculateDataRoot calculates the data root and sets the root to core document +// CalculateDataRoot calculates the data root and sets the root to core document. func (i *Invoice) CalculateDataRoot() ([]byte, error) { t, err := i.getDocumentDataTree() if err != nil { - return nil, errors.New("calculateDataRoot error %v", err) + return nil, errors.New("failed to get data tree: %v", err) } - return t.RootHash(), nil + + dr := t.RootHash() + i.CoreDocument.SetDataRoot(dr) + return dr, nil } // getDocumentDataTree creates precise-proofs data tree for the model @@ -386,20 +365,60 @@ func (i *Invoice) getDocumentDataTree() (tree *proofs.DocumentTree, err error) { return t, nil } -// CreateProofs generates proofs for given fields +// CreateProofs generates proofs for given fields. func (i *Invoice) CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) { - // There can be failure scenarios where the core doc for the particular document - // is still not saved with roots in db due to failures during getting signatures. - _, err = i.PackCoreDocument() + tree, err := i.getDocumentDataTree() if err != nil { return nil, errors.New("createProofs error %v", err) } - tree, err := i.getDocumentDataTree() + return i.CoreDocument.CreateProofs(i.DocumentType(), tree, fields) +} + +// DocumentType returns the invoice document type. +func (*Invoice) DocumentType() string { + return documenttypes.InvoiceDataTypeUrl +} + +// PrepareNewVersion prepares new version from the old invoice. +func (i *Invoice) PrepareNewVersion(old documents.Model, data *clientinvoicepb.InvoiceData, collaborators []string) error { + err := i.initInvoiceFromData(data) if err != nil { - return nil, errors.New("createProofs error %v", err) + return err + } + + oldCD := old.(*Invoice).CoreDocument + i.CoreDocument, err = oldCD.PrepareNewVersion(collaborators, true) + if err != nil { + return err + } + + return nil +} + +// AddNFT adds NFT to the Invoice. +func (i *Invoice) AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) error { + cd, err := i.CoreDocument.AddNFT(grantReadAccess, registry, tokenID) + if err != nil { + return err } - proofs, err = i.CoreDocumentModel.CreateProofs(tree, fields) - return proofs, err + i.CoreDocument = cd + return nil +} + +// CalculateSigningRoot calculates the signing root of the document. +func (i *Invoice) CalculateSigningRoot() ([]byte, error) { + return i.CoreDocument.CalculateSigningRoot(i.DocumentType()) +} + +// CreateNFTProofs creates proofs specific to NFT minting. +func (i *Invoice) CreateNFTProofs( + account identity.DID, + registry common.Address, + tokenID []byte, + nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { + return i.CoreDocument.CreateNFTProofs( + i.DocumentType(), + account, registry, tokenID, nftUniqueProof, readAccessProof) } diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index c402971f0..f18f35842 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -5,15 +5,9 @@ package invoice import ( "encoding/json" "os" - "reflect" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - - "github.com/centrifuge/go-centrifuge/identity/ideth" - - "github.com/stretchr/testify/mock" - + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -24,6 +18,8 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" @@ -31,12 +27,14 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) var ctx = map[string]interface{}{} @@ -51,7 +49,7 @@ func TestMain(m *testing.M) { ctx[transactions.BootstrappedService] = txMan done := make(chan bool) txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(transactions.NilTxID(), done, nil) - + ctx[nft.BootstrappedPayObService] = new(testingdocuments.MockRegistry) ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -75,110 +73,69 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestInvoice_FromCoreDocuments_invalidParameter(t *testing.T) { - invoiceModel := &Invoice{} - - emptyCoreDocModel := &documents.CoreDocumentModel{ - nil, - nil, - } - err := invoiceModel.UnpackCoreDocument(emptyCoreDocModel) - assert.Error(t, err, "it should not be possible to init with an empty core document") - - err = invoiceModel.UnpackCoreDocument(nil) - assert.Error(t, err, "it should not be possible to init with an empty core document") - - invalidEmbeddedData := &any.Any{TypeUrl: "invalid"} - coreDocument := &coredocumentpb.CoreDocument{EmbeddedData: invalidEmbeddedData} - coreDocModel := &documents.CoreDocumentModel{ - coreDocument, - nil, - } - err = invoiceModel.UnpackCoreDocument(coreDocModel) - assert.Error(t, err, "it should not be possible to init invalid typeUrl") - -} - -func TestInvoice_InitCoreDocument_successful(t *testing.T) { - invoiceModel := &Invoice{} - - dm := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - invoiceModel.CoreDocumentModel = dm - err := invoiceModel.UnpackCoreDocument(dm) - assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") -} - -func TestInvoice_CoreDocument_successful(t *testing.T) { - invoiceModel := &Invoice{} - - //init model with a CoreDocModel - - coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - invoiceModel.CoreDocumentModel = coreDocumentModel - invoiceModel.UnpackCoreDocument(coreDocumentModel) - - returnedCoreDocumentModel, err := invoiceModel.PackCoreDocument() - assert.Nil(t, err, "transformation from invoice to CoreDocModel failed") - - assert.Equal(t, coreDocumentModel.Document.EmbeddedData, returnedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, returnedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") -} +func TestInvoice_PackCoreDocument(t *testing.T) { + id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + assert.NoError(t, err) -func TestInvoice_ModelInterface(t *testing.T) { - var i interface{} = &Invoice{} - _, ok := i.(documents.Model) - assert.True(t, ok, "model interface not implemented correctly for invoiceModel") -} + inv := new(Invoice) + assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String())) -func TestInvoice_Type(t *testing.T) { - var model documents.Model - model = &Invoice{} - assert.Equal(t, model.Type(), reflect.TypeOf(&Invoice{}), "InvoiceType not correct") + cd, err := inv.PackCoreDocument() + assert.NoError(t, err) + assert.NotNil(t, cd.EmbeddedData) + assert.NotNil(t, cd.EmbeddedDataSalts) } func TestInvoice_JSON(t *testing.T) { - invoiceModel := &Invoice{} - - //init model with a CoreDocModel - coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - invoiceModel.CoreDocumentModel = coreDocumentModel - invoiceModel.UnpackCoreDocument(coreDocumentModel) + inv := new(Invoice) + id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + assert.NoError(t, err) + assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String())) - jsonBytes, err := invoiceModel.JSON() + cd, err := inv.PackCoreDocument() + assert.NoError(t, err) + jsonBytes, err := inv.JSON() assert.Nil(t, err, "marshal to json didn't work correctly") assert.True(t, json.Valid(jsonBytes), "json format not correct") - err = invoiceModel.FromJSON(jsonBytes) + inv = new(Invoice) + err = inv.FromJSON(jsonBytes) assert.Nil(t, err, "unmarshal JSON didn't work correctly") - receivedCoreDocumentModel, err := invoiceModel.PackCoreDocument() + ncd, err := inv.PackCoreDocument() assert.Nil(t, err, "JSON unmarshal damaged invoice variables") - assert.Equal(t, receivedCoreDocumentModel.Document.EmbeddedData, coreDocumentModel.Document.EmbeddedData, "JSON unmarshal damaged invoice variables") + assert.Equal(t, cd, ncd) } func TestInvoiceModel_UnpackCoreDocument(t *testing.T) { var model = new(Invoice) var err error - // nil core doc - err = model.UnpackCoreDocument(nil) - assert.Error(t, err, "unpack must fail") - // embed data missing - err = model.UnpackCoreDocument(new(documents.CoreDocumentModel)) - assert.Error(t, err, "unpack must fail due to missing embed data") + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{}) + assert.Error(t, err) - // successful - coreDocumentModel := CreateCDWithEmbeddedInvoice(t, testingdocuments.CreateInvoiceData()) - model.CoreDocumentModel = coreDocumentModel - err = model.UnpackCoreDocument(coreDocumentModel) - assert.Nil(t, err, "valid core document with embedded invoice shouldn't produce an error") + // embed data type is wrong + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{EmbeddedData: new(any.Any)}) + assert.Error(t, err, "unpack must fail due to missing embed data") - receivedCoreDocumentModel, err := model.PackCoreDocument() - assert.Nil(t, err, "model should be able to return the core document with embedded invoice") + // embed data is wrong + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{ + EmbeddedData: &any.Any{ + Value: utils.RandomSlice(32), + TypeUrl: documenttypes.InvoiceDataTypeUrl, + }, + }) + assert.Error(t, err) - assert.Equal(t, coreDocumentModel.Document.EmbeddedData, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, receivedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") + // successful + inv, cd := createCDWithEmbeddedInvoice(t) + err = model.UnpackCoreDocument(cd) + assert.NoError(t, err) + assert.Equal(t, model.getClientData(), inv.(*Invoice).getClientData()) + assert.Equal(t, model.ID(), inv.ID()) + assert.Equal(t, model.CurrentVersion(), inv.CurrentVersion()) + assert.Equal(t, model.PreviousVersion(), inv.PreviousVersion()) } func TestInvoiceModel_getClientData(t *testing.T) { @@ -256,7 +213,6 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { assert.Equal(t, inv.Payee[:], payeeDID[:]) assert.Equal(t, inv.Recipient[:], recipientDID[:]) assert.Equal(t, inv.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - assert.Equal(t, inv.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], collab1[:], collab2[:]}) } func TestInvoiceModel_calculateDataRoot(t *testing.T) { @@ -272,13 +228,13 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { assert.NotNil(t, m.InvoiceSalts, "salts must be created") } -func TestInvoiceModel_createProofs(t *testing.T) { - i, err := createMockInvoice(t) +func TestInvoice_GenerateProofs(t *testing.T) { + i, err := createInvoice(t) assert.Nil(t, err) proof, err := i.CreateProofs([]string{"invoice.invoice_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) - tree, err := i.CoreDocumentModel.GetDocumentRootTree() + tree, err := i.CoreDocument.DocumentRootTree() assert.NoError(t, err) // Validate invoice_number @@ -292,7 +248,8 @@ func TestInvoiceModel_createProofs(t *testing.T) { assert.True(t, valid) // Validate []byte value - assert.Equal(t, i.CoreDocumentModel.Document.Collaborators[0], proof[1].Value) + id := identity.NewDIDFromBytes(proof[1].Value) + assert.True(t, i.CoreDocument.AccountCanRead(id)) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -301,17 +258,16 @@ func TestInvoiceModel_createProofs(t *testing.T) { } func TestInvoiceModel_createProofsFieldDoesNotExist(t *testing.T) { - i, err := createMockInvoice(t) + i, err := createInvoice(t) assert.Nil(t, err) _, err = i.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } func TestInvoiceModel_GetDocumentID(t *testing.T) { - i, err := createMockInvoice(t) + i, err := createInvoice(t) assert.Nil(t, err) - ID, err := i.ID() - assert.Equal(t, i.CoreDocumentModel.Document.DocumentIdentifier, ID) + assert.Equal(t, i.CoreDocument.ID(), i.ID()) } func TestInvoiceModel_getDocumentDataTree(t *testing.T) { @@ -323,28 +279,15 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { assert.Equal(t, "invoice.invoice_number", leaf.Property.ReadableName()) } -func createMockInvoice(t *testing.T) (*Invoice, error) { - i := &Invoice{InvoiceNumber: "3213121", NetAmount: 2, GrossAmount: 2, Currency: "USD", CoreDocumentModel: documents.NewCoreDocModel()} - i.CoreDocumentModel.Document.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} - dataRoot, err := i.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the invoice - - cdm, err := i.PackCoreDocument() - if err != nil { - return nil, err - } - - err = cdm.CalculateSigningRoot(dataRoot) - if err != nil { - return nil, err - } - err = cdm.CalculateDocumentRoot() - if err != nil { - return nil, err - } - i.UnpackCoreDocument(cdm) +func createInvoice(t *testing.T) (*Invoice, error) { + i := new(Invoice) + err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), "0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + _, err = i.CalculateDataRoot() + assert.NoError(t, err) + _, err = i.CalculateSigningRoot() + assert.NoError(t, err) + _, err = i.CalculateDocumentRoot() + assert.NoError(t, err) return i, nil } diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 9db88ea5c..711a87a2f 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -3,10 +3,10 @@ package invoice import ( "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -54,17 +54,15 @@ func DefaultService( } } -// DeriveFromCoreDocumentModel takes a core document model and returns an invoice -func (s service) DeriveFromCoreDocumentModel(dm *documents.CoreDocumentModel) (documents.Model, error) { - var model documents.Model = &Invoice{ - CoreDocumentModel: dm, - } - err := model.UnpackCoreDocument(dm) +// DeriveFromCoreDocument takes a core document model and returns an invoice +func (s service) DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (documents.Model, error) { + inv := new(Invoice) + err := inv.UnpackCoreDocument(cd) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - return model, nil + return inv, nil } // UnpackFromCreatePayload initializes the model with parameters provided from the rest-api call @@ -79,9 +77,6 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv } invoiceModel := new(Invoice) - if invoiceModel.CoreDocumentModel == nil { - invoiceModel.CoreDocumentModel = documents.NewCoreDocModel() - } err = invoiceModel.InitInvoiceInput(payload, id.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) @@ -109,7 +104,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], inv.CoreDocumentModel.Document.CurrentVersion, inv) + err = s.repo.Create(self.ID[:], inv.CurrentVersion(), inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -129,14 +124,8 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod return nil, transactions.NilTxID(), nil, err } - dm, err := inv.PackCoreDocument() - if err != nil { - return nil, transactions.NilTxID(), nil, err - } - - DID := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, DID, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, inv.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -144,57 +133,51 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod } // Update finds the old document, validates the new version and persists the updated document -func (s service) Update(ctx context.Context, inv documents.Model) (documents.Model, transactions.TxID, chan bool, error) { +func (s service) Update(ctx context.Context, new documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - dm, err := inv.PackCoreDocument() - if err != nil { - return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, new.ID()) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - inv, err = s.validateAndPersist(ctx, old, inv, UpdateValidator()) + new, err = s.validateAndPersist(ctx, old, new, UpdateValidator()) if err != nil { return nil, transactions.NilTxID(), nil, err } - did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, new.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } - return inv, txID, done, nil + return new, txID, done, nil } // DeriveInvoiceResponse returns create response from invoice model -func (s service) DeriveInvoiceResponse(doc documents.Model) (*clientinvoicepb.InvoiceResponse, error) { - dm, err := doc.PackCoreDocument() +func (s service) DeriveInvoiceResponse(model documents.Model) (*clientinvoicepb.InvoiceResponse, error) { + data, err := s.DeriveInvoiceData(model) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, err } - cd := dm.Document - collaborators := make([]string, len(cd.Collaborators)) - for i, c := range cd.Collaborators { - cid := identity.NewDIDFromBytes(c) - collaborators[i] = cid.String() + + cs, err := model.GetCollaborators() + if err != nil { + return nil, errors.New("failed to get collaborators: %v", err) } - h := &clientinvoicepb.ResponseHeader{ - DocumentId: hexutil.Encode(cd.DocumentIdentifier), - VersionId: hexutil.Encode(cd.CurrentVersion), - Collaborators: collaborators, + var css []string + for _, c := range cs { + css = append(css, c.String()) } - data, err := s.DeriveInvoiceData(doc) - if err != nil { - return nil, err + h := &clientinvoicepb.ResponseHeader{ + DocumentId: hexutil.Encode(model.ID()), + VersionId: hexutil.Encode(model.CurrentVersion()), + Collaborators: css, } return &clientinvoicepb.InvoiceResponse{ @@ -231,28 +214,11 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientinv return nil, err } - // load invoice data inv := new(Invoice) - err = inv.initInvoiceFromData(payload.Data) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentInvalid, errors.New("failed to load invoice from data: %v", err)) - } - - // update core document - oldDM, err := old.PackCoreDocument() + err = inv.PrepareNewVersion(old, payload.Data, payload.Collaborators) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, errors.New("failed to load invoice from data: %v", err)) } - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigAccountID - } - - collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) - inv.CoreDocumentModel, err = oldDM.PrepareNewVersion(collaborators) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) - } return inv, nil } diff --git a/documents/invoice/service_test.go b/documents/invoice/service_test.go index 48bd29cbe..5708e534d 100644 --- a/documents/invoice/service_test.go +++ b/documents/invoice/service_test.go @@ -5,20 +5,18 @@ package invoice import ( "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/errors" clientinvoicepb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/gocelery" @@ -44,13 +42,6 @@ func (r *mockAnchorRepo) GetDocumentRootOf(anchorID anchors.AnchorID) (anchors.D return docRoot, args.Error(1) } -func TestDefaultService(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil).Once() - srv := DefaultService(nil, testRepo(), nil, nil) - assert.NotNil(t, srv, "must be non-nil") -} - func getServiceWithMockedLayers() (testingcommons.MockIdentityService, Service) { c := &testingconfig.MockConfig{} c.On("GetIdentityID").Return(centIDBytes, nil) @@ -69,248 +60,52 @@ func getServiceWithMockedLayers() (testingcommons.MockIdentityService, Service) ctx[transactions.BootstrappedService].(transactions.Manager)) } -func createMockDocument() (*Invoice, error) { - documentIdentifier := utils.RandomSlice(32) - nextIdentifier := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - NextVersion: nextIdentifier, - } - dm := documents.NewCoreDocModel() - dm.Document = coreDoc - inv1 := &Invoice{ - InvoiceNumber: "test_invoice", - GrossAmount: 60, - CoreDocumentModel: dm, - } - err := testRepo().Create(accountID, documentIdentifier, inv1) - return inv1, err -} - -func TestService_DeriveFromCoreDocument(t *testing.T) { - // nil doc - invSrv := service{repo: testRepo()} - _, err := invSrv.DeriveFromCoreDocumentModel(nil) - assert.Error(t, err, "must fail to derive") - - // successful - data := testingdocuments.CreateInvoiceData() - coreDocModel := CreateCDWithEmbeddedInvoice(t, data) - model, err := invSrv.DeriveFromCoreDocumentModel(coreDocModel) - assert.Nil(t, err, "must return model") - assert.NotNil(t, model, "model must be non-nil") - inv, ok := model.(*Invoice) - assert.True(t, ok, "must be true") - assert.Equal(t, inv.Payee[:], data.Payee) - assert.Equal(t, inv.Sender[:], data.Sender) - assert.Equal(t, inv.Recipient[:], data.Recipient) - assert.Equal(t, inv.GrossAmount, data.GrossAmount) -} - -func TestService_DeriveFromPayload(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - payload := testingdocuments.CreateInvoicePayload() - var model documents.Model - var err error - - // fail due to nil payload - _, err = invSrv.DeriveFromCreatePayload(nil, nil) - assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - - // fail due to nil payload data - _, err = invSrv.DeriveFromCreatePayload(nil, &clientinvoicepb.InvoiceCreatePayload{}) - assert.Error(t, err, "DeriveWithInvoiceInput should produce an error if invoiceInput equals nil") - - model, err = invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) - assert.Nil(t, err, "valid invoiceData shouldn't produce an error") - - receivedCoreDocumentModel, err := model.PackCoreDocument() - assert.Nil(t, err, "model should be able to return the core document with embedded invoice") - assert.NotNil(t, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be field") -} - -func TestService_GetLastVersion(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - thirdIdentifier := utils.RandomSlice(32) - doc, err := createMockDocument() - assert.Nil(t, err) - - ctxh := testingconfig.CreateAccountContext(t, cfg) - mod1, err := invSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) - assert.Nil(t, err) - - invLoad1, _ := mod1.(*Invoice) - assert.Equal(t, invLoad1.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.DocumentIdentifier) - - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: doc.CoreDocumentModel.Document.DocumentIdentifier, - CurrentVersion: doc.CoreDocumentModel.Document.NextVersion, - NextVersion: thirdIdentifier, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - inv2 := &Invoice{ - GrossAmount: 60, - CoreDocumentModel: coreDocModel, - } - cd := doc.CoreDocumentModel.Document - err = testRepo().Create(accountID, cd.NextVersion, inv2) - assert.Nil(t, err) - - mod2, err := invSrv.GetCurrentVersion(ctxh, cd.DocumentIdentifier) - assert.Nil(t, err) - - invLoad2, _ := mod2.(*Invoice) - assert.Equal(t, invLoad2.CoreDocumentModel.Document.CurrentVersion, cd.NextVersion) - assert.Equal(t, invLoad2.CoreDocumentModel.Document.NextVersion, thirdIdentifier) -} - -func TestService_GetVersion_wrongTyp(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - currentVersion := utils.RandomSlice(32) - documentIdentifier := utils.RandomSlice(32) - - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - //should be an invoice - po := &purchaseorder.PurchaseOrder{ - NetAmount: 60, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, currentVersion, po) - assert.Nil(t, err) - - ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) - assert.Error(t, err) - -} - -func TestService_GetVersion(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - documentIdentifier := utils.RandomSlice(32) - currentVersion := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - inv := &Invoice{ - GrossAmount: 60, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, currentVersion, inv) - assert.Nil(t, err) - +func TestService_Update(t *testing.T) { + _, srv := getServiceWithMockedLayers() + invSrv := srv.(service) ctxh := testingconfig.CreateAccountContext(t, cfg) - mod, err := invSrv.GetVersion(ctxh, documentIdentifier, currentVersion) - assert.Nil(t, err) - loadInv, _ := mod.(*Invoice) - assert.Equal(t, loadInv.CoreDocumentModel.Document.CurrentVersion, currentVersion) - assert.Equal(t, loadInv.CoreDocumentModel.Document.DocumentIdentifier, documentIdentifier) - mod, err = invSrv.GetVersion(ctxh, documentIdentifier, []byte{}) + // missing last version + model, _ := createCDWithEmbeddedInvoice(t) + _, _, _, err := invSrv.Update(ctxh, model) assert.Error(t, err) -} - -func TestService_Exists(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - documentIdentifier := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - inv := &Invoice{ - GrossAmount: 60, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, documentIdentifier, inv) - assert.Nil(t, err) - - ctxh := testingconfig.CreateAccountContext(t, cfg) - exists := invSrv.Exists(ctxh, documentIdentifier) - assert.True(t, exists, "invoice should exist") - - exists = invSrv.Exists(ctxh, utils.RandomSlice(32)) - assert.False(t, exists, "invoice should not exist") - -} - -func TestService_Create(t *testing.T) { - ctxh := testingconfig.CreateAccountContext(t, cfg) - _, srv := getServiceWithMockedLayers() - invSrv := srv.(service) + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) + assert.NoError(t, testRepo().Create(accountID, model.CurrentVersion(), model)) // calculate data root fails - m, _, _, err := invSrv.Create(ctxh, &testingdocuments.MockModel{}) - assert.Nil(t, m) + nm := new(mockModel) + nm.On("ID").Return(model.ID(), nil).Once() + _, _, _, err = invSrv.Update(ctxh, nm) + nm.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") - // anchor success - po, err := invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) + // success + data, err := invSrv.DeriveInvoiceData(model) assert.Nil(t, err) - m, _, _, err = invSrv.Create(ctxh, po) + data.GrossAmount = 100 + data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) + collab := testingidentity.GenerateRandomDID().String() + newInv, err := invSrv.DeriveFromUpdatePayload(ctxh, &clientinvoicepb.InvoiceUpdatePayload{ + Identifier: hexutil.Encode(model.ID()), + Collaborators: []string{collab}, + Data: data, + }) assert.Nil(t, err) - newDM, err := m.PackCoreDocument() + newData, err := invSrv.DeriveInvoiceData(newInv) assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newDM.Document.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newDM.Document.CurrentVersion)) -} - -func TestService_DeriveInvoiceData(t *testing.T) { - _, invSrv := getServiceWithMockedLayers() - - // some random model - _, err := invSrv.DeriveInvoiceData(&mockModel{}) - assert.Error(t, err, "Derive must fail") - - // success - payload := testingdocuments.CreateInvoicePayload() - inv, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) - assert.Nil(t, err, "must be non nil") - data, err := invSrv.DeriveInvoiceData(inv) - assert.Nil(t, err, "Derive must succeed") - assert.NotNil(t, data, "data must be non nil") -} + assert.Equal(t, data, newData) -func TestService_DeriveInvoiceResponse(t *testing.T) { - // success - invSrv := service{repo: testRepo()} - payload := testingdocuments.CreateInvoicePayload() - inv1, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) - assert.Nil(t, err, "must be non nil") - inv, ok := inv1.(*Invoice) - assert.True(t, ok) + model, _, _, err = invSrv.Update(ctxh, newInv) + assert.Nil(t, err) + assert.NotNil(t, model) + assert.True(t, testRepo().Exists(accountID, model.ID())) + assert.True(t, testRepo().Exists(accountID, model.CurrentVersion())) + assert.True(t, testRepo().Exists(accountID, model.PreviousVersion())) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: []byte{}, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - inv.CoreDocumentModel = coreDocModel - resp, err := invSrv.DeriveInvoiceResponse(inv) - assert.Nil(t, err, "Derive must succeed") - assert.NotNil(t, resp, "data must be non nil") - assert.Equal(t, resp.Data, payload.Data, "data mismatch") + newData, err = invSrv.DeriveInvoiceData(model) + assert.Nil(t, err) + assert.Equal(t, data, newData) } func TestService_DeriveFromUpdatePayload(t *testing.T) { @@ -345,14 +140,8 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // failed to load from data - idC, _ := contextutil.Self(contextHeader) - old := new(Invoice) - err = old.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), idC.ID.String()) - assert.Nil(t, err) - old.CoreDocumentModel.Document.DocumentIdentifier = id - old.CoreDocumentModel.Document.CurrentVersion = id - old.CoreDocumentModel.Document.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(accountID, id, old) + old, _ := createCDWithEmbeddedInvoice(t) + err = testRepo().Create(accountID, old.CurrentVersion(), old) assert.Nil(t, err) payload.Data = &clientinvoicepb.InvoiceData{ Sender: "0xed03fa80291ff5ddc284de6b51e716b130b05e20", @@ -362,9 +151,10 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { ExtraData: "some data", Currency: "EUR", } + + payload.Identifier = hexutil.Encode(old.ID()) doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, doc) // failed core document new version @@ -377,100 +167,181 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { // success wantCollab := testingidentity.GenerateRandomDID() + payload.Collaborators = []string{wantCollab.String()} doc, err = invSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) - dm, err := doc.PackCoreDocument() - assert.Nil(t, err) - assert.Equal(t, wantCollab[:], dm.Document.Collaborators[2]) - assert.Len(t, dm.Document.Collaborators, 3) - oldDM, err := old.PackCoreDocument() - assert.Nil(t, err) - assert.Equal(t, oldDM.Document.DocumentIdentifier, dm.Document.DocumentIdentifier) - assert.Equal(t, payload.Identifier, hexutil.Encode(dm.Document.DocumentIdentifier)) - assert.Equal(t, oldDM.Document.CurrentVersion, dm.Document.PreviousVersion) - assert.Equal(t, oldDM.Document.NextVersion, dm.Document.CurrentVersion) - assert.NotNil(t, dm.Document.NextVersion) + cs, err := doc.GetCollaborators() + assert.Len(t, cs, 3) + assert.Contains(t, cs, wantCollab) + assert.Equal(t, old.ID(), doc.ID()) + assert.Equal(t, payload.Identifier, hexutil.Encode(doc.ID())) + assert.Equal(t, old.CurrentVersion(), doc.PreviousVersion()) + assert.Equal(t, old.NextVersion(), doc.CurrentVersion()) + assert.NotNil(t, doc.NextVersion()) assert.Equal(t, payload.Data, doc.(*Invoice).getClientData()) } -func TestService_Update(t *testing.T) { - _, srv := getServiceWithMockedLayers() - invSrv := srv.(service) +func TestService_DeriveFromCreatePayload(t *testing.T) { + invSrv := service{} ctxh := testingconfig.CreateAccountContext(t, cfg) - // pack failed - model := &mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, _, err := invSrv.Update(ctxh, model) - model.AssertExpectations(t) + // nil payload + m, err := invSrv.DeriveFromCreatePayload(ctxh, nil) + assert.Nil(t, m) assert.Error(t, err) - assert.Contains(t, err.Error(), "pack error") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) - // missing last version - model = &mockModel{} - dm := documents.NewCoreDocModel() - model.On("PackCoreDocument").Return(dm, nil).Once() - _, _, _, err = invSrv.Update(ctxh, model) - model.AssertExpectations(t) + // nil data payload + m, err = invSrv.DeriveFromCreatePayload(ctxh, &clientinvoicepb.InvoiceCreatePayload{}) + assert.Nil(t, m) assert.Error(t, err) - assert.Contains(t, err.Error(), "document not found") + assert.True(t, errors.IsOfType(documents.ErrDocumentNil, err)) - payload := testingdocuments.CreateInvoicePayload() - payload.Collaborators = []string{testingidentity.GenerateRandomDID().String()} - inv, err := invSrv.DeriveFromCreatePayload(ctxh, payload) - assert.Nil(t, err) - dm, err = inv.PackCoreDocument() + // Init fails + payload := &clientinvoicepb.InvoiceCreatePayload{ + Data: &clientinvoicepb.InvoiceData{ + ExtraData: "some data", + }, + } + + m, err = invSrv.DeriveFromCreatePayload(ctxh, payload) + assert.Nil(t, m) + assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) + + // success + payload.Data.ExtraData = "0x01020304050607" + m, err = invSrv.DeriveFromCreatePayload(ctxh, payload) assert.Nil(t, err) - dm.Document.DocumentRoot = utils.RandomSlice(32) - inv.(*Invoice).CoreDocumentModel = dm - testRepo().Create(accountID, dm.Document.CurrentVersion, inv) + assert.NotNil(t, m) + inv := m.(*Invoice) + assert.Equal(t, hexutil.Encode(inv.ExtraData), payload.Data.ExtraData) +} + +func TestService_DeriveFromCoreDocument(t *testing.T) { + invSrv := service{repo: testRepo()} + _, cd := createCDWithEmbeddedInvoice(t) + m, err := invSrv.DeriveFromCoreDocument(cd) + assert.Nil(t, err, "must return model") + assert.NotNil(t, m, "model must be non-nil") + inv, ok := m.(*Invoice) + assert.True(t, ok, "must be true") + assert.Equal(t, inv.Recipient.String(), "0xEA939D5C0494b072c51565b191eE59B5D34fbf79") + assert.Equal(t, inv.GrossAmount, int64(42)) +} + +func TestService_Create(t *testing.T) { + ctxh := testingconfig.CreateAccountContext(t, cfg) + _, srv := getServiceWithMockedLayers() + invSrv := srv.(service) // calculate data root fails - model = &mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - _, _, _, err = invSrv.Update(ctxh, model) - model.AssertExpectations(t) + m, _, _, err := invSrv.Create(ctxh, &mockModel{}) + assert.Nil(t, m) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") - // anchor fails + // success + inv, err := invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) + assert.Nil(t, err) + m, _, _, err = invSrv.Create(ctxh, inv) + assert.Nil(t, err) + assert.True(t, testRepo().Exists(accountID, m.ID())) + assert.True(t, testRepo().Exists(accountID, m.CurrentVersion())) +} + +func TestService_DeriveInvoiceData(t *testing.T) { + _, invSrv := getServiceWithMockedLayers() + + // some random model + _, err := invSrv.DeriveInvoiceData(&mockModel{}) + assert.Error(t, err, "Derive must fail") + + // success + payload := testingdocuments.CreateInvoicePayload() + inv, err := invSrv.DeriveFromCreatePayload(testingconfig.CreateAccountContext(t, cfg), payload) + assert.Nil(t, err, "must be non nil") data, err := invSrv.DeriveInvoiceData(inv) + assert.Nil(t, err, "Derive must succeed") + assert.NotNil(t, data, "data must be non nil") +} + +func TestService_DeriveInvoiceResponse(t *testing.T) { + // success + invSrv := service{repo: testRepo()} + + // derive data failed + m := new(mockModel) + r, err := invSrv.DeriveInvoiceResponse(m) + m.AssertExpectations(t) + assert.Nil(t, r) + assert.Error(t, err) + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalidType, err)) + + // success + inv, _ := createCDWithEmbeddedInvoice(t) + r, err = invSrv.DeriveInvoiceResponse(inv) + payload := testingdocuments.CreateInvoicePayload() assert.Nil(t, err) - data.GrossAmount = 100 - data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) - collab := testingidentity.GenerateRandomDID().String() - newInv, err := invSrv.DeriveFromUpdatePayload(ctxh, &clientinvoicepb.InvoiceUpdatePayload{ - Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), - Collaborators: []string{collab}, - Data: data, - }) + assert.Equal(t, payload.Data, r.Data) + assert.Contains(t, r.Header.Collaborators, cid.String()) +} + +func TestService_GetCurrentVersion(t *testing.T) { + _, invSrv := getServiceWithMockedLayers() + doc, _ := createCDWithEmbeddedInvoice(t) + ctxh := testingconfig.CreateAccountContext(t, cfg) + + err := testRepo().Create(accountID, doc.CurrentVersion(), doc) assert.Nil(t, err) - newData, err := invSrv.DeriveInvoiceData(newInv) + + data := doc.(*Invoice).getClientData() + data.Currency = "INR" + doc2 := new(Invoice) + assert.NoError(t, doc2.PrepareNewVersion(doc, data, nil)) + assert.NoError(t, testRepo().Create(accountID, doc2.CurrentVersion(), doc2)) + + doc3, err := invSrv.GetCurrentVersion(ctxh, doc.ID()) assert.Nil(t, err) - assert.Equal(t, data, newData) - inv, _, _, err = invSrv.Update(ctxh, newInv) + assert.Equal(t, doc2, doc3) +} + +func TestService_GetVersion(t *testing.T) { + _, invSrv := getServiceWithMockedLayers() + inv, _ := createCDWithEmbeddedInvoice(t) + err := testRepo().Create(accountID, inv.CurrentVersion(), inv) assert.Nil(t, err) - assert.NotNil(t, inv) - newDM, err := inv.PackCoreDocument() + + ctxh := testingconfig.CreateAccountContext(t, cfg) + mod, err := invSrv.GetVersion(ctxh, inv.ID(), inv.CurrentVersion()) assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newDM.Document.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newDM.Document.CurrentVersion)) - assert.True(t, testRepo().Exists(accountID, newDM.Document.PreviousVersion)) - newData, err = invSrv.DeriveInvoiceData(inv) + + mod, err = invSrv.GetVersion(ctxh, mod.ID(), []byte{}) + assert.Error(t, err) +} + +func TestService_Exists(t *testing.T) { + _, invSrv := getServiceWithMockedLayers() + inv, _ := createCDWithEmbeddedInvoice(t) + err := testRepo().Create(accountID, inv.CurrentVersion(), inv) assert.Nil(t, err) - assert.Equal(t, data, newData) + ctxh := testingconfig.CreateAccountContext(t, cfg) + exists := invSrv.Exists(ctxh, inv.CurrentVersion()) + assert.True(t, exists, "invoice should exist") + + exists = invSrv.Exists(ctxh, utils.RandomSlice(32)) + assert.False(t, exists, " invoice should not exist") } func TestService_calculateDataRoot(t *testing.T) { - _, srv := getServiceWithMockedLayers() - invSrv := srv.(service) + invSrv := service{repo: testRepo()} ctxh := testingconfig.CreateAccountContext(t, cfg) // type mismatch - inv, err := invSrv.validateAndPersist(ctxh, nil, &testingdocuments.MockModel{}, nil) + inv, err := invSrv.validateAndPersist(ctxh, nil, &mockModel{}, nil) assert.Nil(t, inv) assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") @@ -478,7 +349,6 @@ func TestService_calculateDataRoot(t *testing.T) { // failed validator inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) v := documents.ValidatorFunc(func(_, _ documents.Model) error { return errors.New("validations fail") }) @@ -490,18 +360,16 @@ func TestService_calculateDataRoot(t *testing.T) { // create failed inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) - err = invSrv.repo.Create(accountID, inv.(*Invoice).CoreDocumentModel.Document.CurrentVersion, inv) + err = invSrv.repo.Create(accountID, inv.CurrentVersion(), inv) assert.Nil(t, err) inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, inv) assert.Error(t, err) - assert.Contains(t, err.Error(), "db repository could not create the given model, key already exists") + assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists) // success inv, err = invSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreateInvoicePayload()) assert.Nil(t, err) - assert.Nil(t, inv.(*Invoice).CoreDocumentModel.Document.DataRoot) inv, err = invSrv.validateAndPersist(ctxh, nil, inv, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, inv) @@ -520,3 +388,18 @@ func testRepo() documents.Repository { } return testRepoGlobal } + +func createCDWithEmbeddedInvoice(t *testing.T) (documents.Model, coredocumentpb.CoreDocument) { + i := new(Invoice) + err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), cid.String()) + assert.NoError(t, err) + _, err = i.CalculateDataRoot() + assert.NoError(t, err) + _, err = i.CalculateSigningRoot() + assert.NoError(t, err) + _, err = i.CalculateDocumentRoot() + assert.NoError(t, err) + cd, err := i.PackCoreDocument() + assert.NoError(t, err) + return i, cd +} diff --git a/documents/invoice/utils_test.go b/documents/invoice/utils_test.go deleted file mode 100644 index eeb3709eb..000000000 --- a/documents/invoice/utils_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build unit - -package invoice - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/documents" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/stretchr/testify/assert" -) - -func CreateCDWithEmbeddedInvoice(t *testing.T, invoiceData invoicepb.InvoiceData) *documents.CoreDocumentModel { - identifier := []byte("1") - invoiceModel := &Invoice{} - invoiceModel.CoreDocumentModel = documents.NewCoreDocModel() - invoiceModel.loadFromP2PProtobuf(&invoiceData) - _, err := invoiceModel.getInvoiceSalts(&invoiceData) - assert.NoError(t, err) - cdm, err := invoiceModel.PackCoreDocument() - assert.NoError(t, err) - cdm.Document.DocumentIdentifier = identifier - - return cdm -} diff --git a/documents/model.go b/documents/model.go index e0be73bc4..a1137b26c 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,1122 +1,92 @@ package documents import ( - "bytes" - "context" - "crypto/sha256" - "encoding/binary" - "fmt" - "strings" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/golang/protobuf/ptypes/any" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/storage" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/proto" -) - -const ( - // CDRootField represents the coredocument root property of a tree - CDRootField = "cd_root" - // DataRootField represents the data root property of a tree - DataRootField = "data_root" - // DocumentTypeField represents the doc type property of a tree - DocumentTypeField = "document_type" - // SignaturesField represents the signatures property of a tree - SignaturesField = "signatures" - // SigningRootField represents the signature root property of a tree - SigningRootField = "signing_root" - - // ErrZeroCollaborators error when no collaborators are passed - ErrZeroCollaborators = errors.Error("require at least one collaborator") - // nftByteCount is the length of combined bytes of registry and tokenID - nftByteCount = 52 - // ErrNFTRoleMissing errors when role to generate proof doesn't exist - ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") - //IDByteCount represents the byte length of valid identifiers - IDByteCount = 32 - - // ACLReadSign represents the read/sign action for ACLS - ACLReadSign = coredocumentpb.Action_ACTION_READ_SIGN - // ACLRead represents the read action for ACLS - ACLRead = coredocumentpb.Action_ACTION_READ - - // CDTreePrefix is the human readable prefix for core doc tree props - CDTreePrefix = "cd_tree" - // SigningTreePrefix is the human readable prefix for signing tree props - SigningTreePrefix = "signing_tree" ) -func compactProperties(key string) []byte { - m := map[string][]byte{ - CDRootField: {0, 0, 0, 7}, - DataRootField: {0, 0, 0, 5}, - DocumentTypeField: {0, 0, 0, 100}, - SignaturesField: {0, 0, 0, 6}, - SigningRootField: {0, 0, 0, 10}, - - // tree prefixes use the first byte of a 4 byte slice by convention - CDTreePrefix: {1, 0, 0, 0}, - SigningTreePrefix: {2, 0, 0, 0}, - } - return m[key] -} - // Model is an interface to abstract away model specificness like invoice or purchaseOrder // The interface can cast into the type specified by the model if required // It should only handle protocol-level Document actions type Model interface { storage.Model - // Get the ID of the document represented by this model - ID() ([]byte, error) - - // PackCoreDocument packs the implementing document into a core document - // should create the identifiers for the core document if not present - PackCoreDocument() (*CoreDocumentModel, error) - - // UnpackCoreDocument must return the document.Model - // assumes that core document has valid identifiers set - UnpackCoreDocument(model *CoreDocumentModel) error - - // CalculateDataRoot calculates the dataroot of precise-proofs tree of the model - CalculateDataRoot() ([]byte, error) - - // CreateProofs creates precise-proofs for given fields - CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) -} - -// TokenRegistry defines NFT retrieval functions. -type TokenRegistry interface { - // OwnerOf to retrieve owner of the tokenID - OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) -} - -// CoreDocumentModel contains methods which handle all interactions mutating or reading from a core document -// Access to a core document should always go through this model -type CoreDocumentModel struct { - Document *coredocumentpb.CoreDocument - TokenRegistry -} - -// NewDefaultTree returns a DocumentTree with default opts -func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { - return NewDefaultTreeWithPrefix(salts, "", nil) -} - -// NewDefaultTreeWithPrefix returns a DocumentTree with default opts passing a prefix to the tree leaves -func NewDefaultTreeWithPrefix(salts *proofs.Salts, prefix string, compactPrefix []byte) *proofs.DocumentTree { - var prop proofs.Property - if prefix != "" { - prop = NewLeafProperty(prefix, compactPrefix) - } - - t := proofs.NewDocumentTree(proofs.TreeOptions{CompactProperties: true, EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) - return &t -} - -// NewLeafProperty returns a proof property with the literal and the compact -func NewLeafProperty(literal string, compact []byte) proofs.Property { - return proofs.NewProperty(literal, compact...) -} - -// NewCoreDocModel returns a new CoreDocumentModel -// Note: collaborators and salts are to be filled by the caller -// TODO: double check if registry should be initialised as nil -func NewCoreDocModel() *CoreDocumentModel { - id := utils.RandomSlice(32) - cd := &coredocumentpb.CoreDocument{ - DocumentIdentifier: id, - CurrentVersion: id, - NextVersion: utils.RandomSlice(32), - } - return &CoreDocumentModel{ - cd, - nil, - } -} - -// PrepareNewVersion creates a new CoreDocumentModel with the version fields updated -// Adds collaborators and fills salts -// Note: new collaborators are added to the list with old collaborators. -//TODO: this will change when collaborators are moved down to next level -func (m *CoreDocumentModel) PrepareNewVersion(collaborators []string) (*CoreDocumentModel, error) { - ndm, err := m.prepareNewVersion(collaborators) - if err != nil { - return nil, err - } - - return ndm, ndm.setCoreDocumentSalts() -} - -// prepareNewVersion prepares the next version of the CoreDocument -// Note: salts needs to be filled by the caller -func (m *CoreDocumentModel) prepareNewVersion(collaborators []string) (*CoreDocumentModel, error) { - ndm := NewCoreDocModel() - ncd := ndm.Document - ocd := m.Document - ucs, err := fetchUniqueCollaborators(ocd.Collaborators, collaborators) - if err != nil { - return nil, errors.New("failed to decode collaborator: %v", err) - } - - cs := ocd.Collaborators - for _, c := range ucs { - c := c - cs = append(cs, c[:]) - } - - ncd.Collaborators = cs - ncd.Roles = m.Document.Roles - ncd.ReadRules = m.Document.ReadRules - err = ndm.addCollaboratorsToReadSignRules(ucs) - if err != nil { - return nil, err - } - if ocd.DocumentIdentifier == nil { - return nil, errors.New("Document.DocumentIdentifier is nil") - } - ncd.DocumentIdentifier = ocd.DocumentIdentifier + // ID returns the Document identifier + ID() []byte - if ocd.CurrentVersion == nil { - return nil, errors.New("Document.CurrentVersion is nil") - } - ncd.PreviousVersion = ocd.CurrentVersion + // CurrentVersion returns the current version identifier of the Document + CurrentVersion() []byte - if ocd.NextVersion == nil { - return nil, errors.New("Document.NextVersion is nil") - } + // PreviousVersion returns the previous version identifier of the Document + PreviousVersion() []byte - ncd.CurrentVersion = ocd.NextVersion - ncd.NextVersion = utils.RandomSlice(32) - if ocd.DocumentRoot == nil { - return nil, errors.New("DocumentRoot is nil") - } - ncd.PreviousRoot = ocd.DocumentRoot - // copy over token registry - ndm.TokenRegistry = m.TokenRegistry + // NextVersion returns the next version identifier of the Document. + NextVersion() []byte - // copy over embedded data - ncd.EmbeddedData = ocd.EmbeddedData - ncd.EmbeddedDataSalts = ocd.EmbeddedDataSalts - - return ndm, nil -} - -// NewWithCollaborators generates new core document, adds collaborators, adds read rules and fills salts -func NewWithCollaborators(collaborators []string) (*CoreDocumentModel, error) { - m := NewCoreDocModel() - ids, err := identity.NewDIDsFromStrings(collaborators) - if err != nil { - return nil, errors.New("failed to decode collaborator: %v", err) - } - - for i := range ids { - m.Document.Collaborators = append(m.Document.Collaborators, ids[i][:]) - } - err = m.initReadRules(ids) - if err != nil { - return nil, errors.New("failed to init read rules: %v", err) - } - - if err := m.setCoreDocumentSalts(); err != nil { - return nil, err - } - - return m, nil -} - -// CreateProofs util function that takes document data tree, coreDocument and a list fo fields and generates proofs -func (m *CoreDocumentModel) CreateProofs(dataTree *proofs.DocumentTree, fields []string) (proofs []*proofspb.Proof, err error) { - signingRootProofHashes, err := m.getSigningRootProofHashes() - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - - cdtree, err := m.GetCoreDocumentTree() - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - - dataRoot := dataTree.RootHash() - cdRoot := cdtree.RootHash() - - // We support fields that belong to different document trees, as we do not prepend a tree prefix to the field, the approach - // is to try in both trees to find the field and create the proof accordingly - for _, field := range fields { - proof, err := dataTree.CreateProof(field) - if err != nil { - if strings.Contains(err.Error(), "No such field") { - proof, err = cdtree.CreateProof(field) - if err != nil { - return nil, errors.New("createProofs error %v", err) - } - proof.SortedHashes = append(proof.SortedHashes, dataRoot) - } else { - return nil, errors.New("createProofs error %v", err) - } - } else { - proof.SortedHashes = append(proof.SortedHashes, cdRoot) - } - proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) - proofs = append(proofs, &proof) - } - - return proofs, nil -} + // PackCoreDocument packs the implementing Document into a core Document + // Should only be called when the Document is about to be put on wire. + PackCoreDocument() (coredocumentpb.CoreDocument, error) -// GetCoreDocumentTree returns the merkle tree for the coredoc root -func (m *CoreDocumentModel) GetCoreDocumentTree() (tree *proofs.DocumentTree, err error) { - document := m.Document - tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(m.Document.CoredocumentSalts), CDTreePrefix, compactProperties(CDTreePrefix)) - err = tree.AddLeavesFromDocument(document) - if err != nil { - return nil, err - } + // UnpackCoreDocument takes a core Document protobuf and loads the data into the model. + UnpackCoreDocument(cd coredocumentpb.CoreDocument) error - if document.EmbeddedData == nil { - return nil, errors.New("EmbeddedData cannot be nil when generating signing tree") - } - prefixProp := NewLeafProperty(CDTreePrefix, compactProperties(CDTreePrefix)) - // Adding document type as it is an excluded field in the tree - documentTypeNode := proofs.LeafNode{ - Property: prefixProp.FieldProp(DocumentTypeField, binary.LittleEndian.Uint32(compactProperties(DocumentTypeField))), - Salt: make([]byte, 32), - Value: []byte(document.EmbeddedData.TypeUrl), - } + // DocumentType returns the type of the Document + DocumentType() string - err = documentTypeNode.HashNode(sha256.New(), true) - if err != nil { - return nil, err - } - - err = tree.AddLeaf(documentTypeNode) - if err != nil { - return nil, err - } - - err = tree.Generate() - if err != nil { - return nil, err - } - - return tree, nil -} - -// GetDocumentSigningTree returns the merkle tree for the signing root -func (m *CoreDocumentModel) GetDocumentSigningTree(dataRoot []byte) (tree *proofs.DocumentTree, err error) { - // coredoc tree - coreDocTree, err := m.GetCoreDocumentTree() - if err != nil { - return nil, err - } - - // create the signing tree with data root and coredoc root as siblings - tree = NewDefaultTreeWithPrefix(ConvertToProofSalts(m.Document.CoredocumentSalts), SigningTreePrefix, compactProperties(SigningTreePrefix)) - prefixProp := NewLeafProperty(SigningTreePrefix, compactProperties(SigningTreePrefix)) - - err = tree.AddLeaves([]proofs.LeafNode{ - { - Property: prefixProp.FieldProp(DataRootField, binary.LittleEndian.Uint32(compactProperties(DataRootField))), - Hash: dataRoot, - Hashed: true, - }, - { - Property: prefixProp.FieldProp(CDRootField, binary.LittleEndian.Uint32(compactProperties(CDRootField))), - Hash: coreDocTree.RootHash(), - Hashed: true, - }, - }) - - if err != nil { - return nil, err - } - - err = tree.Generate() - if err != nil { - return nil, err - } - - return tree, nil -} - -// GetDocumentRootTree returns the merkle tree for the document root -func (m *CoreDocumentModel) GetDocumentRootTree() (tree *proofs.DocumentTree, err error) { - document := m.Document - tree = NewDefaultTree(ConvertToProofSalts(document.CoredocumentSalts)) - - // The first leave added is the signing_root - err = tree.AddLeaf(proofs.LeafNode{Hash: document.SigningRoot, Hashed: true, Property: NewLeafProperty(SigningRootField, compactProperties(SigningRootField))}) - if err != nil { - return nil, err - } - - // For every signature we create a LeafNode - sigProperty := NewLeafProperty(SignaturesField, compactProperties(SignaturesField)) - sigLeafList := make([]proofs.LeafNode, len(document.Signatures)+1) - sigLengthNode := proofs.LeafNode{ - Property: sigProperty.LengthProp(proofs.DefaultSaltsLengthSuffix), - Salt: make([]byte, 32), - Value: []byte(fmt.Sprintf("%d", len(document.Signatures))), - } - - h := sha256.New() - err = sigLengthNode.HashNode(h, true) - if err != nil { - return nil, err - } - sigLeafList[0] = sigLengthNode - for i, sig := range document.Signatures { - payload := sha256.Sum256(append(sig.EntityId, append(sig.PublicKey, sig.Signature...)...)) - leaf := proofs.LeafNode{ - Hash: payload[:], - Hashed: true, - Property: sigProperty.SliceElemProp(proofs.FieldNumForSliceLength(i)), - } - err = leaf.HashNode(h, true) - if err != nil { - return nil, err - } - sigLeafList[i+1] = leaf - } - err = tree.AddLeaves(sigLeafList) - if err != nil { - return nil, err - } - - err = tree.Generate() - if err != nil { - return nil, err - } - - return tree, nil -} - -// CalculateDocumentRoot calculates the document root of the core document -func (m *CoreDocumentModel) CalculateDocumentRoot() error { - document := m.Document - if len(document.SigningRoot) != 32 { - return errors.New("signing root invalid") - } - - tree, err := m.GetDocumentRootTree() - if err != nil { - return err - } - - document.DocumentRoot = tree.RootHash() - return nil -} - -// getDataProofHashes returns the hashes needed to create a proof from DataRoot to SigningRoot. This method is used -// to create field proofs -func (m *CoreDocumentModel) getDataProofHashes(dataRoot []byte) (hashes [][]byte, err error) { - tree, err := m.GetDocumentSigningTree(dataRoot) - if err != nil { - return - } - - signingProof, err := tree.CreateProof(SigningTreePrefix + ".data_root") - if err != nil { - return - } - - rootProofHashes, err := m.getSigningRootProofHashes() - if err != nil { - return - } - - return append(signingProof.SortedHashes, rootProofHashes...), err -} - -// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. This method is used -// to create field proofs -func (m *CoreDocumentModel) getSigningRootProofHashes() (hashes [][]byte, err error) { - tree, err := m.GetDocumentRootTree() - if err != nil { - return - } - rootProof, err := tree.CreateProof("signing_root") - if err != nil { - return - } - - return rootProof.SortedHashes, err -} - -// CalculateSigningRoot calculates the signing root of the core document -func (m *CoreDocumentModel) CalculateSigningRoot(dataRoot []byte) error { - doc := m.Document - tree, err := m.GetDocumentSigningTree(dataRoot) - if err != nil { - return err - } - - doc.SigningRoot = tree.RootHash() - return nil -} - -// AccountCanRead validate if the core document can be read by the account . -// Returns an error if not. -func (m *CoreDocumentModel) AccountCanRead(account identity.DID) bool { - // loop though read rules, check all the rules - return m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { - _, found := isAccountInRole(role, account) - return found - }, ACLRead, ACLReadSign) -} - -// GenerateCoreDocSalts generates coredoc salts -func GenerateCoreDocSalts(document proto.Message) (*proofs.Salts, error) { - return GenerateNewSalts(document, CDTreePrefix, compactProperties(CDTreePrefix)) -} - -// GenerateNewSalts generates salts for new document -func GenerateNewSalts(document proto.Message, prefix string, compactPrefix []byte) (*proofs.Salts, error) { - docSalts := &proofs.Salts{} - t := NewDefaultTreeWithPrefix(docSalts, prefix, compactPrefix) - err := t.AddLeavesFromDocument(document) - if err != nil { - return nil, err - } - return docSalts, nil -} - -// ConvertToProtoSalts converts proofSalts into protocolSalts -func ConvertToProtoSalts(proofSalts *proofs.Salts) []*coredocumentpb.DocumentSalt { - if proofSalts == nil { - return nil - } - - protoSalts := make([]*coredocumentpb.DocumentSalt, len(*proofSalts)) - for i, pSalt := range *proofSalts { - protoSalts[i] = &coredocumentpb.DocumentSalt{Value: pSalt.Value, Compact: pSalt.Compact} - } - - return protoSalts -} - -// ConvertToProofSalts converts protocolSalts into proofSalts -func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salts { - if protoSalts == nil { - return nil - } - - proofSalts := make(proofs.Salts, len(protoSalts)) - for i, pSalt := range protoSalts { - proofSalts[i] = proofs.Salt{Value: pSalt.Value, Compact: pSalt.Compact} - } - - return &proofSalts -} - -// setCoreDocumentSalts creates a new coredocument.Salts and fills it in case that is not initialized yet -func (m *CoreDocumentModel) setCoreDocumentSalts() error { - if m.Document.CoredocumentSalts == nil { - pSalts, err := GenerateCoreDocSalts(m.Document) - if err != nil { - return err - } - - m.Document.CoredocumentSalts = ConvertToProtoSalts(pSalts) - } - - return nil -} - -// PackCoreDocument sets the embed data and embed salts and generates core doc salts if not exists -func (m *CoreDocumentModel) PackCoreDocument(embedData *any.Any, embedSalts []*coredocumentpb.DocumentSalt) error { - m.Document.EmbeddedData = embedData - m.Document.EmbeddedDataSalts = embedSalts - return m.setCoreDocumentSalts() -} - -// UnpackCoreDocument sets the embed data and embed salts and generates core doc salts if not exists -func (m *CoreDocumentModel) UnpackCoreDocument() error { - m.Document.EmbeddedData = nil - m.Document.EmbeddedDataSalts = nil - return m.setCoreDocumentSalts() -} - -// initReadRules initiates the read rules for a given CoreDocumentModel. -// Collaborators are given Read_Sign action. -// if the rules are created already, this is a no-op. -func (m *CoreDocumentModel) initReadRules(collabs []identity.DID) error { - cd := m.Document - if len(cd.Roles) > 0 && len(cd.ReadRules) > 0 { - return nil - } - - if len(collabs) < 1 { - return ErrZeroCollaborators - } - - return m.addCollaboratorsToReadSignRules(collabs) -} - -// addNewRule creates a new rule as per the role and action. -func (m *CoreDocumentModel) addNewRule(role *coredocumentpb.Role, action coredocumentpb.Action) { - cd := m.Document - cd.Roles = append(cd.Roles, role) - - rule := new(coredocumentpb.ReadRule) - rule.Roles = append(rule.Roles, role.RoleKey) - rule.Action = action - cd.ReadRules = append(cd.ReadRules, rule) -} - -// findRole calls OnRole for every role that matches the actions passed in -func (m *CoreDocumentModel) findRole(onRole func(rridx, ridx int, role *coredocumentpb.Role) bool, actions ...coredocumentpb.Action) bool { - cd := m.Document - am := make(map[int32]struct{}) - for _, a := range actions { - am[int32(a)] = struct{}{} - } - - for i, rule := range cd.ReadRules { - if _, ok := am[int32(rule.Action)]; !ok { - continue - } - - for j, rk := range rule.Roles { - role, err := getRole(rk, cd.Roles) - if err != nil { - // seems like roles and rules are not in sync - // skip to next one - continue - } - - if onRole(i, j, role) { - return true - } - - } - } - - return false -} - -// isAccountInRole returns the index of the collaborator and true if account is in the given role as collaborators. -func isAccountInRole(role *coredocumentpb.Role, account identity.DID) (idx int, found bool) { - for i, id := range role.Collaborators { - if bytes.Equal(id, account[:]) { - return i, true - } - } - - return idx, false -} - -func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { - for _, role := range roles { - if utils.IsSameByteSlice(role.RoleKey, key) { - return role, nil - } - } - - return nil, errors.New("role %d not found", key) -} - -func newRole() *coredocumentpb.Role { - role := new(coredocumentpb.Role) - rk := utils.RandomSlice(32) - role.RoleKey = rk[:] - return role -} - -func (m *CoreDocumentModel) addCollaboratorsToReadSignRules(collabs []identity.DID) error { - if len(collabs) == 0 { - return nil - } - // create a role for given collaborators - role := newRole() - for _, c := range collabs { - c := c - role.Collaborators = append(role.Collaborators, c[:]) - } - - m.addNewRule(role, ACLReadSign) - - return nil -} - -func fetchUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.DID, err error) { - ocsm := make(map[string]struct{}) - for _, c := range oldCollabs { - cs := strings.ToLower(hexutil.Encode(c)) - ocsm[cs] = struct{}{} - } - - var uc []string - for _, c := range newCollabs { - cs := strings.ToLower(c) - if _, ok := ocsm[cs]; ok { - continue - } - - uc = append(uc, c) - } - - for _, c := range uc { - id, err := identity.NewDIDFromString(c) - if err != nil { - return nil, err - } - - ids = append(ids, id) - } - - return ids, nil -} - -// GetExternalCollaborators returns collaborators of a document without the own centID. -func (m *CoreDocumentModel) GetExternalCollaborators(selfCentID identity.DID) ([][]byte, error) { - var collabs [][]byte - - for _, collab := range m.Document.Collaborators { - collabID := identity.NewDIDFromBytes(collab) - if !selfCentID.Equal(collabID) { - collabs = append(collabs, collab) - } - } - - return collabs, nil -} - -// NFTOwnerCanRead checks if the nft owner/account can read the document -func (m *CoreDocumentModel) NFTOwnerCanRead(registry common.Address, tokenID []byte, account identity.DID) error { - // check if the account can read the doc - if m.AccountCanRead(account) { - return nil - } - - // check if the nft is present in read rules - found := m.findRole(func(_, _ int, role *coredocumentpb.Role) bool { - _, found := isNFTInRole(role, registry, tokenID) - return found - }, coredocumentpb.Action_ACTION_READ) - - if !found { - return errors.New("nft missing") - } - - // get the owner of the NFT - owner, err := m.TokenRegistry.OwnerOf(registry, tokenID) - if err != nil { - return errors.New("failed to get NFT owner: %v", err) - } - - // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address - if !bytes.Equal(owner.Bytes(), account[:]) { - return errors.New("account (%v) not owner of the NFT", account.String()) - } - - return nil -} - -// ConstructNFT appends registry and tokenID to byte slice -func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { - var nft []byte - // first 20 bytes of registry - nft = append(nft, registry.Bytes()...) - - // next 32 bytes of the tokenID - nft = append(nft, tokenID...) - - if len(nft) != nftByteCount { - return nil, errors.New("byte length mismatch") - } - - return nft, nil -} - -// AddNFTToReadRules adds NFT token to the read rules of core document. -func (m *CoreDocumentModel) AddNFTToReadRules(registry common.Address, tokenID []byte) error { - nft, err := ConstructNFT(registry, tokenID) - if err != nil { - return errors.New("failed to construct NFT: %v", err) - } - - role := newRole() - role.Nfts = append(role.Nfts, nft) - m.addNewRule(role, coredocumentpb.Action_ACTION_READ) - if err := m.setCoreDocumentSalts(); err != nil { - return errors.New("failed to generate CoreDocumentSalts") - } - return nil -} - -//ValidateDocumentAccess validates the GetDocument request against the AccessType indicated in the request -func (m *CoreDocumentModel) ValidateDocumentAccess(docReq *p2ppb.GetDocumentRequest, peer identity.DID) error { - // checks which access type is relevant for the request - switch docReq.GetAccessType() { - case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: - if !m.AccountCanRead(peer) { - return errors.New("requester does not have access") - } - case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: - registry := common.BytesToAddress(docReq.NftRegistryAddress) - if m.NFTOwnerCanRead(registry, docReq.NftTokenId, peer) != nil { - return errors.New("requester does not have access") - } - case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: - reqID := peer[:] - err := m.accessTokenOwnerCanRead(docReq, reqID) - if err != nil { - return err - } - default: - return errors.New("invalid access type ") - } - return nil -} - -// isNFTInRole checks if the given nft(registry + token) is part of the core document role. -// If found, returns the index of the nft in the role and true -func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) (nftIdx int, found bool) { - enft, err := ConstructNFT(registry, tokenID) - if err != nil { - return nftIdx, false - } - - for i, n := range role.Nfts { - if bytes.Equal(n, enft) { - return i, true - } - } - - return nftIdx, false -} - -// AddNFT returns a new CoreDocument model with nft added to the Core document. If grantReadAccess is true, the nft is added -// to the read rules. -func (m *CoreDocumentModel) AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) (*CoreDocumentModel, error) { - data := m.Document.EmbeddedData - ndm, err := m.prepareNewVersion(nil) - if err != nil { - return nil, err - } - - ndm.Document.EmbeddedData = data - cd := ndm.Document - nft := getStoredNFT(cd.Nfts, registry.Bytes()) - if nft == nil { - nft = new(coredocumentpb.NFT) - // add 12 empty bytes - eb := make([]byte, 12, 12) - nft.RegistryId = append(registry.Bytes(), eb...) - cd.Nfts = append(cd.Nfts, nft) - } - nft.TokenId = tokenID - - if grantReadAccess { - err = ndm.AddNFTToReadRules(registry, tokenID) - if err != nil { - return nil, err - } - } - - return ndm, ndm.setCoreDocumentSalts() -} - -// IsNFTMinted checks if the there is an NFT that is minted against this document in the given registry. -func (m *CoreDocumentModel) IsNFTMinted(tokenRegistry TokenRegistry, registry common.Address) bool { - nft := getStoredNFT(m.Document.Nfts, registry.Bytes()) - if nft == nil { - return false - } - - _, err := tokenRegistry.OwnerOf(registry, nft.TokenId) - return err == nil -} - -func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.NFT { - for _, nft := range nfts { - if bytes.Equal(nft.RegistryId[:20], registry) { - return nft - } - } - - return nil -} - -// IsAccountInRole checks if the the account exists in the role provided -func (m *CoreDocumentModel) IsAccountInRole(roleKey []byte, account identity.DID) bool { - role, err := getRole(roleKey, m.Document.Roles) - if err != nil { - return false - } - _, found := isAccountInRole(role, account) - return found -} - -// assembleTokenMessage assembles a token message -func assembleTokenMessage(tokenIdentifier []byte, granterID identity.DID, granteeID identity.DID, roleID []byte, docID []byte) ([]byte, error) { - tokenIdentifiers := [][]byte{tokenIdentifier, roleID, docID} - for _, id := range tokenIdentifiers { - if len(id) != IDByteCount { - return nil, errors.New("invalid identifier length") - } - } - - tm := append(tokenIdentifier, granterID[:]...) - tm = append(tm, granteeID[:]...) - tm = append(tm, roleID...) - tm = append(tm, docID...) - return tm, nil -} - -// assembleAccessToken assembles a Read Access Token from the payload received -func (m *CoreDocumentModel) assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenParams, roleKey []byte) (*coredocumentpb.AccessToken, error) { - account, err := contextutil.Account(ctx) - if err != nil { - return nil, err - } - tokenIdentifier := utils.RandomSlice(32) - id, err := account.GetIdentityID() - if err != nil { - return nil, err - } - granterID := identity.NewDIDFromByte(id) - roleID := roleKey - granteeID, err := identity.NewDIDFromString(payload.Grantee) - if err != nil { - return nil, err - } - // assemble access token message to be signed - docID, err := hexutil.Decode(payload.DocumentIdentifier) - if err != nil { - return nil, err - } - - tm, err := assembleTokenMessage(tokenIdentifier, granterID, granteeID, roleID[:], docID) - if err != nil { - return nil, err - } - - // fetch key pair from identity - // TODO: change to signing key pair once secp scheme is available - sig, err := account.SignMsg(tm) - if err != nil { - return nil, err - } - keys, err := account.GetKeys() - if err != nil { - return nil, err - } - // assemble the access token, appending the signature and public keys - at := &coredocumentpb.AccessToken{ - Identifier: tokenIdentifier, - Granter: granterID[:], - Grantee: granteeID[:], - RoleIdentifier: roleID[:], - DocumentIdentifier: docID, - Signature: sig.Signature, - Key: keys[identity.KeyPurposeSigning].PublicKey, - } - return at, nil - -} - -// AddAccessTokenToReadRules adds the AccessToken(s) to the read rules of the document -func (m *CoreDocumentModel) AddAccessTokenToReadRules(ctx context.Context, payload documentpb.AccessTokenParams) (*CoreDocumentModel, error) { - role := newRole() - at, err := m.assembleAccessToken(ctx, payload, role.RoleKey) - if err != nil { - return nil, errors.New("failed to construct AT: %v", err) - } - role.AccessTokens = append(role.AccessTokens, at) - m.addNewRule(role, ACLRead) - cdSalts, _ := GenerateNewSalts(m.Document, "", nil) - m.Document.CoredocumentSalts = ConvertToProtoSalts(cdSalts) - return m, nil -} - -// ATOwnerCanRead checks that the owner AT can read the document requested -func (m *CoreDocumentModel) accessTokenOwnerCanRead(docReq *p2ppb.GetDocumentRequest, requesterID []byte) error { - // check if the access token is present in read rules of the document indicated in the AT request - token, err := m.findAT(ACLRead, docReq.AccessTokenRequest.AccessTokenId) - if err != nil { - return err - } - // check if the requested document is the document indicated in the access token - if !bytes.Equal(token.DocumentIdentifier, docReq.DocumentIdentifier) { - return errors.New("the document requested does not match the document to which the access token grants access") - } - // validate the access token - // TODO: fetch public key from Ethereum chain - err = validateAT(token.Key, token, requesterID) - if err != nil { - return err - } - return nil - -} - -// validateAT validates that given access token against its signature -func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID []byte) error { - // assemble token message from the token for validation - reqID := identity.NewDIDFromByte(requesterID) - granterID := identity.NewDIDFromByte(token.Granter) - tm, err := assembleTokenMessage(token.Identifier, granterID, reqID, token.RoleIdentifier, token.DocumentIdentifier) - if err != nil { - return err - } - validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1, true) - if !validated { - return errors.New("access token is invalid") - } - return nil -} - -// isATInRole checks if the given access token is part of the core document role. -func isATInRole(role *coredocumentpb.Role, tokenID []byte) (*coredocumentpb.AccessToken, error) { - for _, a := range role.AccessTokens { - if bytes.Equal(tokenID, a.Identifier) { - return a, nil - } - } - return nil, errors.New("access token not found") -} - -// findAT calls OnRole for every role, returns the access token if it is found in the Roles of the document -func (m *CoreDocumentModel) findAT(action coredocumentpb.Action, tokenID []byte) (*coredocumentpb.AccessToken, error) { - cd := m.Document - var token coredocumentpb.AccessToken - for _, rule := range cd.ReadRules { - if rule.Action != action { - continue - } - ruleRoles := rule.GetRoles() - for _, rk := range ruleRoles { - role, err := getRole(rk, cd.Roles) - if err != nil { - // seems like roles and rules are not in sync - // skip to next one - continue - } - at, err := isATInRole(role, tokenID) - if err != nil { - return nil, err - } - token = *at - } - } - return &token, nil -} - -// GetNFTProofs generate proofs required to mint an NFT -func (m *CoreDocumentModel) GetNFTProofs( - dataRoot []byte, - account identity.DID, - registry common.Address, - tokenID []byte, - nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { + // CalculateDataRoot calculates the data root of the model. + CalculateDataRoot() ([]byte, error) - var pfKeys []string - if nftUniqueProof { - pk, err := getNFTUniqueProofKey(m.Document.Nfts, registry) - if err != nil { - return nil, err - } + // CalculateSigningRoot calculates the signing root of the model. + CalculateSigningRoot() ([]byte, error) - pfKeys = append(pfKeys, pk) - } + // CalculateDocumentRoot returns the Document root of the model. + CalculateDocumentRoot() ([]byte, error) - if readAccessProof { - pks, err := getReadAccessProofKeys(m, registry, tokenID) - if err != nil { - return nil, err - } + // PreviousDocumentRoot returns the Document root of the previous version. + PreviousDocumentRoot() []byte - pfKeys = append(pfKeys, pks...) - } + // AppendSignatures appends the signatures to the model. + AppendSignatures(signatures ...*coredocumentpb.Signature) - signingRootProofHashes, err := m.getSigningRootProofHashes() - if err != nil { - return nil, errors.New("failed to generate signing root proofs: %v", err) - } + // Signatures returns a copy of the signatures on the Document + Signatures() []coredocumentpb.Signature - cdtree, err := m.GetCoreDocumentTree() - if err != nil { - return nil, errors.New("failed to generate document tree: %v", err) - } + // CreateProofs creates precise-proofs for given fields + CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) - for _, field := range pfKeys { - proof, err := cdtree.CreateProof(field) - if err != nil { - return nil, errors.New("failed to create proof: %v", err) - } + // CreateNFTProofs creates NFT proofs for minting. + CreateNFTProofs( + account identity.DID, + registry common.Address, + tokenID []byte, + nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) - proof.SortedHashes = append(proof.SortedHashes, dataRoot) - proof.SortedHashes = append(proof.SortedHashes, signingRootProofHashes...) - proofs = append(proofs, &proof) - } + // IsNFTMinted checks if there is any NFT minted for the registry given + IsNFTMinted(tr TokenRegistry, registry common.Address) bool - return proofs, nil -} + // AddNFT adds an NFT to the Document. + // Note: The Document should be anchored after successfully adding the NFT. + AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) error -func getReadAccessProofKeys(m *CoreDocumentModel, registry common.Address, tokenID []byte) (pks []string, err error) { - var rridx int // index of the read rules which contain the role - var ridx int // index of the role - var nftIdx int // index of the NFT in the above role - var rk []byte // role key of the above role + // GetCollaborators returns the collaborators of this Document. + // filter ids should not be returned + GetCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) - found := m.findRole(func(i, j int, role *coredocumentpb.Role) bool { - z, found := isNFTInRole(role, registry, tokenID) - if found { - rridx = i - ridx = j - rk = role.RoleKey - nftIdx = z - } + // AccountCanRead returns true if the account can read the document + AccountCanRead(account identity.DID) bool - return found - }, ACLRead) + // NFTOwnerCanRead returns error if the NFT cannot read the document. + NFTOwnerCanRead(tokenRegistry TokenRegistry, registry common.Address, tokenID []byte, account identity.DID) error - if !found { - return nil, ErrNFTRoleMissing - } - - return []string{ - fmt.Sprintf(CDTreePrefix+".read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role - fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists - fmt.Sprintf(CDTreePrefix+".read_rules[%d].action", rridx), // proof that this read rule has read access - }, nil + // ATOwnerCanRead returns error if the NFT cannot read the document. + ATOwnerCanRead(tokenID, docID []byte, account identity.DID) (err error) } -func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) (pk string, err error) { - nft := getStoredNFT(nfts, registry.Bytes()) - if nft == nil { - return pk, errors.New("nft is missing from the document") - } - - key := hexutil.Encode(nft.RegistryId) - return fmt.Sprintf(CDTreePrefix+".nfts[%s]", key), nil -} - -func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.DID) (pk string, err error) { - role, err := getRole(roleKey, roles) - if err != nil { - return pk, err - } - - idx, found := isAccountInRole(role, account) - if !found { - return pk, ErrNFTRoleMissing - } - - return fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[%d]", hexutil.Encode(role.RoleKey), idx), nil +// TokenRegistry defines NFT related functions. +type TokenRegistry interface { + // OwnerOf to retrieve owner of the tokenID + OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) } diff --git a/documents/model_test.go b/documents/model_test.go deleted file mode 100644 index c3a11ab88..000000000 --- a/documents/model_test.go +++ /dev/null @@ -1,844 +0,0 @@ -// +build unit - -package documents - -import ( - "crypto/sha256" - "fmt" - "os" - "testing" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" - "github.com/centrifuge/go-centrifuge/testingutils/config" - - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/storage/leveldb" - - "github.com/centrifuge/go-centrifuge/testingutils/identity" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/bootstrap" - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/centrifuge/go-centrifuge/queue" - "github.com/centrifuge/go-centrifuge/testingutils/commons" - "github.com/centrifuge/go-centrifuge/transactions/txv1" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/precise-proofs/proofs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -var ctx map[string]interface{} -var ConfigService config.Service -var cfg config.Configuration - -func TestMain(m *testing.M) { - ctx = make(map[string]interface{}) - ethClient := &testingcommons.MockEthClient{} - ethClient.On("GetEthClient").Return(nil) - ctx[ethereum.BootstrappedEthereumClient] = ethClient - ibootstappers := []bootstrap.TestBootstrapper{ - &testlogging.TestLoggingBootstrapper{}, - &config.Bootstrapper{}, - &leveldb.Bootstrapper{}, - &configstore.Bootstrapper{}, - txv1.Bootstrapper{}, - &queue.Bootstrapper{}, - &anchors.Bootstrapper{}, - &Bootstrapper{}, - } - ctx[identity.BootstrappedDIDService] = &testingcommons.MockIdentityService{} - ctx[identity.BootstrappedDIDFactory] = &testingcommons.MockIdentityFactory{} - bootstrap.RunTestBootstrappers(ibootstappers, ctx) - ConfigService = ctx[config.BootstrappedConfigStorage].(config.Service) - cfg = ctx[bootstrap.BootstrappedConfig].(config.Configuration) - - cfg.Set("keys.p2p.publicKey", "../build/resources/p2pKey.pub.pem") - cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") - cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") - cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") - result := m.Run() - bootstrap.RunTestTeardown(ibootstappers) - os.Exit(result) -} - -func Test_fetchUniqueCollaborators(t *testing.T) { - o1 := testingidentity.GenerateRandomDID() - o2 := testingidentity.GenerateRandomDID() - n1 := testingidentity.GenerateRandomDID() - tests := []struct { - old [][]byte - new []string - result []identity.DID - err bool - }{ - { - new: []string{n1.String()}, - result: []identity.DID{n1}, - }, - - { - old: [][]byte{o1[:]}, - new: []string{n1.String()}, - result: []identity.DID{n1}, - }, - - { - old: [][]byte{o1[:], n1[:]}, - new: []string{n1.String()}, - }, - - { - old: [][]byte{o1[:], o2[:]}, - }, - - // new collaborator with wrong format - { - old: [][]byte{o1[:], o2[:]}, - new: []string{"0x0102030405"}, - err: true, - }, - } - - for _, c := range tests { - uc, err := fetchUniqueCollaborators(c.old, c.new) - if err != nil { - if c.err { - continue - } - - t.Fatal(err) - } - - assert.Equal(t, c.result, uc) - } -} - -func TestCoreDocumentModel_PrepareNewVersion(t *testing.T) { - dm := NewCoreDocModel() - cd := dm.Document - assert.NotNil(t, cd) - - //collaborators need to be hex string - collabs := []string{"some ID"} - newDocModel, err := dm.PrepareNewVersion(collabs) - assert.Error(t, err) - assert.Nil(t, newDocModel) - - // missing DocumentRoot - c1 := testingidentity.GenerateRandomDID() - c2 := testingidentity.GenerateRandomDID() - c := []string{c1.String(), c2.String()} - ndm, err := dm.PrepareNewVersion(c) - assert.NotNil(t, err) - assert.Nil(t, ndm) - - // successful preparation of new version upon addition of DocumentRoot - cd.DocumentRoot = utils.RandomSlice(32) - ndm, err = dm.PrepareNewVersion(c) - assert.Nil(t, err) - assert.NotNil(t, ndm) - - // successful updating of version in new Document - ncd := ndm.Document - ocd := dm.Document - assert.Equal(t, ncd.PreviousVersion, ocd.CurrentVersion) - assert.Equal(t, ncd.CurrentVersion, ocd.NextVersion) - - // DocumentIdentifier has not changed - assert.Equal(t, ncd.DocumentIdentifier, ocd.DocumentIdentifier) - - // DocumentRoot was updated - assert.Equal(t, ncd.PreviousRoot, ocd.DocumentRoot) - - // TokenRegistry was copied over - assert.Equal(t, ndm.TokenRegistry, dm.TokenRegistry) -} - -func TestReadACLs_initReadRules(t *testing.T) { - dm := NewCoreDocModel() - cd := dm.Document - err := dm.initReadRules(nil) - assert.Error(t, err) - assert.True(t, errors.IsOfType(ErrZeroCollaborators, err)) - - cs := []identity.DID{testingidentity.GenerateRandomDID()} - err = dm.initReadRules(cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) - - err = dm.initReadRules(cs) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) -} - -func TestReadAccessValidator_AccountCanRead(t *testing.T) { - dm := NewCoreDocModel() - account := testingidentity.GenerateRandomDID() - - dm.Document.DocumentRoot = utils.RandomSlice(32) - ndm, err := dm.PrepareNewVersion([]string{account.String()}) - cd := ndm.Document - assert.NoError(t, err) - assert.NotNil(t, cd.ReadRules) - assert.NotNil(t, cd.Roles) - - // account who cant access - rcid := testingidentity.GenerateRandomDID() - assert.False(t, ndm.AccountCanRead(rcid)) - - // account can access - assert.True(t, ndm.AccountCanRead(account)) -} - -func TestGetSigningProofHashes(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - dm := NewCoreDocModel() - cd := dm.Document - cd.EmbeddedData = docAny - cd.DataRoot = utils.RandomSlice(32) - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - - err = dm.CalculateSigningRoot(cd.DataRoot) - assert.Nil(t, err) - - err = dm.CalculateDocumentRoot() - assert.Nil(t, err) - - hashes, err := dm.getSigningRootProofHashes() - assert.Nil(t, err) - assert.Equal(t, 1, len(hashes)) - - valid, err := proofs.ValidateProofSortedHashes(cd.SigningRoot, hashes, cd.DocumentRoot, sha256.New()) - assert.True(t, valid) - assert.Nil(t, err) -} - -func TestGetDataProofHashes(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - dm := NewCoreDocModel() - cd := dm.Document - cd.EmbeddedData = docAny - cd.DataRoot = utils.RandomSlice(32) - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - - err = dm.CalculateSigningRoot(cd.DataRoot) - assert.Nil(t, err) - - err = dm.CalculateDocumentRoot() - assert.Nil(t, err) - - hashes, err := dm.getDataProofHashes(cd.DataRoot) - assert.Nil(t, err) - assert.Equal(t, 2, len(hashes)) - - valid, err := proofs.ValidateProofSortedHashes(cd.DataRoot, hashes, cd.DocumentRoot, sha256.New()) - assert.True(t, valid) - assert.Nil(t, err) -} - -func TestGetDocumentSigningTree(t *testing.T) { - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - dm := NewCoreDocModel() - cd := dm.Document - cd.EmbeddedData = docAny - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - tree, err := dm.GetDocumentSigningTree(cd.DataRoot) - assert.Nil(t, err) - assert.NotNil(t, tree) - - _, leaf := tree.GetLeafByProperty(SigningTreePrefix + ".data_root") - assert.NotNil(t, leaf) - - _, leaf = tree.GetLeafByProperty(SigningTreePrefix + ".cd_root") - assert.NotNil(t, leaf) -} - -func TestGetDocumentSigningTree_EmptyEmbeddedData(t *testing.T) { - dm := NewCoreDocModel() - cd := dm.Document - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - tree, err := dm.GetDocumentSigningTree(cd.DataRoot) - assert.NotNil(t, err) - assert.Nil(t, tree) -} - -func TestCoreDocumentTree(t *testing.T) { - dm := NewCoreDocModel() - cd := dm.Document - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - cd.EmbeddedData = docAny - cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - tree1, err := dm.GetCoreDocumentTree() - assert.NoError(t, err) - assert.NotNil(t, tree1) - root1 := tree1.RootHash() - - tree2, err := dm.GetCoreDocumentTree() - assert.NoError(t, err) - root2 := tree2.RootHash() - assert.Equal(t, root1, root2) -} - -// TestGetDocumentRootTree tests that the documentroottree is properly calculated -func TestGetDocumentRootTree(t *testing.T) { - dm := NewCoreDocModel() - cd := &coredocumentpb.CoreDocument{SigningRoot: []byte{0x72, 0xee, 0xb8, 0x88, 0x92, 0xf7, 0x6, 0x19, 0x82, 0x76, 0xe9, 0xe7, 0xfe, 0xcc, 0x33, 0xa, 0x66, 0x78, 0xd4, 0xa6, 0x5f, 0xf6, 0xa, 0xca, 0x2b, 0xe4, 0x17, 0xa9, 0xf6, 0x15, 0x67, 0xa1}} - dm.Document = cd - tree, err := dm.GetDocumentRootTree() - - // Manually constructing the two node tree: - signaturesLengthLeaf := sha256.Sum256(append(append(compactProperties(SignaturesField), []byte{48}...), make([]byte, 32)...)) - expectedRootHash := sha256.Sum256(append(dm.Document.SigningRoot, signaturesLengthLeaf[:]...)) - assert.Nil(t, err) - assert.Equal(t, expectedRootHash[:], tree.RootHash()) -} - -func TestCreateProofs(t *testing.T) { - h := sha256.New() - testTree := NewDefaultTree(nil) - props := []proofs.Property{NewLeafProperty("sample_field", []byte{0, 0, 0, 200}), NewLeafProperty("sample_field2", []byte{0, 0, 0, 202})} - compactProps := [][]byte{props[0].Compact, props[1].Compact} - err := testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[0]}) - assert.NoError(t, err) - err = testTree.AddLeaf(proofs.LeafNode{Hash: utils.RandomSlice(32), Hashed: true, Property: props[1]}) - assert.NoError(t, err) - err = testTree.Generate() - assert.NoError(t, err) - docAny := &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - dm := NewCoreDocModel() - cd := dm.Document - cd.EmbeddedData = docAny - cd.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} - err = dm.setCoreDocumentSalts() - assert.NoError(t, err) - err = dm.CalculateSigningRoot(testTree.RootHash()) - assert.NoError(t, err) - err = dm.CalculateDocumentRoot() - assert.NoError(t, err) - cdTree, err := dm.GetCoreDocumentTree() - assert.NoError(t, err) - tests := []struct { - fieldName string - fromCoreDoc bool - proofLength int - }{ - { - "sample_field", - false, - 3, - }, - { - CDTreePrefix + ".document_identifier", - true, - 6, - }, - { - "sample_field2", - false, - 3, - }, - { - CDTreePrefix + ".collaborators[0]", - true, - 6, - }, - } - for _, test := range tests { - t.Run(test.fieldName, func(t *testing.T) { - p, err := dm.CreateProofs(testTree, []string{test.fieldName}) - assert.NoError(t, err) - assert.Equal(t, test.proofLength, len(p[0].SortedHashes)) - var l *proofs.LeafNode - if test.fromCoreDoc { - _, l = cdTree.GetLeafByProperty(test.fieldName) - valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:4], cdTree.RootHash(), h) - assert.NoError(t, err) - assert.True(t, valid) - } else { - _, l = testTree.GetLeafByProperty(test.fieldName) - assert.Contains(t, compactProps, l.Property.CompactName()) - valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes[:1], testTree.RootHash(), h) - assert.NoError(t, err) - assert.True(t, valid) - } - valid, err := proofs.ValidateProofSortedHashes(l.Hash, p[0].SortedHashes, cd.DocumentRoot, h) - assert.NoError(t, err) - assert.True(t, valid) - }) - } -} - -type mockRegistry struct { - mock.Mock -} - -func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { - args := m.Called(registry, tokenID) - addr, _ := args.Get(0).(common.Address) - return addr, args.Error(1) -} - -func Test_addNFTToReadRules(t *testing.T) { - dm := NewCoreDocModel() - // wrong registry or token format - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(34) - err := dm.AddNFTToReadRules(registry, tokenID) - assert.Error(t, err) - - dm.Document.DocumentRoot = utils.RandomSlice(32) - dm, err = dm.PrepareNewVersion([]string{testingidentity.GenerateRandomDID().String()}) - assert.NoError(t, err) - cd := dm.Document - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 1) - assert.Equal(t, cd.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ_SIGN) - assert.Len(t, cd.Roles, 1) - - tokenID = utils.RandomSlice(32) - err = dm.AddNFTToReadRules(registry, tokenID) - assert.NoError(t, err) - assert.Len(t, cd.ReadRules, 2) - assert.Equal(t, cd.ReadRules[1].Action, coredocumentpb.Action_ACTION_READ) - assert.Len(t, cd.Roles, 2) -} - -func TestReadAccessValidator_NFTOwnerCanRead(t *testing.T) { - dm := NewCoreDocModel() - dm.Document.DocumentRoot = utils.RandomSlice(32) - account := testingidentity.GenerateRandomDID() - - dm, err := dm.PrepareNewVersion([]string{account.String()}) - assert.NoError(t, err) - - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - - // account can read - err = dm.NFTOwnerCanRead(registry, nil, account) - assert.NoError(t, err) - - // account not in read rules and nft missing - account = testingidentity.GenerateRandomDID() - assert.NoError(t, err) - tokenID := utils.RandomSlice(32) - err = dm.NFTOwnerCanRead(registry, tokenID, account) - assert.Error(t, err) - - tr := mockRegistry{} - tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() - dm.TokenRegistry = tr - err = dm.AddNFTToReadRules(registry, tokenID) - assert.NoError(t, err) - err = dm.NFTOwnerCanRead(registry, tokenID, account) - assert.Error(t, err) - assert.Contains(t, err, "failed to get owner of") - tr.AssertExpectations(t) - - // not the same owner - owner := common.BytesToAddress(utils.RandomSlice(20)) - tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() - dm.TokenRegistry = tr - err = dm.NFTOwnerCanRead(registry, tokenID, account) - assert.Error(t, err) - tr.AssertExpectations(t) -} - -func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { - m := NewCoreDocModel() - m.Document.DocumentRoot = utils.RandomSlice(32) - ctx := testingconfig.CreateAccountContext(t, cfg) - account, err := contextutil.Account(ctx) - assert.NoError(t, err) - - cd := m.Document - assert.Len(t, cd.ReadRules, 0) - assert.Len(t, cd.Roles, 0) - - // invalid centID format - payload := documentpb.AccessTokenParams{ - // invalid grantee format - Grantee: "randomCentID", - DocumentIdentifier: "randomDocID", - } - _, err = m.AddAccessTokenToReadRules(ctx, payload) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to construct AT: malformed address provided") - // invalid centID length - invalidCentID := utils.RandomSlice(25) - payload = documentpb.AccessTokenParams{ - Grantee: hexutil.Encode(invalidCentID), - DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), - } - _, err = m.AddAccessTokenToReadRules(ctx, payload) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to construct AT: malformed address provided") - // invalid docID length - id, err := account.GetIdentityID() - assert.NoError(t, err) - invalidDocID := utils.RandomSlice(33) - payload = documentpb.AccessTokenParams{ - Grantee: hexutil.Encode(id), - DocumentIdentifier: hexutil.Encode(invalidDocID), - } - - _, err = m.AddAccessTokenToReadRules(ctx, payload) - assert.Contains(t, err.Error(), "failed to construct AT: invalid identifier length") - // valid - payload = documentpb.AccessTokenParams{ - Grantee: hexutil.Encode(id), - DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), - } - _, err = m.AddAccessTokenToReadRules(ctx, payload) - assert.NoError(t, err) - assert.Len(t, m.Document.ReadRules, 1) - assert.Equal(t, m.Document.ReadRules[0].Action, ACLRead) - assert.Len(t, m.Document.Roles, 1) -} - -func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { - ctx := testingconfig.CreateAccountContext(t, cfg) - account, _ := contextutil.Account(ctx) - m := NewCoreDocModel() - m.Document.DocumentRoot = utils.RandomSlice(32) - id, err := account.GetIdentityID() - granteeID := identity.NewDIDFromByte(id) - assert.NoError(t, err) - payload := documentpb.AccessTokenParams{ - Grantee: hexutil.Encode(granteeID[:]), - DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), - } - dm, err := m.AddAccessTokenToReadRules(ctx, payload) - assert.NoError(t, err) - dm.Document.DocumentRoot = utils.RandomSlice(32) - docRoles := dm.Document.GetRoles() - at := docRoles[0].AccessTokens[0] - assert.NotNil(t, at) - // wrong token identifier - tr := &p2ppb.AccessTokenRequest{ - DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, - AccessTokenId: []byte("randomtokenID"), - } - dr := &p2ppb.GetDocumentRequest{ - DocumentIdentifier: m.Document.DocumentIdentifier, - AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, - AccessTokenRequest: tr, - } - err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) - assert.Error(t, err, "access token not found") - // valid access token - // TODO: this will always fail until validation for signatures is secp - //tr = &p2ppb.AccessTokenRequest{ - // DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, - // AccessTokenId: at.Identifier, - //} - //dr.AccessTokenRequest = tr - //err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) - //assert.NoError(t, err) -} - -func TestGetCoreDocumentSalts(t *testing.T) { - dm := NewCoreDocModel() - // From empty - err := dm.setCoreDocumentSalts() - assert.NoError(t, err) - assert.NotNil(t, dm.Document.CoredocumentSalts) - salts := dm.Document.CoredocumentSalts - - // Return existing - err = dm.setCoreDocumentSalts() - assert.NoError(t, err) - assert.NotNil(t, dm.Document.CoredocumentSalts) - assert.Equal(t, salts, dm.Document.CoredocumentSalts) -} - -func TestGenerateNewSalts(t *testing.T) { - dm := NewCoreDocModel() - salts, err := GenerateNewSalts(dm.Document, "", nil) - assert.NoError(t, err) - assert.NotNil(t, salts) -} - -func TestConvertToProofAndProtoSalts(t *testing.T) { - dm := NewCoreDocModel() - salts, err := GenerateNewSalts(dm.Document, "", nil) - assert.NoError(t, err) - assert.NotNil(t, salts) - - nilProto := ConvertToProtoSalts(nil) - assert.Nil(t, nilProto) - - nilProof := ConvertToProofSalts(nil) - assert.Nil(t, nilProof) - - protoSalts := ConvertToProtoSalts(salts) - assert.NotNil(t, protoSalts) - assert.Len(t, protoSalts, len(*salts)) - assert.Equal(t, protoSalts[0].Value, (*salts)[0].Value) - - cSalts := ConvertToProofSalts(protoSalts) - assert.NotNil(t, cSalts) - assert.Len(t, *cSalts, len(*salts)) - assert.Equal(t, (*cSalts)[0].Value, (*salts)[0].Value) -} - -func TestCoreDocumentModel_AddNFT(t *testing.T) { - dm := NewCoreDocModel() - cd := dm.Document - cd.DocumentRoot = utils.RandomSlice(32) - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") - tokenID := utils.RandomSlice(32) - assert.Nil(t, cd.Nfts) - assert.Nil(t, cd.ReadRules) - assert.Nil(t, cd.Roles) - - ndm, err := dm.AddNFT(true, registry, tokenID) - assert.Nil(t, err) - cd = ndm.Document - assert.Len(t, cd.Nfts, 1) - assert.Len(t, cd.Nfts[0].RegistryId, 32) - assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) - assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) - assert.Len(t, cd.ReadRules, 1) - assert.Len(t, cd.Roles, 1) - assert.Len(t, cd.Roles[0].Nfts, 1) - - tokenID = utils.RandomSlice(32) - cd.DocumentRoot = utils.RandomSlice(32) - ndm, err = ndm.AddNFT(true, registry, tokenID) - assert.Nil(t, err) - cd = ndm.Document - assert.Len(t, cd.Nfts, 1) - assert.Len(t, cd.Nfts[0].RegistryId, 32) - assert.Equal(t, tokenID, getStoredNFT(cd.Nfts, registry.Bytes()).TokenId) - assert.Nil(t, getStoredNFT(cd.Nfts, registry2.Bytes())) - assert.Len(t, cd.ReadRules, 2) - assert.Len(t, cd.Roles, 2) - assert.Len(t, cd.Roles[1].Nfts, 1) -} - -func TestCoreDocumentModel_IsNFTMinted(t *testing.T) { - dm := NewCoreDocModel() - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - assert.False(t, dm.IsNFTMinted(nil, registry)) - - cd := dm.Document - cd.DocumentRoot = utils.RandomSlice(32) - tokenID := utils.RandomSlice(32) - owner := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") - ndm, err := dm.AddNFT(true, registry, tokenID) - assert.Nil(t, err) - - tr := new(mockRegistry) - tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() - assert.True(t, ndm.IsNFTMinted(tr, registry)) - tr.AssertExpectations(t) -} - -func TestCoreDocumentModel_IsAccountInRole(t *testing.T) { - dm := NewCoreDocModel() - account := testingidentity.GenerateRandomDID() - roleKey := make([]byte, 32, 32) - assert.False(t, dm.IsAccountInRole(roleKey, account)) - - err := dm.initReadRules([]identity.DID{account}) - assert.NoError(t, err) - roles := dm.Document.Roles - rk := roles[0].RoleKey - assert.True(t, dm.IsAccountInRole(rk, account)) -} - -func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { - dm := NewCoreDocModel() - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(32) - - pfs, err := getReadAccessProofKeys(dm, registry, tokenID) - assert.Error(t, err) - assert.Nil(t, pfs) - - dm.Document.DocumentRoot = utils.RandomSlice(32) - ndm, err := dm.AddNFT(true, registry, tokenID) - assert.NoError(t, err) - assert.NotNil(t, ndm) - role := ndm.Document.Roles[0] - rk := role.RoleKey - - pfs, err = getReadAccessProofKeys(ndm, registry, tokenID) - assert.NoError(t, err) - assert.Len(t, pfs, 3) - assert.Equal(t, CDTreePrefix+".read_rules[0].roles[0]", pfs[0]) - assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(rk)), pfs[1]) - assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[2]) -} - -func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { - dm := NewCoreDocModel() - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - pf, err := getNFTUniqueProofKey(dm.Document.Nfts, registry) - assert.Error(t, err) - assert.Empty(t, pf) - - dm.Document.DocumentRoot = utils.RandomSlice(32) - tokenID := utils.RandomSlice(32) - ndm, err := dm.AddNFT(false, registry, tokenID) - assert.NoError(t, err) - assert.NotNil(t, ndm) - - pf, err = getNFTUniqueProofKey(ndm.Document.Nfts, registry) - assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf(CDTreePrefix+".nfts[%s]", hexutil.Encode(append(registry.Bytes(), make([]byte, 12, 12)...))), pf) -} - -func TestCoreDocument_getRoleProofKey(t *testing.T) { - - dm := NewCoreDocModel() - rk := utils.RandomSlice(32) - account := testingidentity.GenerateRandomDID() - pf, err := getRoleProofKey(dm.Document.Roles, rk, account) - assert.Error(t, err) - assert.Empty(t, pf) - - err = dm.initReadRules([]identity.DID{account}) - assert.NoError(t, err) - - role := dm.Document.Roles[0] - roleKey := role.RoleKey - - pf, err = getRoleProofKey(dm.Document.Roles, roleKey, testingidentity.GenerateRandomDID()) - assert.Error(t, err) - assert.True(t, errors.IsOfType(ErrNFTRoleMissing, err)) - assert.Empty(t, pf) - - pf, err = getRoleProofKey(dm.Document.Roles, roleKey, account) - assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[0]", hexutil.Encode(roleKey)), pf) -} - -func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { - dataRoot := utils.RandomSlice(32) - dm := NewCoreDocModel() - invData := &invoicepb.InvoiceData{} - dataSalts, err := GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) - assert.NoError(t, err) - - dm.Document.EmbeddedData = &any.Any{Value: utils.RandomSlice(32), TypeUrl: documenttypes.InvoiceDataTypeUrl} - account := testingidentity.GenerateRandomDID() - assert.NoError(t, dm.initReadRules([]identity.DID{account})) - - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(32) - dm.Document.DocumentRoot = utils.RandomSlice(32) - dm, err = dm.AddNFT(true, registry, tokenID) - assert.NoError(t, err) - dm.Document.EmbeddedDataSalts = ConvertToProtoSalts(dataSalts) - assert.NoError(t, err) - assert.NoError(t, dm.setCoreDocumentSalts()) - assert.NoError(t, dm.CalculateSigningRoot(dataRoot)) - assert.NoError(t, dm.CalculateDocumentRoot()) - - tests := []struct { - registry common.Address - tokenID []byte - nftReadAccess bool - nftUniqueProof bool - error bool - }{ - - // failed nft unique proof - { - nftUniqueProof: true, - registry: common.BytesToAddress(utils.RandomSlice(20)), - error: true, - }, - - // good nft unique proof - { - nftUniqueProof: true, - registry: registry, - }, - - // failed read access proof - { - nftReadAccess: true, - registry: registry, - tokenID: utils.RandomSlice(32), - error: true, - }, - - // good read access proof - { - nftReadAccess: true, - registry: registry, - tokenID: tokenID, - }, - - // all proofs - { - nftUniqueProof: true, - registry: registry, - nftReadAccess: true, - tokenID: tokenID, - }, - } - - tree, err := dm.GetDocumentRootTree() - assert.NoError(t, err) - - for _, c := range tests { - pfs, err := dm.GetNFTProofs(dataRoot, account, c.registry, c.tokenID, c.nftUniqueProof, c.nftReadAccess) - if c.error { - assert.Error(t, err) - continue - } - - assert.NoError(t, err) - assert.True(t, len(pfs) > 0) - - for _, pf := range pfs { - valid, err := tree.ValidateProof(pf) - assert.NoError(t, err) - assert.True(t, valid) - } - } - -} diff --git a/documents/processor.go b/documents/processor.go index ef433c193..a863add4a 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" @@ -23,7 +24,7 @@ type Config interface { type Client interface { // GetSignaturesForDocument gets the signatures for document - GetSignaturesForDocument(ctx context.Context, model *CoreDocumentModel) error + GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, error) // after all signatures are collected the sender sends the document including the signatures SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) @@ -48,70 +49,45 @@ func DefaultProcessor(idService identity.ServiceDID, p2pClient Client, repositor } // Send sends the given defaultProcessor to the given recipient on the P2P layer -func (dp defaultProcessor) Send(ctx context.Context, coreDocModel *CoreDocumentModel, recipient identity.DID) (err error) { - if coreDocModel == nil { - return errors.New("passed coreDocModel is nil") - } - if coreDocModel.Document == nil { - return errors.New("passed coreDoc is nil") - } - coreDocument := coreDocModel.Document - log.Infof("sending coredocument %x to recipient %x", coreDocument.DocumentIdentifier, recipient) +func (dp defaultProcessor) Send(ctx context.Context, cd coredocumentpb.CoreDocument, id identity.DID) (err error) { + log.Infof("sending document %x to recipient %x", cd.DocumentIdentifier, id) + ctx, cancel := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) + defer cancel() - c, _ := context.WithTimeout(ctx, dp.config.GetP2PConnectionTimeout()) - resp, err := dp.p2pClient.SendAnchoredDocument(c, recipient, &p2ppb.AnchorDocumentRequest{Document: coreDocument}) + resp, err := dp.p2pClient.SendAnchoredDocument(ctx, id, &p2ppb.AnchorDocumentRequest{Document: &cd}) if err != nil || !resp.Accepted { return errors.New("failed to send document to the node: %v", err) } - log.Infof("Done opening connection against recipient [%x]\n", recipient) - + log.Infof("Sent document to %x\n", id) return nil } // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model Model) error { - dm, err := model.PackCoreDocument() - - if err != nil { - return errors.New("failed to pack core document: %v", err) - } - cd := dm.Document - dataRoot, err := model.CalculateDataRoot() + self, err := contextutil.Self(ctx) if err != nil { return err } - // calculate the signing root - err = dm.CalculateSigningRoot(dataRoot) - if err != nil { - return errors.New("failed to calculate signing root: %v", err) - } - - self, err := contextutil.Self(ctx) + _, err = model.CalculateDataRoot() if err != nil { return err } - sig := identity.Sign(self, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = append(cd.Signatures, sig) - - err = model.UnpackCoreDocument(dm) + // calculate the signing root + sr, err := model.CalculateSigningRoot() if err != nil { - return errors.New("failed to unpack the core document: %v", err) + return errors.New("failed to calculate signing root: %v", err) } + model.AppendSignatures(identity.Sign(self, identity.KeyPurposeSigning, sr)) return nil } // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) error { - dm, err := model.PackCoreDocument() - if err != nil { - return errors.New("failed to pack core document: %v", err) - } - self, err := contextutil.Self(ctx) if err != nil { return err @@ -128,65 +104,45 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e return errors.New("failed to validate model for signature request: %v", err) } - err = dp.p2pClient.GetSignaturesForDocument(ctx, dm) + signs, err := dp.p2pClient.GetSignaturesForDocument(ctx, model) if err != nil { return errors.New("failed to collect signatures from the collaborators: %v", err) } - err = model.UnpackCoreDocument(dm) - if err != nil { - return errors.New("failed to unpack core document: %v", err) - } - + model.AppendSignatures(signs...) return nil } // PrepareForAnchoring validates the signatures and generates the document root func (dp defaultProcessor) PrepareForAnchoring(model Model) error { - dm, err := model.PackCoreDocument() - if err != nil { - return errors.New("failed to pack core document: %v", err) - } - psv := PostSignatureRequestValidator(dp.identityService) - err = psv.Validate(nil, model) + err := psv.Validate(nil, model) if err != nil { return errors.New("failed to validate signatures: %v", err) } - err = dm.CalculateDocumentRoot() - if err != nil { - return errors.New("failed to generate document root: %v", err) - } - - err = model.UnpackCoreDocument(dm) - if err != nil { - return errors.New("failed to unpack core document: %v", err) - } - return nil } // AnchorDocument validates the model, and anchors the document func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) error { - dm, err := model.PackCoreDocument() + pav := PreAnchorValidator(dp.identityService) + err := pav.Validate(nil, model) if err != nil { - return errors.New("failed to pack core document: %v", err) + return errors.New("pre anchor validation failed: %v", err) } - pav := PreAnchorValidator(dp.identityService) - err = pav.Validate(nil, model) + dr, err := model.CalculateDocumentRoot() if err != nil { - return errors.New("pre anchor validation failed: %v", err) + return errors.New("failed to get document root: %v", err) } - cd := dm.Document - rootHash, err := anchors.ToDocumentRoot(cd.DocumentRoot) + rootHash, err := anchors.ToDocumentRoot(dr) if err != nil { return errors.New("failed to get document root: %v", err) } - anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) + anchorID, err := anchors.ToAnchorID(model.CurrentVersion()) if err != nil { return errors.New("failed to get anchor ID: %v", err) } @@ -195,7 +151,7 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("failed to generate ethereum MAC: %v", err) } - log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) + log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", model.ID(), model.CurrentVersion(), model.NextVersion(), dr) done, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) isDone := <-done @@ -204,19 +160,14 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("failed to commit anchor: %v", err) } - log.Infof("Anchored document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", cd.DocumentIdentifier, cd.CurrentVersion, cd.NextVersion, cd.DocumentRoot) + log.Infof("Anchored document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", model.ID(), model.CurrentVersion(), model.NextVersion(), dr) return nil } // SendDocument does post anchor validations and sends the document to collaborators func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error { - dm, err := model.PackCoreDocument() - if err != nil { - return errors.New("failed to pack core document: %v", err) - } - av := PostAnchoredValidator(dp.identityService, dp.anchorRepository) - err = av.Validate(nil, model) + err := av.Validate(nil, model) if err != nil { return errors.New("post anchor validations failed: %v", err) } @@ -226,14 +177,18 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error return err } - extCollaborators, err := dm.GetExternalCollaborators(self.ID) + cs, err := model.GetCollaborators(self.ID) if err != nil { return errors.New("get external collaborators failed: %v", err) } - for _, c := range extCollaborators { - DID := identity.NewDIDFromBytes(c) - erri := dp.Send(ctx, dm, DID) + cd, err := model.PackCoreDocument() + if err != nil { + return errors.New("failed to pack core document: %v", err) + } + + for _, c := range cs { + erri := dp.Send(ctx, cd, c) if erri != nil { err = errors.AppendError(err, erri) } diff --git a/documents/processor_test.go b/documents/processor_test.go index 3271bc5ed..195412309 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -6,104 +6,144 @@ import ( "context" "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "golang.org/x/crypto/ed25519" ) -func TestCoreDocumentProcessor_SendNilDocument(t *testing.T) { - dp := DefaultProcessor(nil, nil, nil, cfg) - err := dp.Send(nil, nil, identity.DID{}) - assert.Error(t, err, "should have thrown an error") -} - type mockModel struct { mock.Mock Model + sigs []*coredocumentpb.Signature } -func (m mockModel) PackCoreDocument() (*CoreDocumentModel, error) { +func (m *mockModel) CalculateDataRoot() ([]byte, error) { args := m.Called() - cd, _ := args.Get(0).(*CoreDocumentModel) - return cd, args.Error(1) + dr, _ := args.Get(0).([]byte) + return dr, args.Error(1) +} + +func (m *mockModel) CalculateSigningRoot() ([]byte, error) { + args := m.Called() + sr, _ := args.Get(0).([]byte) + return sr, args.Error(1) +} + +func (m *mockModel) CalculateDocumentRoot() ([]byte, error) { + args := m.Called() + dr, _ := args.Get(0).([]byte) + return dr, args.Error(1) +} + +func (m *mockModel) PreviousDocumentRoot() []byte { + args := m.Called() + dr, _ := args.Get(0).([]byte) + return dr +} + +func (m *mockModel) AppendSignatures(sigs ...*coredocumentpb.Signature) { + m.Called(sigs) + m.sigs = sigs +} + +func (m *mockModel) ID() []byte { + args := m.Called() + id, _ := args.Get(0).([]byte) + return id +} + +func (m *mockModel) CurrentVersion() []byte { + args := m.Called() + id, _ := args.Get(0).([]byte) + return id } -func (m mockModel) UnpackCoreDocument(model *CoreDocumentModel) error { - args := m.Called(model) - return args.Error(0) +func (m *mockModel) NextVersion() []byte { + args := m.Called() + id, _ := args.Get(0).([]byte) + return id } -func (m mockModel) CalculateDataRoot() ([]byte, error) { +func (m *mockModel) PreviousVersion() []byte { args := m.Called() - return args.Get(0).([]byte), args.Error(1) + id, _ := args.Get(0).([]byte) + return id +} + +func (m *mockModel) Signatures() []coredocumentpb.Signature { + m.Called() + var ss []coredocumentpb.Signature + for _, s := range m.sigs { + ss = append(ss, *s) + } + return ss +} + +func (m *mockModel) GetCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) { + args := m.Called(filterIDs) + cids, _ := args.Get(0).([]identity.DID) + return cids, args.Error(1) +} + +func (m *mockModel) PackCoreDocument() (coredocumentpb.CoreDocument, error) { + args := m.Called() + cd, _ := args.Get(0).(coredocumentpb.CoreDocument) + return cd, args.Error(1) } func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - // pack failed - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() ctxh := testingconfig.CreateAccountContext(t, cfg) - err := dp.PrepareForSignatureRequests(ctxh, model) - model.AssertExpectations(t) + + // failed to get self + err := dp.PrepareForSignatureRequests(context.Background(), nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack core document") - - dm := NewCoreDocModel() - cd := dm.Document - model = mockModel{} - - // failed to get id - pub, _ := cfg.GetSigningKeyPair() - cfg.Set("keys.signing.publicKey", "wrong path") - cd.DataRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: "some type", - Value: []byte("some data"), - } - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - cfg.Set("keys.signing.publicKey", pub) - ctxh = testingconfig.CreateAccountContext(t, cfg) - - // failed unpack - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + assert.True(t, errors.IsOfType(contextutil.ErrSelfNotFound, err)) + + // failed data root + model := new(mockModel) + model.On("CalculateDataRoot").Return(nil, errors.New("failed data root")).Once() err = dp.PrepareForSignatureRequests(ctxh, model) + model.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to unpack the core document") + assert.Contains(t, err.Error(), "failed data root") + + // failed signing root + model = new(mockModel) + model.On("CalculateDataRoot").Return(utils.RandomSlice(32), nil).Once() + model.On("CalculateSigningRoot").Return(nil, errors.New("failed signing root")).Once() + err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed signing root") // success - cd.Signatures = nil - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - model.On("UnpackCoreDocument", dm).Return(nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + sr := utils.RandomSlice(32) + model = new(mockModel) + model.On("CalculateDataRoot").Return(utils.RandomSlice(32), nil).Once() + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("AppendSignatures", mock.Anything).Return().Once() err = dp.PrepareForSignatureRequests(ctxh, model) model.AssertExpectations(t) assert.Nil(t, err) - assert.NotNil(t, cd.Signatures) - assert.Len(t, cd.Signatures, 1) - sig := cd.Signatures[0] + assert.NotNil(t, model.sigs) + assert.Len(t, model.sigs, 1) + sig := model.sigs[0] self, _ := contextutil.Self(ctxh) - assert.True(t, ed25519.Verify(self.Keys[identity.KeyPurposeSigning].PublicKey, cd.SigningRoot, sig.Signature)) + assert.True(t, ed25519.Verify(self.Keys[identity.KeyPurposeSigning].PublicKey, sr, sig.Signature)) } type p2pClient struct { @@ -111,88 +151,75 @@ type p2pClient struct { Client } -func (p p2pClient) GetSignaturesForDocument(ctx context.Context, model *CoreDocumentModel) error { +func (p *p2pClient) GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, error) { args := p.Called(ctx, model) - return args.Error(0) + sigs, _ := args.Get(0).([]*coredocumentpb.Signature) + return sigs, args.Error(1) } -func (p p2pClient) SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { +func (p *p2pClient) SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { args := p.Called(ctx, receiverID, in) resp, _ := args.Get(0).(*p2ppb.AnchorDocumentResponse) - return resp, args.Get(1).(error) + return resp, args.Error(1) } func TestDefaultProcessor_RequestSignatures(t *testing.T) { srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - // pack failed - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err := dp.RequestSignatures(ctxh, model) - model.AssertExpectations(t) + + // failed to get self + err := dp.RequestSignatures(context.Background(), nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack core document") + assert.True(t, errors.IsOfType(contextutil.ErrSelfNotFound, err)) + + self, err := contextutil.Self(ctxh) + assert.NoError(t, err) + sr := utils.RandomSlice(32) + keys := self.Keys[identity.KeyPurposeSigning] + sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) // validations failed - dm := NewCoreDocModel() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) + model := new(mockModel) + model.On("ID").Return([]byte{}) + model.On("CurrentVersion").Return([]byte{}) + model.On("NextVersion").Return([]byte{}) + model.On("CalculateSigningRoot").Return(nil, errors.New("error")) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to validate model for signature request") // failed signature collection - dm = NewCoreDocModel() - cd := dm.Document - cd.DataRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: "some type", - Value: []byte("some data"), - } - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - model.On("UnpackCoreDocument", dm).Return(nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - err = dp.PrepareForSignatureRequests(ctxh, model) - assert.Nil(t, err) - model.AssertExpectations(t) - c := p2pClient{} - c.On("GetSignaturesForDocument", ctxh, dm).Return(errors.New("error")).Once() - dp.p2pClient = c - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - err = dp.RequestSignatures(ctxh, model) - model.AssertExpectations(t) - c.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to collect signatures from the collaborators") - - // unpack fail - c = p2pClient{} - c.On("GetSignaturesForDocument", ctxh, dm).Return(nil).Once() + model = new(mockModel) + id := utils.RandomSlice(32) + next := utils.RandomSlice(32) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.sigs = append(model.sigs, sig) + c := new(p2pClient) + c.On("GetSignaturesForDocument", ctxh, model).Return(nil, errors.New("failed to get signatures")).Once() dp.p2pClient = c - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to unpack core document") + assert.Contains(t, err.Error(), "failed to get signatures") // success - c = p2pClient{} - c.On("GetSignaturesForDocument", ctxh, dm).Return(nil).Once() + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("AppendSignatures", []*coredocumentpb.Signature{sig}).Return().Once() + model.sigs = append(model.sigs, sig) + c = new(p2pClient) + c.On("GetSignaturesForDocument", ctxh, model).Return([]*coredocumentpb.Signature{sig}, nil).Once() dp.p2pClient = c - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - model.On("UnpackCoreDocument", dm).Return(nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) err = dp.RequestSignatures(ctxh, model) model.AssertExpectations(t) c.AssertExpectations(t) @@ -202,62 +229,47 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) - // pack failed - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err := dp.PrepareForAnchoring(model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack core document") - // failed validations - dm := NewCoreDocModel() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - err = dp.PrepareForAnchoring(model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to validate signatures") - - // failed unpack - dm = NewCoreDocModel() - cd := dm.Document - cd.DataRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: "some type", - Value: []byte("some data"), - } - dm.setCoreDocumentSalts() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - err = dm.CalculateSigningRoot(cd.DataRoot) - assert.Nil(t, err) - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - model.On("UnpackCoreDocument", dm).Return(errors.New("error")).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - c, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, err) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) - dp = DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) + ctxh := testingconfig.CreateAccountContext(t, cfg) + self, err := contextutil.Self(ctxh) + assert.NoError(t, err) + sr := utils.RandomSlice(32) + keys := self.Keys[identity.KeyPurposeSigning] + sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + + // validation failed + model := new(mockModel) + id := utils.RandomSlice(32) + next := utils.RandomSlice(32) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(errors.New("validation failed")).Once() + dp.identityService = srv err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) srv.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to unpack core document") // success - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(4) - model.On("UnpackCoreDocument", dm).Return(nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv err = dp.PrepareForAnchoring(model) model.AssertExpectations(t) srv.AssertExpectations(t) - assert.Nil(t, err) - assert.NotNil(t, cd.DocumentRoot) + assert.NoError(t, err) } type mockRepo struct { @@ -281,46 +293,44 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - - // pack failed - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err := dp.AnchorDocument(ctxh, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack core document") + self, err := contextutil.Self(ctxh) + assert.NoError(t, err) + sr := utils.RandomSlice(32) + keys := self.Keys[identity.KeyPurposeSigning] + sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) // validations failed - model = mockModel{} - dm := NewCoreDocModel() - model.On("PackCoreDocument").Return(dm, nil).Times(5) + id := utils.RandomSlice(32) + next := utils.RandomSlice(32) + model := new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(nil, errors.New("error")) + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv err = dp.AnchorDocument(ctxh, model) model.AssertExpectations(t) + srv.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "pre anchor validation failed") // success - dm = NewCoreDocModel() - cd := dm.Document - cd.DataRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: "some type", - Value: []byte("some data"), - } - dm.setCoreDocumentSalts() - assert.Nil(t, dm.CalculateSigningRoot(cd.DataRoot)) - c, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} - assert.Nil(t, dm.CalculateDocumentRoot()) - assert.Nil(t, err) - - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(5) - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil) + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv repo := mockRepo{} ch := make(chan bool, 1) ch <- true @@ -338,55 +348,138 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - // pack failed - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err := dp.SendDocument(ctxh, model) + self, err := contextutil.Self(ctxh) + assert.NoError(t, err) + sr := utils.RandomSlice(32) + keys := self.Keys[identity.KeyPurposeSigning] + sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + + // validations failed + id := utils.RandomSlice(32) + aid, err := anchors.ToAnchorID(id) + assert.NoError(t, err) + next := utils.RandomSlice(32) + model := new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil) + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv + repo := mockRepo{} + repo.On("GetDocumentRootOf", aid).Return(nil, errors.New("error")) + dp.anchorRepository = repo + err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) + srv.AssertExpectations(t) + repo.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to pack core document") + assert.Contains(t, err.Error(), "post anchor validations failed") - // failed validations - model = mockModel{} - dm := NewCoreDocModel() - model.On("PackCoreDocument").Return(dm, nil).Times(6) + // get collaborators failed + dr, err := anchors.ToDocumentRoot(utils.RandomSlice(32)) + assert.NoError(t, err) + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(dr[:], nil) + model.On("GetCollaborators", mock.Anything).Return(nil, errors.New("error")).Once() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv + repo = mockRepo{} + repo.On("GetDocumentRootOf", aid).Return(dr, nil).Once() + dp.anchorRepository = repo err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) + srv.AssertExpectations(t) + repo.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "post anchor validations failed") - // failed send - dm = NewCoreDocModel() - cd := dm.Document - cd.DataRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: "some type", - Value: []byte("some data"), - } - cd.Collaborators = [][]byte{[]byte("some id")} - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - dm.setCoreDocumentSalts() - assert.Nil(t, dm.CalculateSigningRoot(cd.DataRoot)) - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Times(6) - c, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - s := identity.Sign(c, identity.KeyPurposeSigning, cd.SigningRoot) - cd.Signatures = []*coredocumentpb.Signature{s} - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) - assert.Nil(t, dm.CalculateDocumentRoot()) - docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) - assert.Nil(t, err) - repo := mockRepo{} - repo.On("GetDocumentRootOf", mock.Anything).Return(docRoot, nil).Once() + // pack core document failed + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(dr[:], nil) + model.On("GetCollaborators", mock.Anything).Return([]identity.DID{testingidentity.GenerateRandomDID()}, nil).Once() + model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv + repo = mockRepo{} + repo.On("GetDocumentRootOf", aid).Return(dr, nil).Once() dp.anchorRepository = repo - p2pc := p2pClient{} - p2pc.On("SendAnchoredDocument", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("not found")).Once() - dp.p2pClient = p2pc err = dp.SendDocument(ctxh, model) model.AssertExpectations(t) srv.AssertExpectations(t) repo.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to send document to the node") + + // send failed + cd := coredocumentpb.CoreDocument{} + did := testingidentity.GenerateRandomDID() + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(dr[:], nil) + model.On("GetCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() + model.On("PackCoreDocument").Return(cd, nil).Once() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv + repo = mockRepo{} + repo.On("GetDocumentRootOf", aid).Return(dr, nil).Once() + client := new(p2pClient) + client.On("SendAnchoredDocument", mock.Anything, did, mock.Anything).Return(nil, errors.New("error")).Once() + dp.anchorRepository = repo + dp.p2pClient = client + err = dp.SendDocument(ctxh, model) + model.AssertExpectations(t) + srv.AssertExpectations(t) + repo.AssertExpectations(t) + client.AssertExpectations(t) + assert.Error(t, err) + + // successful + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.On("CalculateDocumentRoot").Return(dr[:], nil) + model.On("GetCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() + model.On("PackCoreDocument").Return(cd, nil).Once() + model.sigs = append(model.sigs, sig) + srv = &testingcommons.MockIdentityService{} + srv.On("ValidateSignature", sig, sr).Return(nil).Once() + dp.identityService = srv + repo = mockRepo{} + repo.On("GetDocumentRootOf", aid).Return(dr, nil).Once() + client = new(p2pClient) + client.On("SendAnchoredDocument", mock.Anything, did, mock.Anything).Return(&p2ppb.AnchorDocumentResponse{Accepted: true}, nil).Once() + dp.anchorRepository = repo + dp.p2pClient = client + err = dp.SendDocument(ctxh, model) + model.AssertExpectations(t) + srv.AssertExpectations(t) + repo.AssertExpectations(t) + client.AssertExpectations(t) + assert.NoError(t, err) } diff --git a/documents/purchaseorder/model.go b/documents/purchaseorder/model.go index f84eed81f..b472e2fc3 100644 --- a/documents/purchaseorder/model.go +++ b/documents/purchaseorder/model.go @@ -4,16 +4,17 @@ import ( "encoding/json" "reflect" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/centerrors" + "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" @@ -27,6 +28,7 @@ func compactPrefix() []byte { return []byte{0, 2, 0, 0} } // PurchaseOrder implements the documents.Model keeps track of purchase order related fields and state type PurchaseOrder struct { + *documents.CoreDocument Status string // status of the Purchase Order PoNumber string // purchase order number or reference number OrderName string // name of the ordering company @@ -52,21 +54,6 @@ type PurchaseOrder struct { DateCreated *timestamp.Timestamp // purchase order date ExtraData []byte PurchaseOrderSalts *proofs.Salts - CoreDocumentModel *documents.CoreDocumentModel -} - -// ID returns the DocumentIdentifier for this document -// Note: this is not same as VersionIdentifier -func (p *PurchaseOrder) ID() ([]byte, error) { - coreDocModel, err := p.PackCoreDocument() - if err != nil { - return []byte{}, err - } - if coreDocModel.Document == nil { - return []byte{}, errors.New("nil core document") - } - - return coreDocModel.Document.DocumentIdentifier, nil } // getClientData returns the client data from the purchaseOrder model @@ -159,11 +146,12 @@ func (p *PurchaseOrder) InitPurchaseOrderInput(payload *clientpurchaseorderpb.Pu } collaborators := append([]string{self}, payload.Collaborators...) - p.CoreDocumentModel, err = documents.NewWithCollaborators(collaborators) + cd, err := documents.NewCoreDocumentWithCollaborators(collaborators) if err != nil { return errors.New("failed to init core document: %v", err) } + p.CoreDocument = cd return nil } @@ -265,65 +253,50 @@ func (p *PurchaseOrder) getPurchaseOrderSalts(purchaseOrderData *purchaseorderpb } // PackCoreDocument packs the PurchaseOrder into a Core Document -// If the, PurchaseOrder is new, it creates a valid identifiers -func (p *PurchaseOrder) PackCoreDocument() (*documents.CoreDocumentModel, error) { +func (p *PurchaseOrder) PackCoreDocument() (cd coredocumentpb.CoreDocument, err error) { poData := p.createP2PProtobuf() - poSerialized, err := proto.Marshal(poData) + data, err := proto.Marshal(poData) if err != nil { - return nil, centerrors.Wrap(err, "couldn't serialise PurchaseOrderData") - } - - poAny := any.Any{ - TypeUrl: documenttypes.PurchaseOrderDataTypeUrl, - Value: poSerialized, + return cd, errors.New("failed to marshal po data: %v", err) } - poSalts, err := p.getPurchaseOrderSalts(poData) - if err != nil { - return nil, errors.NewTypedError(err, errors.New("couldn't get POSalts")) + embedData := &any.Any{ + TypeUrl: p.DocumentType(), + Value: data, } - err = p.CoreDocumentModel.PackCoreDocument(&poAny, documents.ConvertToProtoSalts(poSalts)) + salts, err := p.getPurchaseOrderSalts(poData) if err != nil { - return nil, err + return cd, errors.New("failed to get po salts: %v", err) } - return p.CoreDocumentModel, nil + return p.CoreDocument.PackCoreDocument(embedData, documents.ConvertToProtoSalts(salts)), nil } // UnpackCoreDocument unpacks the core document into PurchaseOrder -func (p *PurchaseOrder) UnpackCoreDocument(coreDocModel *documents.CoreDocumentModel) error { - if coreDocModel == nil { - return errors.New("coredocmodel is nil %v", coreDocModel) - } - if coreDocModel.Document == nil { - return errors.New("core document provided is nil %v", coreDocModel.Document) - } - - coreDoc := coreDocModel.Document - if coreDoc.EmbeddedData == nil || - coreDoc.EmbeddedData.TypeUrl != documenttypes.PurchaseOrderDataTypeUrl { +func (p *PurchaseOrder) UnpackCoreDocument(cd coredocumentpb.CoreDocument) error { + if cd.EmbeddedData == nil || + cd.EmbeddedData.TypeUrl != p.DocumentType() { return errors.New("trying to convert document with incorrect schema") } - poData := &purchaseorderpb.PurchaseOrderData{} - err := proto.Unmarshal(coreDoc.EmbeddedData.Value, poData) + poData := new(purchaseorderpb.PurchaseOrderData) + err := proto.Unmarshal(cd.EmbeddedData.Value, poData) if err != nil { return err } p.loadFromP2PProtobuf(poData) - - if coreDoc.EmbeddedDataSalts == nil { + if cd.EmbeddedDataSalts == nil { p.PurchaseOrderSalts, err = p.getPurchaseOrderSalts(poData) if err != nil { return err } } else { - p.PurchaseOrderSalts = documents.ConvertToProofSalts(coreDoc.EmbeddedDataSalts) + p.PurchaseOrderSalts = documents.ConvertToProofSalts(cd.EmbeddedDataSalts) } - err = p.CoreDocumentModel.UnpackCoreDocument() + p.CoreDocument = documents.NewCoreDocumentFromProtobuf(cd) return err } @@ -347,9 +320,12 @@ func (p *PurchaseOrder) Type() reflect.Type { func (p *PurchaseOrder) CalculateDataRoot() ([]byte, error) { t, err := p.getDocumentDataTree() if err != nil { - return nil, errors.New("calculateDataRoot error %v", err) + return nil, errors.New("failed to get data tree: %v", err) } - return t.RootHash(), nil + + dr := t.RootHash() + p.CoreDocument.SetDataRoot(dr) + return dr, nil } // getDocumentDataTree creates precise-proofs data tree for the model @@ -371,19 +347,61 @@ func (p *PurchaseOrder) getDocumentDataTree() (tree *proofs.DocumentTree, err er return t, nil } -// CreateProofs generates proofs for given fields +// CreateProofs generates proofs for given fields. func (p *PurchaseOrder) CreateProofs(fields []string) (proofs []*proofspb.Proof, err error) { - // There can be failure scenarios where the core doc for the particular document - // is still not saved with roots in db due to failures during getting signatures. - _, err = p.PackCoreDocument() + tree, err := p.getDocumentDataTree() if err != nil { return nil, errors.New("createProofs error %v", err) } - tree, err := p.getDocumentDataTree() + return p.CoreDocument.CreateProofs(p.DocumentType(), tree, fields) +} + +// DocumentType returns the po document type. +func (*PurchaseOrder) DocumentType() string { + return documenttypes.PurchaseOrderDataTypeUrl +} + +// PrepareNewVersion prepares new version from the old invoice. +func (p *PurchaseOrder) PrepareNewVersion(old documents.Model, data *clientpurchaseorderpb.PurchaseOrderData, collaborators []string) error { + err := p.initPurchaseOrderFromData(data) if err != nil { - return nil, errors.New("createProofs error %v", err) + return err } - proofs, err = p.CoreDocumentModel.CreateProofs(tree, fields) - return proofs, err + + oldCD := old.(*PurchaseOrder).CoreDocument + p.CoreDocument, err = oldCD.PrepareNewVersion(collaborators, true) + if err != nil { + return err + } + + return nil +} + +// AddNFT adds NFT to the Purchase Order. +func (p *PurchaseOrder) AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) error { + cd, err := p.CoreDocument.AddNFT(grantReadAccess, registry, tokenID) + if err != nil { + return err + } + + p.CoreDocument = cd + return nil +} + +// CalculateSigningRoot returns the signing root of the document. +// Calculates it if not generated yet. +func (p *PurchaseOrder) CalculateSigningRoot() ([]byte, error) { + return p.CoreDocument.CalculateSigningRoot(p.DocumentType()) +} + +// CreateNFTProofs creates proofs specific to NFT minting. +func (p *PurchaseOrder) CreateNFTProofs( + account identity.DID, + registry common.Address, + tokenID []byte, + nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { + return p.CoreDocument.CreateNFTProofs( + p.DocumentType(), + account, registry, tokenID, nftUniqueProof, readAccessProof) } diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 66e0fd763..6b6ad2d4b 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -5,11 +5,9 @@ package purchaseorder import ( "encoding/json" "os" - "reflect" "testing" - "github.com/centrifuge/go-centrifuge/identity/ideth" - + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -20,6 +18,8 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/identity/ideth" + "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" @@ -48,7 +48,7 @@ func TestMain(m *testing.M) { ctx[transactions.BootstrappedService] = txMan done := make(chan bool) txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(transactions.NilTxID(), done, nil) - + ctx[nft.BootstrappedPayObService] = new(testingdocuments.MockRegistry) ibootstrappers := []bootstrap.TestBootstrapper{ &testlogging.TestLoggingBootstrapper{}, &config.Bootstrapper{}, @@ -72,114 +72,69 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestPO_FromCoreDocuments_invalidParameter(t *testing.T) { - poModel := &PurchaseOrder{} - - emptyCoreDocModel := &documents.CoreDocumentModel{ - nil, - nil, - } - err := poModel.UnpackCoreDocument(emptyCoreDocModel) - assert.Error(t, err, "it should not be possible to init a empty core document") - - err = poModel.UnpackCoreDocument(nil) - assert.Error(t, err, "it should not be possible to init a empty core document") - - invalidEmbeddedData := &any.Any{TypeUrl: "invalid"} - coreDocument := &coredocumentpb.CoreDocument{EmbeddedData: invalidEmbeddedData} - coreDocModel := &documents.CoreDocumentModel{ - coreDocument, - nil, - } - err = poModel.UnpackCoreDocument(coreDocModel) - assert.Error(t, err, "it should not be possible to init invalid typeUrl") - -} - -func TestPO_InitCoreDocument_successful(t *testing.T) { - poModel := &PurchaseOrder{} - - poData := testingdocuments.CreatePOData() - - coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) - poModel.CoreDocumentModel = coreDocumentModel - err := poModel.UnpackCoreDocument(coreDocumentModel) - assert.Nil(t, err, "valid coredocumentmodel shouldn't produce an error") -} - -func TestPO_CoreDocument_successful(t *testing.T) { - poModel := &PurchaseOrder{} - - //init model with a CoreDoc - poData := testingdocuments.CreatePOData() - - coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) - poModel.CoreDocumentModel = coreDocumentModel - err := poModel.UnpackCoreDocument(coreDocumentModel) +func TestPurchaseOrder_PackCoreDocument(t *testing.T) { + id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) assert.NoError(t, err) - returnedCoreDocumentModel, err := poModel.PackCoreDocument() - assert.Nil(t, err, "transformation from purchase order to CoreDoc failed") - - assert.Equal(t, coreDocumentModel.Document.EmbeddedData, returnedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, returnedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") -} - -func TestPO_ModelInterface(t *testing.T) { - var i interface{} = &PurchaseOrder{} - _, ok := i.(documents.Model) - assert.True(t, ok, "model interface not implemented correctly for purchaseOrder model") -} + po := new(PurchaseOrder) + assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String())) -func TestPO_Type(t *testing.T) { - var model documents.Model - model = &PurchaseOrder{} - assert.Equal(t, model.Type(), reflect.TypeOf(&PurchaseOrder{}), "purchaseOrder Type not correct") + cd, err := po.PackCoreDocument() + assert.NoError(t, err) + assert.NotNil(t, cd.EmbeddedData) + assert.NotNil(t, cd.EmbeddedDataSalts) } -func TestPO_JSON(t *testing.T) { - poModel := &PurchaseOrder{} - poData := testingdocuments.CreatePOData() - coreDocumentModel := CreateCDWithEmbeddedPO(t, poData) - poModel.CoreDocumentModel = coreDocumentModel - err := poModel.UnpackCoreDocument(coreDocumentModel) +func TestPurchaseOrder_JSON(t *testing.T) { + po := new(PurchaseOrder) + id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) assert.NoError(t, err) + assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String())) - jsonBytes, err := poModel.JSON() + cd, err := po.PackCoreDocument() + assert.NoError(t, err) + jsonBytes, err := po.JSON() assert.Nil(t, err, "marshal to json didn't work correctly") assert.True(t, json.Valid(jsonBytes), "json format not correct") - err = poModel.FromJSON(jsonBytes) + po = new(PurchaseOrder) + err = po.FromJSON(jsonBytes) assert.Nil(t, err, "unmarshal JSON didn't work correctly") - receivedCoreDocumentModel, err := poModel.PackCoreDocument() - assert.Nil(t, err, "JSON unmarshal damaged purchase order variables") - assert.Equal(t, receivedCoreDocumentModel.Document.EmbeddedData, coreDocumentModel.Document.EmbeddedData, "JSON unmarshal damaged purchase order variables") + ncd, err := po.PackCoreDocument() + assert.Nil(t, err, "JSON unmarshal damaged invoice variables") + assert.Equal(t, cd, ncd) } -func TestPOModel_UnpackCoreDocument(t *testing.T) { +func TestPO_UnpackCoreDocument(t *testing.T) { var model = new(PurchaseOrder) var err error - // nil core doc - err = model.UnpackCoreDocument(nil) - assert.Error(t, err, "unpack must fail") - // embed data missing - err = model.UnpackCoreDocument(new(documents.CoreDocumentModel)) - assert.Error(t, err, "unpack must fail due to missing embed data") + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{}) + assert.Error(t, err) - // successful - coreDocumentModel := CreateCDWithEmbeddedPO(t, testingdocuments.CreatePOData()) - model.CoreDocumentModel = coreDocumentModel - err = model.UnpackCoreDocument(coreDocumentModel) - assert.Nil(t, err, "valid core document with embedded purchase order shouldn't produce an error") + // embed data type is wrong + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{EmbeddedData: new(any.Any)}) + assert.Error(t, err, "unpack must fail due to missing embed data") - receivedCoreDocumentModel, err := model.PackCoreDocument() - assert.Nil(t, err, "model should be able to return the core document with embedded purchase order") + // embed data is wrong + err = model.UnpackCoreDocument(coredocumentpb.CoreDocument{ + EmbeddedData: &any.Any{ + Value: utils.RandomSlice(32), + TypeUrl: documenttypes.PurchaseOrderDataTypeUrl, + }, + }) + assert.Error(t, err) - assert.Equal(t, coreDocumentModel.Document.EmbeddedData, receivedCoreDocumentModel.Document.EmbeddedData, "embeddedData should be the same") - assert.Equal(t, coreDocumentModel.Document.EmbeddedDataSalts, receivedCoreDocumentModel.Document.EmbeddedDataSalts, "embeddedDataSalt should be the same") + // successful + po, cd := createCDWithEmbeddedPO(t) + err = model.UnpackCoreDocument(cd) + assert.NoError(t, err) + assert.Equal(t, model.getClientData(), po.(*PurchaseOrder).getClientData()) + assert.Equal(t, model.ID(), po.ID()) + assert.Equal(t, model.CurrentVersion(), po.CurrentVersion()) + assert.Equal(t, model.PreviousVersion(), po.PreviousVersion()) } func TestPOModel_getClientData(t *testing.T) { @@ -232,8 +187,6 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { assert.NoError(t, err) assert.Equal(t, poModel.Recipient[:], did[:]) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) - - assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators, [][]byte{id.ID[:], collab1[:], collab2[:]}) } func TestPOModel_calculateDataRoot(t *testing.T) { @@ -248,13 +201,15 @@ func TestPOModel_calculateDataRoot(t *testing.T) { assert.False(t, utils.IsEmptyByteSlice(dr)) assert.NotNil(t, poModel.PurchaseOrderSalts, "salts must be created") } -func TestPOModel_createProofs(t *testing.T) { - poModel, err := createMockPurchaseOrder(t) - assert.Nil(t, err) - proof, err := poModel.CreateProofs([]string{"po.po_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) + +func TestPOModel_GenerateProofs(t *testing.T) { + po := createPurchaseOrder(t) + assert.NotNil(t, po) + proof, err := po.CreateProofs([]string{"po.po_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) - tree, err := poModel.CoreDocumentModel.GetDocumentRootTree() + tree, err := po.DocumentRootTree() + assert.NoError(t, err) // Validate po_number valid, err := tree.ValidateProof(proof[0]) @@ -267,7 +222,8 @@ func TestPOModel_createProofs(t *testing.T) { assert.True(t, valid) // Validate []byte value - assert.Equal(t, poModel.CoreDocumentModel.Document.Collaborators[0], proof[1].Value) + id := identity.NewDIDFromBytes(proof[1].Value) + assert.True(t, po.CoreDocument.AccountCanRead(id)) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -276,9 +232,8 @@ func TestPOModel_createProofs(t *testing.T) { } func TestPOModel_createProofsFieldDoesNotExist(t *testing.T) { - poModel, err := createMockPurchaseOrder(t) - assert.Nil(t, err) - _, err = poModel.CreateProofs([]string{"nonexisting"}) + poModel := createPurchaseOrder(t) + _, err := poModel.CreateProofs([]string{"nonexisting"}) assert.NotNil(t, err) } @@ -291,28 +246,15 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { assert.Equal(t, "po.po_number", leaf.Property.ReadableName()) } -func createMockPurchaseOrder(t *testing.T) (*PurchaseOrder, error) { - poModel := &PurchaseOrder{PoNumber: "3213121", NetAmount: 2, OrderAmount: 2, Currency: "USD", CoreDocumentModel: documents.NewCoreDocModel()} - poModel.CoreDocumentModel.Document.Collaborators = [][]byte{{1, 1, 2, 4, 5, 6}, {1, 2, 3, 2, 3, 2}} - dataRoot, err := poModel.CalculateDataRoot() - if err != nil { - return nil, err - } - // get the coreDoc for the purchaseOrder - corDocModel, err := poModel.PackCoreDocument() - if err != nil { - return nil, err - } - - err = corDocModel.CalculateSigningRoot(dataRoot) - if err != nil { - return nil, err - } - err = corDocModel.CalculateDocumentRoot() - if err != nil { - return nil, err - } - err = poModel.UnpackCoreDocument(corDocModel) +func createPurchaseOrder(t *testing.T) *PurchaseOrder { + po := new(PurchaseOrder) + err := po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), "0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + _, err = po.CalculateDataRoot() + assert.NoError(t, err) + _, err = po.CalculateSigningRoot() + assert.NoError(t, err) + _, err = po.CalculateDocumentRoot() assert.NoError(t, err) - return poModel, nil + return po } diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index d1f4bc8ec..9af14c391 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -3,10 +3,10 @@ package purchaseorder import ( "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" clientpopb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" @@ -54,17 +54,15 @@ func DefaultService( } } -// DeriveFromCoreDocumentModel takes a core document model and returns a purchase order -func (s service) DeriveFromCoreDocumentModel(coreDocModel *documents.CoreDocumentModel) (documents.Model, error) { - var model documents.Model = &PurchaseOrder{ - CoreDocumentModel: coreDocModel, - } - err := model.UnpackCoreDocument(coreDocModel) +// DeriveFromCoreDocument takes a core document model and returns a purchase order +func (s service) DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (documents.Model, error) { + po := new(PurchaseOrder) + err := po.UnpackCoreDocument(cd) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentUnPackingCoreDocument, err) } - return model, nil + return po, nil } // validateAndPersist validates the document, and persists to DB @@ -86,7 +84,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], po.CoreDocumentModel.Document.CurrentVersion, po) + err = s.repo.Create(self.ID[:], po.CurrentVersion(), po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -106,14 +104,8 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode return nil, transactions.NilTxID(), nil, err } - dm, err := po.PackCoreDocument() - if err != nil { - return nil, transactions.NilTxID(), nil, err - } - - did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, po.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, nil } @@ -121,34 +113,28 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode } // Update validates, persists, and anchors a new version of purchase order -func (s service) Update(ctx context.Context, po documents.Model) (documents.Model, transactions.TxID, chan bool, error) { +func (s service) Update(ctx context.Context, new documents.Model) (documents.Model, transactions.TxID, chan bool, error) { self, err := contextutil.Self(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } - dm, err := po.PackCoreDocument() - if err != nil { - return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - old, err := s.GetCurrentVersion(ctx, dm.Document.DocumentIdentifier) + old, err := s.GetCurrentVersion(ctx, new.ID()) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentNotFound, err) } - po, err = s.validateAndPersist(ctx, old, po, UpdateValidator()) + new, err = s.validateAndPersist(ctx, old, new, UpdateValidator()) if err != nil { return nil, transactions.NilTxID(), nil, err } - did := identity.NewDIDFromBytes(self.ID[:]) txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, did, txID, dm.Document.CurrentVersion) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, new.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } - return po, txID, done, nil + return new, txID, done, nil } // DeriveFromCreatePayload derives purchase order from create payload @@ -163,9 +149,6 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientpop } po := new(PurchaseOrder) - if po.CoreDocumentModel == nil { - po.CoreDocumentModel = documents.NewCoreDocModel() - } err = po.InitPurchaseOrderInput(payload, idConf.ID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) @@ -193,28 +176,11 @@ func (s service) DeriveFromUpdatePayload(ctx context.Context, payload *clientpop // load purchase order data po := new(PurchaseOrder) - err = po.initPurchaseOrderFromData(payload.Data) + err = po.PrepareNewVersion(old, payload.Data, payload.Collaborators) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, errors.New("failed to load purchase order from data: %v", err)) } - // update core document - oldDM, err := old.PackCoreDocument() - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) - } - - idConf, err := contextutil.Self(ctx) - if err != nil { - return nil, documents.ErrDocumentConfigAccountID - } - - collaborators := append([]string{idConf.ID.String()}, payload.Collaborators...) - po.CoreDocumentModel, err = oldDM.PrepareNewVersion(collaborators) - if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPrepareCoreDocument, err) - } - return po, nil } @@ -230,26 +196,25 @@ func (s service) DerivePurchaseOrderData(doc documents.Model) (*clientpopb.Purch // DerivePurchaseOrderResponse returns po response from the model func (s service) DerivePurchaseOrderResponse(doc documents.Model) (*clientpopb.PurchaseOrderResponse, error) { - dm, err := doc.PackCoreDocument() + data, err := s.DerivePurchaseOrderData(doc) if err != nil { - return nil, errors.NewTypedError(documents.ErrDocumentPackingCoreDocument, err) + return nil, err } - cd := dm.Document - collaborators := make([]string, len(cd.Collaborators)) - for i, c := range cd.Collaborators { - DID := identity.NewDIDFromBytes(c) - collaborators[i] = DID.String() + + cs, err := doc.GetCollaborators() + if err != nil { + return nil, err } - h := &clientpopb.ResponseHeader{ - DocumentId: hexutil.Encode(cd.DocumentIdentifier), - VersionId: hexutil.Encode(cd.CurrentVersion), - Collaborators: collaborators, + var css []string + for _, c := range cs { + css = append(css, c.String()) } - data, err := s.DerivePurchaseOrderData(doc) - if err != nil { - return nil, err + h := &clientpopb.ResponseHeader{ + DocumentId: hexutil.Encode(doc.ID()), + VersionId: hexutil.Encode(doc.CurrentVersion()), + Collaborators: css, } return &clientpopb.PurchaseOrderResponse{ diff --git a/documents/purchaseorder/service_test.go b/documents/purchaseorder/service_test.go index 75721e37c..0556edddf 100644 --- a/documents/purchaseorder/service_test.go +++ b/documents/purchaseorder/service_test.go @@ -9,9 +9,7 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" clientpurchaseorderpb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/purchaseorder" "github.com/centrifuge/go-centrifuge/storage" @@ -29,9 +27,8 @@ import ( ) var ( - cid = testingidentity.GenerateRandomDID() - accountID = cid[:] - centIDBytes = cid[:] + cid = testingidentity.GenerateRandomDID() + accountID = cid[:] ) type mockAnchorRepo struct { @@ -58,46 +55,16 @@ func getServiceWithMockedLayers() (*testingcommons.MockIdentityService, Service) } func TestService_Update(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() ctxh := testingconfig.CreateAccountContext(t, cfg) - // pack failed - model := &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("pack error")).Once() - _, _, _, err := poSrv.Update(ctxh, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "pack error") - // missing last version - model = &testingdocuments.MockModel{} - dm := documents.NewCoreDocModel() - model.On("PackCoreDocument").Return(dm, nil).Once() - _, _, _, err = poSrv.Update(ctxh, model) - model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "document not found") - - payload := testingdocuments.CreatePOPayload() - payload.Collaborators = []string{testingidentity.GenerateRandomDID().String()} - po, err := poSrv.DeriveFromCreatePayload(ctxh, payload) - assert.Nil(t, err) - dm, err = po.PackCoreDocument() - assert.Nil(t, err) - dm.Document.DocumentRoot = utils.RandomSlice(32) - po.(*PurchaseOrder).CoreDocumentModel = dm - testRepo().Create(accountID, dm.Document.CurrentVersion, po) - - // calculate data root fails - model = &testingdocuments.MockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - _, _, _, err = poSrv.Update(ctxh, model) - model.AssertExpectations(t) + po, _ := createCDWithEmbeddedPO(t) + _, _, _, err := poSrv.Update(ctxh, po) assert.Error(t, err) - assert.Contains(t, err.Error(), "unknown document type") + assert.True(t, errors.IsOfType(documents.ErrDocumentNotFound, err)) + assert.NoError(t, testRepo().Create(accountID, po.CurrentVersion(), po)) // success data, err := poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -105,7 +72,7 @@ func TestService_Update(t *testing.T) { data.ExtraData = hexutil.Encode(utils.RandomSlice(32)) collab := testingidentity.GenerateRandomDID().String() newPO, err := poSrv.DeriveFromUpdatePayload(ctxh, &clientpurchaseorderpb.PurchaseOrderUpdatePayload{ - Identifier: hexutil.Encode(dm.Document.DocumentIdentifier), + Identifier: hexutil.Encode(po.ID()), Collaborators: []string{collab}, Data: data, }) @@ -116,13 +83,9 @@ func TestService_Update(t *testing.T) { po, _, _, err = poSrv.Update(ctxh, newPO) assert.Nil(t, err) assert.NotNil(t, po) - - newDM, err := po.PackCoreDocument() - newCD := newDM.Document - assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) - assert.True(t, testRepo().Exists(accountID, newCD.PreviousVersion)) + assert.True(t, testRepo().Exists(accountID, po.ID())) + assert.True(t, testRepo().Exists(accountID, po.CurrentVersion())) + assert.True(t, testRepo().Exists(accountID, po.PreviousVersion())) newData, err = poSrv.DerivePurchaseOrderData(po) assert.Nil(t, err) @@ -130,8 +93,6 @@ func TestService_Update(t *testing.T) { } func TestService_DeriveFromUpdatePayload(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() ctxh := testingconfig.CreateAccountContext(t, cfg) @@ -164,15 +125,8 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { assert.Nil(t, doc) // failed to load from data - self, _ := contextutil.Self(contextHeader) - old := new(PurchaseOrder) - err = old.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), self.ID.String()) - assert.Nil(t, err) - oldCD := old.CoreDocumentModel.Document - oldCD.DocumentIdentifier = id - oldCD.CurrentVersion = id - oldCD.DocumentRoot = utils.RandomSlice(32) - err = testRepo().Create(accountID, id, old) + old, _ := createCDWithEmbeddedPO(t) + err = testRepo().Create(accountID, old.CurrentVersion(), old) assert.Nil(t, err) payload.Data = &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "0xea939d5c0494b072c51565b191ee59b5d34fbf79", @@ -180,6 +134,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { Currency: "EUR", } + payload.Identifier = hexutil.Encode(old.ID()) doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to load purchase order from data") @@ -190,7 +145,7 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { payload.Collaborators = []string{"some wrong ID"} doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Error(t, err) - assert.True(t, errors.IsOfType(documents.ErrDocumentPrepareCoreDocument, err)) + assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) assert.Nil(t, doc) // success @@ -199,19 +154,14 @@ func TestService_DeriveFromUpdatePayload(t *testing.T) { doc, err = poSrv.DeriveFromUpdatePayload(contextHeader, payload) assert.Nil(t, err) assert.NotNil(t, doc) - dm, err := doc.PackCoreDocument() - cd := dm.Document - assert.Nil(t, err) - assert.Equal(t, wantCollab[:], cd.Collaborators[2]) - assert.Len(t, cd.Collaborators, 3) - oldDM, err := old.PackCoreDocument() - oldCD = oldDM.Document - assert.Nil(t, err) - assert.Equal(t, oldCD.DocumentIdentifier, cd.DocumentIdentifier) - assert.Equal(t, payload.Identifier, hexutil.Encode(cd.DocumentIdentifier)) - assert.Equal(t, oldCD.CurrentVersion, cd.PreviousVersion) - assert.Equal(t, oldCD.NextVersion, cd.CurrentVersion) - assert.NotNil(t, cd.NextVersion) + cs, err := doc.GetCollaborators() + assert.Len(t, cs, 3) + assert.Contains(t, cs, wantCollab) + assert.Equal(t, old.ID(), doc.ID()) + assert.Equal(t, payload.Identifier, hexutil.Encode(doc.ID())) + assert.Equal(t, old.CurrentVersion(), doc.PreviousVersion()) + assert.Equal(t, old.NextVersion(), doc.CurrentVersion()) + assert.NotNil(t, doc.NextVersion()) assert.Equal(t, payload.Data, doc.(*PurchaseOrder).getClientData()) } @@ -253,27 +203,19 @@ func TestService_DeriveFromCreatePayload(t *testing.T) { } func TestService_DeriveFromCoreDocument(t *testing.T) { - // nil doc poSrv := service{repo: testRepo()} - _, err := poSrv.DeriveFromCoreDocumentModel(nil) - assert.Error(t, err, "must fail to derive") - - // successful - data := testingdocuments.CreatePOData() - dm := CreateCDWithEmbeddedPO(t, data) - m, err := poSrv.DeriveFromCoreDocumentModel(dm) + _, cd := createCDWithEmbeddedPO(t) + m, err := poSrv.DeriveFromCoreDocument(cd) assert.Nil(t, err, "must return model") assert.NotNil(t, m, "model must be non-nil") po, ok := m.(*PurchaseOrder) assert.True(t, ok, "must be true") - assert.Equal(t, po.Recipient[:], data.Recipient) - assert.Equal(t, po.OrderAmount, data.OrderAmount) + assert.Equal(t, po.Recipient.String(), "0xEA939D5C0494b072c51565b191eE59B5D34fbf79") + assert.Equal(t, po.OrderAmount, int64(42)) } func TestService_Create(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() // calculate data root fails @@ -282,18 +224,16 @@ func TestService_Create(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "unknown document type") - // anchor fails + // success po, err := poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) m, _, _, err = poSrv.Create(ctxh, po) assert.Nil(t, err) assert.NotNil(t, m) - newDM, err := m.PackCoreDocument() - newCD := newDM.Document assert.Nil(t, err) - assert.True(t, testRepo().Exists(accountID, newCD.DocumentIdentifier)) - assert.True(t, testRepo().Exists(accountID, newCD.CurrentVersion)) + assert.True(t, testRepo().Exists(accountID, po.ID())) + assert.True(t, testRepo().Exists(accountID, po.CurrentVersion())) } func TestService_DerivePurchaseOrderData(t *testing.T) { @@ -319,36 +259,12 @@ func TestService_DerivePurchaseOrderData(t *testing.T) { func TestService_DerivePurchaseOrderResponse(t *testing.T) { poSrv := service{} - // pack fails + // derive data failed m := &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(nil, errors.New("pack core document failed")).Once() r, err := poSrv.DerivePurchaseOrderResponse(m) m.AssertExpectations(t) assert.Nil(t, r) assert.Error(t, err) - assert.Contains(t, err.Error(), "pack core document failed") - - // cent id failed - dm := documents.NewCoreDocModel() - cd := dm.Document - cd.Collaborators = [][]byte{{1, 2, 3, 4, 5, 6}, {5, 6, 7}} - m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() - r, err = poSrv.DerivePurchaseOrderResponse(m) - m.AssertExpectations(t) - assert.Nil(t, r) - assert.Error(t, err) - assert.Contains(t, err.Error(), "document is of invalid type") - - // derive data failed - collab := testingidentity.GenerateRandomDID() - cd.Collaborators = [][]byte{collab[:]} - m = &testingdocuments.MockModel{} - m.On("PackCoreDocument").Return(dm, nil).Once() - r, err = poSrv.DerivePurchaseOrderResponse(m) - m.AssertExpectations(t) - assert.Nil(t, r) - assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalidType, err)) // success @@ -361,155 +277,54 @@ func TestService_DerivePurchaseOrderResponse(t *testing.T) { assert.Equal(t, []string{cid.String(), payload.Collaborators[0]}, r.Header.Collaborators) } -func createMockDocument() (*PurchaseOrder, error) { - documentIdentifier := utils.RandomSlice(32) - nextIdentifier := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - NextVersion: nextIdentifier, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - model := &PurchaseOrder{ - PoNumber: "test_po", - OrderAmount: 42, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, documentIdentifier, model) - return model, err -} - -func TestService_GetVersion_wrongTyp(t *testing.T) { - _, poSrv := getServiceWithMockedLayers() - currentVersion := utils.RandomSlice(32) - documentIdentifier := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - //should be an po - po := &invoice.Invoice{ - GrossAmount: 60, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, currentVersion, po) - assert.Nil(t, err) - - ctxh := testingconfig.CreateAccountContext(t, cfg) - _, err = poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) - assert.Error(t, err) - -} - func TestService_GetCurrentVersion(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() - thirdIdentifier := utils.RandomSlice(32) - doc, err := createMockDocument() - assert.Nil(t, err) + doc, _ := createCDWithEmbeddedPO(t) ctxh := testingconfig.CreateAccountContext(t, cfg) - mod1, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) + err := testRepo().Create(accountID, doc.CurrentVersion(), doc) assert.Nil(t, err) - poLoad1, _ := mod1.(*PurchaseOrder) - assert.Equal(t, poLoad1.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.DocumentIdentifier) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: doc.CoreDocumentModel.Document.DocumentIdentifier, - CurrentVersion: doc.CoreDocumentModel.Document.NextVersion, - NextVersion: thirdIdentifier, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - po2 := &PurchaseOrder{ - OrderAmount: 42, - CoreDocumentModel: coreDocModel, - } - - err = testRepo().Create(accountID, doc.CoreDocumentModel.Document.NextVersion, po2) - assert.Nil(t, err) + data := doc.(*PurchaseOrder).getClientData() + data.Currency = "INR" + doc2 := new(PurchaseOrder) + assert.NoError(t, doc2.PrepareNewVersion(doc, data, nil)) + assert.NoError(t, testRepo().Create(accountID, doc2.CurrentVersion(), doc2)) - mod2, err := poSrv.GetCurrentVersion(ctxh, doc.CoreDocumentModel.Document.DocumentIdentifier) + doc3, err := poSrv.GetCurrentVersion(ctxh, doc.ID()) assert.Nil(t, err) - - poLoad2, _ := mod2.(*PurchaseOrder) - assert.Equal(t, poLoad2.CoreDocumentModel.Document.CurrentVersion, doc.CoreDocumentModel.Document.NextVersion) - assert.Equal(t, poLoad2.CoreDocumentModel.Document.NextVersion, thirdIdentifier) + assert.Equal(t, doc2, doc3) } func TestService_GetVersion(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) _, poSrv := getServiceWithMockedLayers() - documentIdentifier := utils.RandomSlice(32) - currentVersion := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: currentVersion, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - - po := &PurchaseOrder{ - OrderAmount: 42, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, currentVersion, po) + po, _ := createCDWithEmbeddedPO(t) + err := testRepo().Create(accountID, po.CurrentVersion(), po) assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - mod, err := poSrv.GetVersion(ctxh, documentIdentifier, currentVersion) + mod, err := poSrv.GetVersion(ctxh, po.ID(), po.CurrentVersion()) assert.Nil(t, err) - loadpo, _ := mod.(*PurchaseOrder) - assert.Equal(t, loadpo.CoreDocumentModel.Document.CurrentVersion, currentVersion) - assert.Equal(t, loadpo.CoreDocumentModel.Document.DocumentIdentifier, documentIdentifier) - mod, err = poSrv.GetVersion(ctxh, documentIdentifier, []byte{}) + mod, err = poSrv.GetVersion(ctxh, mod.ID(), []byte{}) assert.Error(t, err) } func TestService_Exists(t *testing.T) { _, poSrv := getServiceWithMockedLayers() - documentIdentifier := utils.RandomSlice(32) - coreDoc := &coredocumentpb.CoreDocument{ - DocumentIdentifier: documentIdentifier, - CurrentVersion: documentIdentifier, - } - coreDocModel := &documents.CoreDocumentModel{ - coreDoc, - nil, - } - po := &PurchaseOrder{ - OrderAmount: 42, - CoreDocumentModel: coreDocModel, - } - err := testRepo().Create(accountID, documentIdentifier, po) + po, _ := createCDWithEmbeddedPO(t) + err := testRepo().Create(accountID, po.CurrentVersion(), po) assert.Nil(t, err) ctxh := testingconfig.CreateAccountContext(t, cfg) - exists := poSrv.Exists(ctxh, documentIdentifier) + exists := poSrv.Exists(ctxh, po.CurrentVersion()) assert.True(t, exists, "purchase order should exist") exists = poSrv.Exists(ctxh, utils.RandomSlice(32)) assert.False(t, exists, "purchase order should not exist") - } func TestService_calculateDataRoot(t *testing.T) { - c := &testingconfig.MockConfig{} - c.On("GetIdentityID").Return(centIDBytes, nil) poSrv := service{repo: testRepo()} ctxh := testingconfig.CreateAccountContext(t, cfg) @@ -533,8 +348,7 @@ func TestService_calculateDataRoot(t *testing.T) { // create failed po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - assert.Nil(t, po.(*PurchaseOrder).CoreDocumentModel.Document.DataRoot) - err = poSrv.repo.Create(accountID, po.(*PurchaseOrder).CoreDocumentModel.Document.CurrentVersion, po) + err = poSrv.repo.Create(accountID, po.CurrentVersion(), po) assert.Nil(t, err) po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, po) @@ -544,7 +358,6 @@ func TestService_calculateDataRoot(t *testing.T) { // success po, err = poSrv.DeriveFromCreatePayload(ctxh, testingdocuments.CreatePOPayload()) assert.Nil(t, err) - assert.Nil(t, po.(*PurchaseOrder).CoreDocumentModel.Document.DataRoot) po, err = poSrv.validateAndPersist(ctxh, nil, po, CreateValidator()) assert.Nil(t, err) assert.NotNil(t, po) @@ -563,3 +376,18 @@ func testRepo() documents.Repository { } return testRepoGlobal } + +func createCDWithEmbeddedPO(t *testing.T) (documents.Model, coredocumentpb.CoreDocument) { + po := new(PurchaseOrder) + err := po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), cid.String()) + assert.NoError(t, err) + _, err = po.CalculateDataRoot() + assert.NoError(t, err) + _, err = po.CalculateSigningRoot() + assert.NoError(t, err) + _, err = po.CalculateDocumentRoot() + assert.NoError(t, err) + cd, err := po.PackCoreDocument() + assert.NoError(t, err) + return po, cd +} diff --git a/documents/purchaseorder/utils_test.go b/documents/purchaseorder/utils_test.go deleted file mode 100644 index 88d9281ac..000000000 --- a/documents/purchaseorder/utils_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build unit - -package purchaseorder - -import ( - "testing" - - "github.com/centrifuge/go-centrifuge/documents" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/purchaseorder" - "github.com/stretchr/testify/assert" -) - -func CreateCDWithEmbeddedPO(t *testing.T, poData purchaseorderpb.PurchaseOrderData) *documents.CoreDocumentModel { - identifier := []byte("1") - poModel := &PurchaseOrder{} - poModel.CoreDocumentModel = documents.NewCoreDocModel() - poModel.loadFromP2PProtobuf(&poData) - _, err := poModel.getPurchaseOrderSalts(&poData) - assert.NoError(t, err) - cdm, err := poModel.PackCoreDocument() - assert.NoError(t, err) - cdm.Document.DocumentIdentifier = identifier - - return cdm -} diff --git a/documents/read_acls.go b/documents/read_acls.go new file mode 100644 index 000000000..16ad1408f --- /dev/null +++ b/documents/read_acls.go @@ -0,0 +1,477 @@ +package documents + +import ( + "bytes" + "context" + "fmt" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// initReadRules initiates the read rules for a given CoreDocumentModel. +// Collaborators are given Read_Sign action. +// if the rules are created already, this is a no-op. +// if collaborators are empty, it is a no-op +func (cd *CoreDocument) initReadRules(collaborators []identity.DID) { + if len(cd.Document.Roles) > 0 && len(cd.Document.ReadRules) > 0 { + return + } + + if len(collaborators) < 1 { + return + } + + cd.addCollaboratorsToReadSignRules(collaborators) +} + +// findRole calls OnRole for every role that matches the actions passed in +func findRole(cd coredocumentpb.CoreDocument, onRole func(rridx, ridx int, role *coredocumentpb.Role) bool, actions ...coredocumentpb.Action) bool { + am := make(map[int32]struct{}) + for _, a := range actions { + am[int32(a)] = struct{}{} + } + + for i, rule := range cd.ReadRules { + if _, ok := am[int32(rule.Action)]; !ok { + continue + } + + for j, rk := range rule.Roles { + role, err := getRole(rk, cd.Roles) + if err != nil { + // seems like roles and rules are not in sync + // skip to next one + continue + } + + if onRole(i, j, role) { + return true + } + + } + } + + return false +} + +// GetExternalCollaborators returns collaborators of a Document without the own centID. +func (cd *CoreDocument) GetExternalCollaborators(self identity.DID) ([][]byte, error) { + var cs [][]byte + for _, c := range cd.Document.Collaborators { + id := identity.NewDIDFromBytes(c) + if !self.Equal(id) { + cs = append(cs, c) + } + } + + return cs, nil +} + +// NFTOwnerCanRead checks if the nft owner/account can read the Document +func (cd *CoreDocument) NFTOwnerCanRead(tokenRegistry TokenRegistry, registry common.Address, tokenID []byte, account identity.DID) error { + // check if the account can read the doc + if cd.AccountCanRead(account) { + return nil + } + + // check if the nft is present in read rules + found := findRole(cd.Document, func(_, _ int, role *coredocumentpb.Role) bool { + _, found := isNFTInRole(role, registry, tokenID) + return found + }, coredocumentpb.Action_ACTION_READ) + + if !found { + return errors.New("nft not found in the Document") + } + + // get the owner of the NFT + owner, err := tokenRegistry.OwnerOf(registry, tokenID) + if err != nil { + return errors.New("failed to get NFT owner: %v", err) + } + + // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address + if !bytes.Equal(owner.Bytes(), account[:]) { + return errors.New("account (%v) not owner of the NFT", account.String()) + } + + return nil +} + +// AccountCanRead validate if the core Document can be read by the account . +// Returns an error if not. +func (cd *CoreDocument) AccountCanRead(account identity.DID) bool { + // loop though read rules, check all the rules + return findRole(cd.Document, func(_, _ int, role *coredocumentpb.Role) bool { + _, found := isAccountInRole(role, account) + return found + }, coredocumentpb.Action_ACTION_READ, coredocumentpb.Action_ACTION_READ_SIGN) +} + +// addNFTToReadRules adds NFT token to the read rules of core Document. +func (cd *CoreDocument) addNFTToReadRules(registry common.Address, tokenID []byte) error { + nft, err := ConstructNFT(registry, tokenID) + if err != nil { + return errors.New("failed to construct NFT: %v", err) + } + + role := &coredocumentpb.Role{RoleKey: utils.RandomSlice(32)} + role.Nfts = append(role.Nfts, nft) + cd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + return cd.setSalts() +} + +// AddNFT returns a new CoreDocument model with nft added to the Core Document. If grantReadAccess is true, the nft is added +// to the read rules. +func (cd *CoreDocument) AddNFT(grantReadAccess bool, registry common.Address, tokenID []byte) (*CoreDocument, error) { + ncd, err := cd.PrepareNewVersion(nil, false) + if err != nil { + return nil, errors.New("failed to prepare new version: %v", err) + } + + nft := getStoredNFT(ncd.Document.Nfts, registry.Bytes()) + if nft == nil { + nft = new(coredocumentpb.NFT) + // add 12 empty bytes + eb := make([]byte, 12, 12) + nft.RegistryId = append(registry.Bytes(), eb...) + ncd.Document.Nfts = append(ncd.Document.Nfts, nft) + } + nft.TokenId = tokenID + + if grantReadAccess { + err = ncd.addNFTToReadRules(registry, tokenID) + if err != nil { + return nil, err + } + } + + return ncd, ncd.setSalts() +} + +// IsNFTMinted checks if the there is an NFT that is minted against this Document in the given registry. +func (cd *CoreDocument) IsNFTMinted(tokenRegistry TokenRegistry, registry common.Address) bool { + nft := getStoredNFT(cd.Document.Nfts, registry.Bytes()) + if nft == nil { + return false + } + + _, err := tokenRegistry.OwnerOf(registry, nft.TokenId) + return err == nil +} + +// CreateNFTProofs generate proofs returns proofs for NFT minting. +func (cd *CoreDocument) CreateNFTProofs( + docType string, + account identity.DID, + registry common.Address, + tokenID []byte, + nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { + + if len(cd.Document.DataRoot) != idSize { + return nil, errors.New("data root is invalid") + } + + var pfKeys []string + if nftUniqueProof { + pk, err := getNFTUniqueProofKey(cd.Document.Nfts, registry) + if err != nil { + return nil, err + } + + pfKeys = append(pfKeys, pk) + } + + if readAccessProof { + pks, err := getReadAccessProofKeys(cd.Document, registry, tokenID) + if err != nil { + return nil, err + } + + pfKeys = append(pfKeys, pks...) + } + + signingRootProofHashes, err := cd.getSigningRootProofHashes() + if err != nil { + return nil, errors.New("failed to generate signing root proofs: %v", err) + } + + cdTree, err := cd.documentTree(docType) + if err != nil { + return nil, errors.New("failed to generate core Document tree: %v", err) + } + + proofs, missedProofs := generateProofs(cdTree, pfKeys, append([][]byte{cd.Document.DataRoot}, signingRootProofHashes...)) + if len(missedProofs) != 0 { + return nil, errors.New("failed to create proofs for fields %v", missedProofs) + } + + return proofs, nil +} + +// ConstructNFT appends registry and tokenID to byte slice +func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { + var nft []byte + // first 20 bytes of registry + nft = append(nft, registry.Bytes()...) + + // next 32 bytes of the tokenID + nft = append(nft, tokenID...) + + if len(nft) != nftByteCount { + return nil, errors.New("byte length mismatch") + } + + return nft, nil +} + +// isNFTInRole checks if the given nft(registry + token) is part of the core Document role. +// If found, returns the index of the nft in the role and true +func isNFTInRole(role *coredocumentpb.Role, registry common.Address, tokenID []byte) (nftIdx int, found bool) { + enft, err := ConstructNFT(registry, tokenID) + if err != nil { + return nftIdx, false + } + + for i, n := range role.Nfts { + if bytes.Equal(n, enft) { + return i, true + } + } + + return nftIdx, false +} + +func getStoredNFT(nfts []*coredocumentpb.NFT, registry []byte) *coredocumentpb.NFT { + for _, nft := range nfts { + if bytes.Equal(nft.RegistryId[:20], registry) { + return nft + } + } + + return nil +} + +func getReadAccessProofKeys(cd coredocumentpb.CoreDocument, registry common.Address, tokenID []byte) (pks []string, err error) { + var rridx int // index of the read rules which contain the role + var ridx int // index of the role + var nftIdx int // index of the NFT in the above role + var rk []byte // role key of the above role + + found := findRole(cd, func(i, j int, role *coredocumentpb.Role) bool { + z, found := isNFTInRole(role, registry, tokenID) + if found { + rridx = i + ridx = j + rk = role.RoleKey + nftIdx = z + } + + return found + }, coredocumentpb.Action_ACTION_READ) + + if !found { + return nil, ErrNFTRoleMissing + } + + return []string{ + fmt.Sprintf(CDTreePrefix+".read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role + fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists + fmt.Sprintf(CDTreePrefix+".read_rules[%d].action", rridx), // proof that this read rule has read access + }, nil +} + +func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) (pk string, err error) { + nft := getStoredNFT(nfts, registry.Bytes()) + if nft == nil { + return pk, errors.New("nft is missing from the Document") + } + + key := hexutil.Encode(nft.RegistryId) + return fmt.Sprintf(CDTreePrefix+".nfts[%s]", key), nil +} + +func getRoleProofKey(roles []*coredocumentpb.Role, roleKey []byte, account identity.DID) (pk string, err error) { + role, err := getRole(roleKey, roles) + if err != nil { + return pk, err + } + + idx, found := isAccountInRole(role, account) + if !found { + return pk, ErrNFTRoleMissing + } + + return fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[%d]", hexutil.Encode(role.RoleKey), idx), nil +} + +// isAccountInRole returns the index of the collaborator and true if account is in the given role as collaborators. +func isAccountInRole(role *coredocumentpb.Role, account identity.DID) (idx int, found bool) { + for i, id := range role.Collaborators { + if bytes.Equal(id, account[:]) { + return i, true + } + } + + return idx, false +} + +func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, error) { + for _, role := range roles { + if utils.IsSameByteSlice(role.RoleKey, key) { + return role, nil + } + } + + return nil, errors.New("role %d not found", key) +} + +// isATInRole checks if the given access token is part of the core document role. +func isATInRole(role *coredocumentpb.Role, tokenID []byte) (*coredocumentpb.AccessToken, error) { + for _, a := range role.AccessTokens { + if bytes.Equal(tokenID, a.Identifier) { + return a, nil + } + } + return nil, errors.New("access token not found") +} + +// validateAT validates that given access token against its signature +func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID []byte) error { + // assemble token message from the token for validation + reqID := identity.NewDIDFromByte(requesterID) + granterID := identity.NewDIDFromByte(token.Granter) + tm, err := assembleTokenMessage(token.Identifier, granterID, reqID, token.RoleIdentifier, token.DocumentIdentifier) + if err != nil { + return err + } + validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1, true) + if !validated { + return errors.New("access token is invalid") + } + return nil +} + +// ATOwnerCanRead checks that the owner AT can read the document requested +func (cd *CoreDocument) ATOwnerCanRead(tokenID, docID []byte, account identity.DID) (err error) { + // check if the access token is present in read rules of the document indicated in the AT request + var at *coredocumentpb.AccessToken + findRole(cd.Document, func(_, _ int, role *coredocumentpb.Role) bool { + at, err = isATInRole(role, tokenID) + if err != nil { + return false + } + + return true + }, coredocumentpb.Action_ACTION_READ) + + if err != nil { + return err + } + + // check if the requested document is the document indicated in the access token + if !bytes.Equal(at.DocumentIdentifier, docID) { + return errors.New("the document requested does not match the document to which the access token grants access") + } + // validate the access token + // TODO: fetch public key from Ethereum chain + return validateAT(at.Key, at, account[:]) +} + +// AddAccessToken adds the AccessToken to the read rules of the document +func (cd *CoreDocument) AddAccessToken(ctx context.Context, payload documentpb.AccessTokenParams) (*CoreDocument, error) { + ncd, err := cd.PrepareNewVersion(nil, false) + if err != nil { + return nil, err + } + + role := new(coredocumentpb.Role) + role.RoleKey = utils.RandomSlice(32) + at, err := assembleAccessToken(ctx, payload, role.RoleKey) + if err != nil { + return nil, errors.New("failed to construct access token: %v", err) + } + + role.AccessTokens = append(role.AccessTokens, at) + ncd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + return ncd, ncd.setSalts() +} + +// assembleAccessToken assembles a Read Access Token from the payload received +func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenParams, roleKey []byte) (*coredocumentpb.AccessToken, error) { + account, err := contextutil.Account(ctx) + if err != nil { + return nil, err + } + tokenIdentifier := utils.RandomSlice(32) + id, err := account.GetIdentityID() + if err != nil { + return nil, err + } + granterID := identity.NewDIDFromByte(id) + roleID := roleKey + granteeID, err := identity.NewDIDFromString(payload.Grantee) + if err != nil { + return nil, err + } + // assemble access token message to be signed + docID, err := hexutil.Decode(payload.DocumentIdentifier) + if err != nil { + return nil, err + } + + tm, err := assembleTokenMessage(tokenIdentifier, granterID, granteeID, roleID[:], docID) + if err != nil { + return nil, err + } + + // fetch key pair from identity + // TODO: change to signing key pair once secp scheme is available + sig, err := account.SignMsg(tm) + if err != nil { + return nil, err + } + + keys, err := account.GetKeys() + if err != nil { + return nil, err + } + + // assemble the access token, appending the signature and public keys + at := &coredocumentpb.AccessToken{ + Identifier: tokenIdentifier, + Granter: granterID[:], + Grantee: granteeID[:], + RoleIdentifier: roleID[:], + DocumentIdentifier: docID, + Signature: sig.Signature, + Key: keys[identity.KeyPurposeSigning].PublicKey, + } + + return at, nil +} + +// assembleTokenMessage assembles a token message +func assembleTokenMessage(tokenIdentifier []byte, granterID identity.DID, granteeID identity.DID, roleID []byte, docID []byte) ([]byte, error) { + ids := [][]byte{tokenIdentifier, roleID, docID} + for _, id := range ids { + if len(id) != idSize { + return nil, errors.New("invalid identifier length") + } + } + + tm := append(tokenIdentifier, granterID[:]...) + tm = append(tm, granteeID[:]...) + tm = append(tm, roleID...) + tm = append(tm, docID...) + return tm, nil +} diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go new file mode 100644 index 000000000..181fa13e3 --- /dev/null +++ b/documents/read_acls_test.go @@ -0,0 +1,422 @@ +// +build unit + +package documents + +import ( + "fmt" + "testing" + + "github.com/centrifuge/go-centrifuge/testingutils/identity" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" + "github.com/centrifuge/go-centrifuge/testingutils/config" + + "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/errors" + "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/ptypes/any" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestReadACLs_initReadRules(t *testing.T) { + cd := newCoreDocument() + cd.initReadRules(nil) + assert.Nil(t, cd.Document.Roles) + assert.Nil(t, cd.Document.ReadRules) + + cs := []identity.DID{testingidentity.GenerateRandomDID()} + cd.initReadRules(cs) + assert.Len(t, cd.Document.ReadRules, 1) + assert.Len(t, cd.Document.Roles, 1) + + cd.initReadRules(cs) + assert.Len(t, cd.Document.ReadRules, 1) + assert.Len(t, cd.Document.Roles, 1) +} + +func TestReadAccessValidator_AccountCanRead(t *testing.T) { + cd := newCoreDocument() + account := testingidentity.GenerateRandomDID() + cd.Document.DocumentRoot = utils.RandomSlice(32) + ncd, err := cd.PrepareNewVersion([]string{account.String()}, false) + assert.NoError(t, err) + assert.NotNil(t, ncd.Document.ReadRules) + assert.NotNil(t, ncd.Document.Roles) + + // account who cant access + rcid := testingidentity.GenerateRandomDID() + assert.False(t, ncd.AccountCanRead(rcid)) + + // account can access + assert.True(t, ncd.AccountCanRead(account)) +} + +type mockRegistry struct { + mock.Mock +} + +func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { + args := m.Called(registry, tokenID) + addr, _ := args.Get(0).(common.Address) + return addr, args.Error(1) +} + +func TestCoreDocument_addNFTToReadRules(t *testing.T) { + cd := newCoreDocument() + + // wrong registry or token format + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(34) + err := cd.addNFTToReadRules(registry, tokenID) + assert.Error(t, err) + assert.Nil(t, cd.Document.CoredocumentSalts) + assert.Nil(t, cd.Document.ReadRules) + assert.Nil(t, cd.Document.Roles) + + tokenID = utils.RandomSlice(32) + err = cd.addNFTToReadRules(registry, tokenID) + assert.NoError(t, err) + assert.NotNil(t, cd.Document.CoredocumentSalts) + assert.Len(t, cd.Document.ReadRules, 1) + assert.Equal(t, cd.Document.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ) + assert.Len(t, cd.Document.Roles, 1) + enft, err := ConstructNFT(registry, tokenID) + assert.NoError(t, err) + assert.Equal(t, enft, cd.Document.Roles[0].Nfts[0]) +} + +func TestCoreDocument_NFTOwnerCanRead(t *testing.T) { + account := testingidentity.GenerateRandomDID() + cd, err := NewCoreDocumentWithCollaborators([]string{account.String()}) + assert.NoError(t, err) + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + + // account can read + assert.NoError(t, cd.NFTOwnerCanRead(nil, registry, nil, account)) + + // account not in read rules and nft missing + account = testingidentity.GenerateRandomDID() + tokenID := utils.RandomSlice(32) + assert.Error(t, cd.NFTOwnerCanRead(nil, registry, tokenID, account)) + + tr := mockRegistry{} + tr.On("OwnerOf", registry, tokenID).Return(nil, errors.New("failed to get owner of")).Once() + assert.NoError(t, cd.addNFTToReadRules(registry, tokenID)) + assert.Error(t, cd.NFTOwnerCanRead(tr, registry, tokenID, account)) + tr.AssertExpectations(t) + + // not the same owner + owner := common.BytesToAddress(utils.RandomSlice(20)) + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + assert.Error(t, cd.NFTOwnerCanRead(tr, registry, tokenID, account)) + tr.AssertExpectations(t) + + // TODO(ved): add a successful test once identity v2 is complete +} + +func TestCoreDocumentModel_AddNFT(t *testing.T) { + cd := newCoreDocument() + cd.Document.DocumentRoot = utils.RandomSlice(32) + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") + tokenID := utils.RandomSlice(32) + assert.Nil(t, cd.Document.Nfts) + assert.Nil(t, cd.Document.ReadRules) + assert.Nil(t, cd.Document.Roles) + + cd, err := cd.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + assert.Len(t, cd.Document.Nfts, 1) + assert.Len(t, cd.Document.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Document.Nfts, registry.Bytes()).TokenId) + assert.Nil(t, getStoredNFT(cd.Document.Nfts, registry2.Bytes())) + assert.Len(t, cd.Document.ReadRules, 1) + assert.Len(t, cd.Document.Roles, 1) + assert.Len(t, cd.Document.Roles[0].Nfts, 1) + + tokenID = utils.RandomSlice(32) + cd.Document.DocumentRoot = utils.RandomSlice(32) + cd, err = cd.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + assert.Len(t, cd.Document.Nfts, 1) + assert.Len(t, cd.Document.Nfts[0].RegistryId, 32) + assert.Equal(t, tokenID, getStoredNFT(cd.Document.Nfts, registry.Bytes()).TokenId) + assert.Nil(t, getStoredNFT(cd.Document.Nfts, registry2.Bytes())) + assert.Len(t, cd.Document.ReadRules, 2) + assert.Len(t, cd.Document.Roles, 2) + assert.Len(t, cd.Document.Roles[1].Nfts, 1) +} + +func TestCoreDocument_IsNFTMinted(t *testing.T) { + cd := newCoreDocument() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + assert.False(t, cd.IsNFTMinted(nil, registry)) + + cd.Document.DocumentRoot = utils.RandomSlice(32) + tokenID := utils.RandomSlice(32) + owner := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") + cd, err := cd.AddNFT(true, registry, tokenID) + assert.Nil(t, err) + + tr := new(mockRegistry) + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + assert.True(t, cd.IsNFTMinted(tr, registry)) + tr.AssertExpectations(t) +} + +func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { + cd := newCoreDocument() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(32) + + pfs, err := getReadAccessProofKeys(cd.Document, registry, tokenID) + assert.Error(t, err) + assert.Nil(t, pfs) + + cd.Document.DocumentRoot = utils.RandomSlice(32) + cd, err = cd.AddNFT(true, registry, tokenID) + assert.NoError(t, err) + assert.NotNil(t, cd) + + pfs, err = getReadAccessProofKeys(cd.Document, registry, tokenID) + assert.NoError(t, err) + assert.Len(t, pfs, 3) + assert.Equal(t, CDTreePrefix+".read_rules[0].roles[0]", pfs[0]) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(cd.Document.Roles[0].RoleKey)), pfs[1]) + assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[2]) +} + +func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { + cd := newCoreDocument() + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + pf, err := getNFTUniqueProofKey(cd.Document.Nfts, registry) + assert.Error(t, err) + assert.Empty(t, pf) + + cd.Document.DocumentRoot = utils.RandomSlice(32) + tokenID := utils.RandomSlice(32) + cd, err = cd.AddNFT(false, registry, tokenID) + assert.NoError(t, err) + assert.NotNil(t, cd) + + pf, err = getNFTUniqueProofKey(cd.Document.Nfts, registry) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".nfts[%s]", hexutil.Encode(append(registry.Bytes(), make([]byte, 12, 12)...))), pf) +} + +func TestCoreDocument_getRoleProofKey(t *testing.T) { + cd := newCoreDocument() + roleKey := make([]byte, 32, 32) + account := testingidentity.GenerateRandomDID() + pf, err := getRoleProofKey(cd.Document.Roles, roleKey, account) + assert.Error(t, err) + assert.Empty(t, pf) + + cd.initReadRules([]identity.DID{account}) + roleKey = cd.Document.Roles[0].RoleKey + pf, err = getRoleProofKey(cd.Document.Roles, roleKey, testingidentity.GenerateRandomDID()) + assert.Error(t, err) + assert.True(t, errors.IsOfType(ErrNFTRoleMissing, err)) + assert.Empty(t, pf) + + pf, err = getRoleProofKey(cd.Document.Roles, roleKey, account) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].collaborators[0]", hexutil.Encode(roleKey)), pf) +} + +func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { + cd := newCoreDocument() + invData := &invoicepb.InvoiceData{} + dataSalts, err := GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) + assert.NoError(t, err) + + cd.Document.DataRoot = utils.RandomSlice(32) + cd.Document.EmbeddedData = &any.Any{Value: utils.RandomSlice(32), TypeUrl: documenttypes.InvoiceDataTypeUrl} + account := testingidentity.GenerateRandomDID() + cd.initReadRules([]identity.DID{account}) + registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") + tokenID := utils.RandomSlice(32) + cd.Document.EmbeddedDataSalts = ConvertToProtoSalts(dataSalts) + assert.NoError(t, err) + assert.NoError(t, cd.setSalts()) + _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) + assert.NoError(t, err) + _, err = cd.CalculateDocumentRoot() + assert.NoError(t, err) + cd, err = cd.AddNFT(true, registry, tokenID) + assert.NoError(t, err) + cd.Document.DataRoot = utils.RandomSlice(32) + assert.NoError(t, cd.setSalts()) + _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) + assert.NoError(t, err) + _, err = cd.CalculateDocumentRoot() + assert.NoError(t, err) + + tests := []struct { + registry common.Address + tokenID []byte + nftReadAccess bool + nftUniqueProof bool + error bool + }{ + + // failed nft unique proof + { + nftUniqueProof: true, + registry: common.BytesToAddress(utils.RandomSlice(20)), + error: true, + }, + + // good nft unique proof + { + nftUniqueProof: true, + registry: registry, + }, + + // failed read access proof + { + nftReadAccess: true, + registry: registry, + tokenID: utils.RandomSlice(32), + error: true, + }, + + // good read access proof + { + nftReadAccess: true, + registry: registry, + tokenID: tokenID, + }, + + // all proofs + { + nftUniqueProof: true, + registry: registry, + nftReadAccess: true, + tokenID: tokenID, + }, + } + + tree, err := cd.DocumentRootTree() + assert.NoError(t, err) + + for _, c := range tests { + pfs, err := cd.CreateNFTProofs(documenttypes.InvoiceDataTypeUrl, account, c.registry, c.tokenID, c.nftUniqueProof, c.nftReadAccess) + if c.error { + assert.Error(t, err) + continue + } + + assert.NoError(t, err) + assert.True(t, len(pfs) > 0) + + for _, pf := range pfs { + valid, err := tree.ValidateProof(pf) + assert.NoError(t, err) + assert.True(t, valid) + } + } + +} + +func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { + ctx := testingconfig.CreateAccountContext(t, cfg) + account, _ := contextutil.Account(ctx) + cd := newCoreDocument() + cd.Document.DocumentRoot = utils.RandomSlice(32) + id, err := account.GetIdentityID() + granteeID := identity.NewDIDFromByte(id) + assert.NoError(t, err) + payload := documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(granteeID[:]), + DocumentIdentifier: hexutil.Encode(cd.Document.DocumentIdentifier), + } + ncd, err := cd.AddAccessToken(ctx, payload) + assert.NoError(t, err) + ncd.Document.DocumentRoot = utils.RandomSlice(32) + docRoles := ncd.Document.GetRoles() + at := docRoles[0].AccessTokens[0] + assert.NotNil(t, at) + // wrong token identifier + tr := &p2ppb.AccessTokenRequest{ + DelegatingDocumentIdentifier: ncd.Document.DocumentIdentifier, + AccessTokenId: []byte("randomtokenID"), + } + dr := &p2ppb.GetDocumentRequest{ + DocumentIdentifier: ncd.Document.DocumentIdentifier, + AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, + AccessTokenRequest: tr, + } + err = ncd.ATOwnerCanRead(dr.AccessTokenRequest.AccessTokenId, dr.DocumentIdentifier, granteeID) + assert.Error(t, err, "access token not found") + // valid access token + // TODO: this will always fail until validation for signatures is secp + //tr = &p2ppb.AccessTokenRequest{ + // DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, + // AccessTokenId: at.Identifier, + //} + //dr.AccessTokenRequest = tr + //err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) + //assert.NoError(t, err) +} + +func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { + m := newCoreDocument() + m.Document.DocumentRoot = utils.RandomSlice(32) + ctx := testingconfig.CreateAccountContext(t, cfg) + account, err := contextutil.Account(ctx) + assert.NoError(t, err) + + cd := m.Document + assert.Len(t, cd.ReadRules, 0) + assert.Len(t, cd.Roles, 0) + + // invalid centID format + payload := documentpb.AccessTokenParams{ + // invalid grantee format + Grantee: "randomCentID", + DocumentIdentifier: "randomDocID", + } + _, err = m.AddAccessToken(ctx, payload) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to construct access token: malformed address provided") + // invalid centID length + invalidCentID := utils.RandomSlice(25) + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(invalidCentID), + DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), + } + _, err = m.AddAccessToken(ctx, payload) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to construct access token: malformed address provided") + // invalid docID length + id, err := account.GetIdentityID() + assert.NoError(t, err) + invalidDocID := utils.RandomSlice(33) + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(id), + DocumentIdentifier: hexutil.Encode(invalidDocID), + } + + _, err = m.AddAccessToken(ctx, payload) + assert.Contains(t, err.Error(), "failed to construct access token: invalid identifier length") + // valid + payload = documentpb.AccessTokenParams{ + Grantee: hexutil.Encode(id), + DocumentIdentifier: hexutil.Encode(m.Document.DocumentIdentifier), + } + + ncd, err := m.AddAccessToken(ctx, payload) + assert.NoError(t, err) + assert.Len(t, ncd.Document.ReadRules, 1) + assert.Equal(t, ncd.Document.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ) + assert.Len(t, ncd.Document.Roles, 1) +} diff --git a/documents/registry_test.go b/documents/registry_test.go index c1c361279..e31ea54a4 100644 --- a/documents/registry_test.go +++ b/documents/registry_test.go @@ -5,6 +5,7 @@ package documents_test import ( "testing" + "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" @@ -13,13 +14,11 @@ import ( func TestRegistry_Register_LocateService_successful(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - dm, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - documentType := dm.Document.EmbeddedData.TypeUrl - err = registry.Register(documentType, a) - assert.Nil(t, err, "register didn't work with unused id") + docType := documenttypes.InvoiceDataTypeUrl + err := registry.Register(docType, a) + assert.Nil(t, err) - b, err := registry.LocateService(documentType) + b, err := registry.LocateService(docType) assert.Nil(t, err, "service hasn't been registered properly") assert.Equal(t, a, b, "locateService should return the same service ") } @@ -27,15 +26,11 @@ func TestRegistry_Register_LocateService_successful(t *testing.T) { func TestRegistry_Register_invalidId(t *testing.T) { registry := documents.NewServiceRegistry() a := &testingdocuments.MockService{} - dm, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - cd := dm.Document - cd.EmbeddedData.TypeUrl = "testID_1" - - err = registry.Register(cd.EmbeddedData.TypeUrl, a) + docType := documenttypes.InvoiceDataTypeUrl + err := registry.Register(docType, a) assert.Nil(t, err, "register didn't work with unused id") - err = registry.Register(cd.EmbeddedData.TypeUrl, a) + err = registry.Register(docType, a) assert.Error(t, err, "register shouldn't work with same id") err = registry.Register("testId", a) @@ -44,11 +39,6 @@ func TestRegistry_Register_invalidId(t *testing.T) { func TestRegistry_LocateService_invalid(t *testing.T) { registry := documents.NewServiceRegistry() - dm, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - cd := dm.Document - cd.EmbeddedData.TypeUrl = "testID_2" - documentType := cd.EmbeddedData.TypeUrl - _, err = registry.LocateService(documentType) + _, err := registry.LocateService(documenttypes.InvoiceDataTypeUrl) assert.Error(t, err, "should throw an error because no services is registered") } diff --git a/documents/service.go b/documents/service.go index 3735f5c4a..c6bbc73d0 100644 --- a/documents/service.go +++ b/documents/service.go @@ -42,8 +42,8 @@ type Service interface { // GetVersion reads a document from the database GetVersion(ctx context.Context, documentID []byte, version []byte) (Model, error) - // DeriveFromCoreDocumentModel derives a model given the core document model - DeriveFromCoreDocumentModel(dm *CoreDocumentModel) (Model, error) + // DeriveFromCoreDocument derives a model given the core document. + DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (Model, error) // CreateProofs creates proofs for the latest version document given the fields CreateProofs(ctx context.Context, documentID []byte, fields []string) (*DocumentProof, error) @@ -90,33 +90,18 @@ func DefaultService( } } -func getIDs(model Model) ([]byte, []byte, error) { - dm, err := model.PackCoreDocument() - if err != nil { - return nil, nil, err +func (s service) searchVersion(ctx context.Context, m Model) (Model, error) { + id, next := m.ID(), m.NextVersion() + if !s.Exists(ctx, next) { + // at the latest locally known version + return m, nil } - cd := dm.Document - - return cd.DocumentIdentifier, cd.NextVersion, nil - -} -func (s service) searchVersion(ctx context.Context, m Model) (Model, error) { - id, next, err := getIDs(m) + m, err := s.getVersion(ctx, id, next) if err != nil { return nil, err } - - if s.Exists(ctx, next) { - nm, err := s.getVersion(ctx, id, next) - if err != nil { - - return nil, err - } - return s.searchVersion(ctx, nm) - } - - return m, nil + return s.searchVersion(ctx, m) } @@ -145,17 +130,15 @@ func (s service) createProofs(model Model, fields []string) (*DocumentProof, err if err := PostAnchoredValidator(s.idService, s.anchorRepository).Validate(nil, model); err != nil { return nil, errors.NewTypedError(ErrDocumentInvalid, err) } + proofs, err := model.CreateProofs(fields) if err != nil { return nil, errors.NewTypedError(ErrDocumentProof, err) } - coreDocModel, err := model.PackCoreDocument() - if err != nil { - return nil, errors.New("creating proofs failed while packing core document") - } + return &DocumentProof{ - DocumentID: coreDocModel.Document.DocumentIdentifier, - VersionID: coreDocModel.Document.CurrentVersion, + DocumentID: model.ID(), + VersionID: model.CurrentVersion(), FieldProofs: proofs, }, nil @@ -179,41 +162,36 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co return nil, errors.NewTypedError(ErrDocumentInvalid, err) } - docModel, err := model.PackCoreDocument() + sr, err := model.CalculateSigningRoot() if err != nil { - return nil, errors.NewTypedError(ErrDocumentPackingCoreDocument, err) + return nil, errors.New("failed to get signing root: %v", err) } - doc := docModel.Document - srvLog.Infof("coredoc received %x with signing root %x", doc.DocumentIdentifier, doc.SigningRoot) - + srvLog.Infof("document received %x with signing root %x", model.ID(), sr) idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] if !ok { return nil, errors.NewTypedError(ErrDocumentSigning, errors.New("missing signing key")) } - sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, doc.SigningRoot) - doc.Signatures = append(doc.Signatures, sig) - err = model.UnpackCoreDocument(docModel) - if err != nil { - return nil, errors.NewTypedError(ErrDocumentUnPackingCoreDocument, err) - } - tenantID := idConf.ID[:] + sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, sr) + model.AppendSignatures(sig) + tenantID := idConf.ID[:] // Logic for receiving version n (n > 1) of the document for the first time - if !s.repo.Exists(tenantID, doc.DocumentIdentifier) && !utils.IsSameByteSlice(doc.DocumentIdentifier, doc.CurrentVersion) { - err = s.repo.Create(tenantID, doc.DocumentIdentifier, model) + // TODO(ved): we should not save the new model with old identifier. We should sync from the peer. + if !s.repo.Exists(tenantID, model.ID()) && !utils.IsSameByteSlice(model.ID(), model.CurrentVersion()) { + err = s.repo.Create(tenantID, model.ID(), model) if err != nil { return nil, errors.NewTypedError(ErrDocumentPersistence, err) } } - err = s.repo.Create(tenantID, doc.CurrentVersion, model) + err = s.repo.Create(tenantID, model.CurrentVersion(), model) if err != nil { return nil, errors.NewTypedError(ErrDocumentPersistence, err) } - srvLog.Infof("signed coredoc %x with version %x", doc.DocumentIdentifier, doc.CurrentVersion) + srvLog.Infof("signed document %x with version %x", model.ID(), model.CurrentVersion()) return sig, nil } @@ -223,23 +201,11 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende return ErrDocumentConfigAccountID } - if model == nil { - return errors.New("no model given") - } - if err := PostAnchoredValidator(s.idService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(ErrDocumentInvalid, err) } - docModel, err := model.PackCoreDocument() - if err != nil { - return errors.NewTypedError(ErrDocumentPackingCoreDocument, err) - } - if docModel.Document == nil { - return errors.NewTypedError(ErrDocumentPackingCoreDocument, err) - } - doc := docModel.Document - err = s.repo.Update(idConf.ID[:], doc.CurrentVersion, model) + err = s.repo.Update(idConf.ID[:], model.CurrentVersion(), model) if err != nil { return errors.NewTypedError(ErrDocumentPersistence, err) } @@ -251,8 +217,8 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende FromId: hexutil.Encode(senderID), ToId: idConf.ID.String(), Recorded: ts, - DocumentType: doc.EmbeddedData.TypeUrl, - DocumentId: hexutil.Encode(doc.DocumentIdentifier), + DocumentType: model.DocumentType(), + DocumentId: hexutil.Encode(model.ID()), } // Async until we add queuing @@ -279,31 +245,24 @@ func (s service) getVersion(ctx context.Context, documentID, version []byte) (Mo return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) } - dm, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - cd := dm.Document - if !bytes.Equal(cd.DocumentIdentifier, documentID) { + if !bytes.Equal(model.ID(), documentID) { return nil, errors.NewTypedError(ErrDocumentVersionNotFound, errors.New("version is not valid for this identifier")) } + return model, nil } -func (s service) DeriveFromCoreDocumentModel(dm *CoreDocumentModel) (Model, error) { - if dm == nil { - return nil, errors.New("no core doc model passed") - } - if dm.Document == nil || dm.Document.EmbeddedData == nil { - return nil, errors.New("core document is nil") +func (s service) DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (Model, error) { + if cd.EmbeddedData == nil { + return nil, errors.New("core document embed data is nil") } - srv, err := s.registry.LocateService(dm.Document.EmbeddedData.TypeUrl) + srv, err := s.registry.LocateService(cd.EmbeddedData.TypeUrl) if err != nil { return nil, err } - return srv.DeriveFromCoreDocumentModel(dm) + return srv.DeriveFromCoreDocument(cd) } func (s service) Create(ctx context.Context, model Model) (Model, transactions.TxID, chan bool, error) { @@ -325,11 +284,5 @@ func (s service) Update(ctx context.Context, model Model) (Model, transactions.T } func (s service) getService(model Model) (Service, error) { - dm, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - cd := dm.Document - - return s.registry.LocateService(cd.EmbeddedData.TypeUrl) + return s.registry.LocateService(model.DocumentType()) } diff --git a/documents/tree.go b/documents/tree.go new file mode 100644 index 000000000..c4f839d6b --- /dev/null +++ b/documents/tree.go @@ -0,0 +1,69 @@ +package documents + +import ( + "crypto/sha256" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/gogo/protobuf/proto" +) + +// NewDefaultTree returns a DocumentTree with default opts +func NewDefaultTree(salts *proofs.Salts) *proofs.DocumentTree { + return NewDefaultTreeWithPrefix(salts, "", nil) +} + +// NewDefaultTreeWithPrefix returns a DocumentTree with default opts passing a prefix to the tree leaves +func NewDefaultTreeWithPrefix(salts *proofs.Salts, prefix string, compactPrefix []byte) *proofs.DocumentTree { + var prop proofs.Property + if prefix != "" { + prop = NewLeafProperty(prefix, compactPrefix) + } + + t := proofs.NewDocumentTree(proofs.TreeOptions{CompactProperties: true, EnableHashSorting: true, Hash: sha256.New(), ParentPrefix: prop, Salts: salts}) + return &t +} + +// NewLeafProperty returns a proof property with the literal and the compact +func NewLeafProperty(literal string, compact []byte) proofs.Property { + return proofs.NewProperty(literal, compact...) +} + +// GenerateNewSalts generates salts for new Document +func GenerateNewSalts(document proto.Message, prefix string, compactPrefix []byte) (*proofs.Salts, error) { + docSalts := new(proofs.Salts) + t := NewDefaultTreeWithPrefix(docSalts, prefix, compactPrefix) + err := t.AddLeavesFromDocument(document) + if err != nil { + return nil, err + } + return docSalts, nil +} + +// ConvertToProtoSalts converts proofSalts into protocolSalts +func ConvertToProtoSalts(proofSalts *proofs.Salts) []*coredocumentpb.DocumentSalt { + if proofSalts == nil { + return nil + } + + protoSalts := make([]*coredocumentpb.DocumentSalt, len(*proofSalts)) + for i, pSalt := range *proofSalts { + protoSalts[i] = &coredocumentpb.DocumentSalt{Value: pSalt.Value, Compact: pSalt.Compact} + } + + return protoSalts +} + +// ConvertToProofSalts converts protocolSalts into proofSalts +func ConvertToProofSalts(protoSalts []*coredocumentpb.DocumentSalt) *proofs.Salts { + if protoSalts == nil { + return nil + } + + proofSalts := make(proofs.Salts, len(protoSalts)) + for i, pSalt := range protoSalts { + proofSalts[i] = proofs.Salt{Value: pSalt.Value, Compact: pSalt.Compact} + } + + return &proofSalts +} diff --git a/documents/tree_test.go b/documents/tree_test.go new file mode 100644 index 000000000..9c321cc08 --- /dev/null +++ b/documents/tree_test.go @@ -0,0 +1,32 @@ +// +build unit + +package documents + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConvertToProofAndProtoSalts(t *testing.T) { + cd := newCoreDocument() + salts, err := GenerateNewSalts(&cd.Document, "", nil) + assert.NoError(t, err) + assert.NotNil(t, salts) + + nilProto := ConvertToProtoSalts(nil) + assert.Nil(t, nilProto) + + nilProof := ConvertToProofSalts(nil) + assert.Nil(t, nilProof) + + protoSalts := ConvertToProtoSalts(salts) + assert.NotNil(t, protoSalts) + assert.Len(t, protoSalts, len(*salts)) + assert.Equal(t, protoSalts[0].Value, (*salts)[0].Value) + + cSalts := ConvertToProofSalts(protoSalts) + assert.NotNil(t, cSalts) + assert.Len(t, *cSalts, len(*salts)) + assert.Equal(t, (*cSalts)[0].Value, (*salts)[0].Value) +} diff --git a/documents/validator.go b/documents/validator.go index 2f150111c..38c69a04e 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -1,12 +1,7 @@ package documents import ( - "fmt" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/centerrors" "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" @@ -56,66 +51,52 @@ func UpdateVersionValidator() Validator { return errors.New("need both the old and new model") } - oldDM, err := old.PackCoreDocument() - if err != nil { - return errors.New("failed to fetch old core document: %v", err) - } - - newDM, err := new.PackCoreDocument() + dr, err := old.CalculateDocumentRoot() if err != nil { - return errors.New("failed to fetch new core document: %v", err) + return errors.New("failed to get previous version document root: %v", err) } - if oldDM.Document == nil { - return errors.New("coredoc is nil") - } - if newDM.Document == nil { - return errors.New("coredoc is nil") - } - oldCD := oldDM.Document - newCD := newDM.Document - checks := []struct { name string a, b []byte }{ { name: "cd_document_identifier", - a: oldCD.DocumentIdentifier, - b: newCD.DocumentIdentifier, + a: old.ID(), + b: new.ID(), }, { name: "cd_previous_version", - a: oldCD.CurrentVersion, - b: newCD.PreviousVersion, + a: old.CurrentVersion(), + b: new.PreviousVersion(), }, { name: "cd_current_version", - a: oldCD.NextVersion, - b: newCD.CurrentVersion, + a: old.NextVersion(), + b: new.CurrentVersion(), }, { - name: "cd_previous_version", - a: oldCD.DocumentRoot, - b: newCD.PreviousRoot, + name: "cd_document_root", + a: dr, + b: new.PreviousDocumentRoot(), }, } for _, c := range checks { if !utils.CheckMultiple32BytesFilled(c.a, c.b) { - err = errors.AppendError(err, NewError(c.name, "missing identifiers")) + err = errors.AppendError(err, errors.New("missing identifiers")) continue } if !utils.IsSameByteSlice(c.a, c.b) { - err = errors.AppendError(err, NewError(c.name, "mismatched")) + err = errors.AppendError(err, errors.New("%s: mismatch", c.name)) } } - if utils.IsEmptyByteSlice(newCD.NextVersion) { - err = errors.AppendError(err, NewError("cd_next_version", centerrors.RequiredField)) + if utils.IsEmptyByteSlice(new.NextVersion()) { + err = errors.AppendError(err, errors.New("cd_next_version: not set")) } return err @@ -124,83 +105,41 @@ func UpdateVersionValidator() Validator { // baseValidator validates the core document basic fields like identifier, versions, and salts func baseValidator() Validator { - return ValidatorFunc(func(_, model Model) error { - dm, err := model.PackCoreDocument() - if err != nil { - return err - } - if dm.Document == nil { - return errors.New("nil document") + return ValidatorFunc(func(_, model Model) (err error) { + if utils.IsEmptyByteSlice(model.ID()) { + err = errors.AppendError(err, errors.New("document identifier not set")) } - cd := dm.Document - if utils.IsEmptyByteSlice(cd.DocumentIdentifier) { - err = errors.AppendError(err, NewError("cd_identifier", centerrors.RequiredField)) + if utils.IsEmptyByteSlice(model.CurrentVersion()) { + err = errors.AppendError(err, errors.New("current version not set")) } - if utils.IsEmptyByteSlice(cd.CurrentVersion) { - err = errors.AppendError(err, NewError("cd_current_version", centerrors.RequiredField)) - } - - if utils.IsEmptyByteSlice(cd.NextVersion) { - err = errors.AppendError(err, NewError("cd_next_version", centerrors.RequiredField)) + if utils.IsEmptyByteSlice(model.NextVersion()) { + err = errors.AppendError(err, errors.New("next version not set")) } // double check the identifiers isSameBytes := utils.IsSameByteSlice - // Problem (re-using an old identifier for NextVersion): CurrentVersion or DocumentIdentifier same as NextVersion - if isSameBytes(cd.NextVersion, cd.DocumentIdentifier) || - isSameBytes(cd.NextVersion, cd.CurrentVersion) { - err = errors.AppendError(err, NewError("cd_overall", centerrors.IdentifierReUsed)) - } - - // lets not do verbose check like earlier since these will be - // generated by us mostly - salts := cd.CoredocumentSalts - if salts == nil || !checkSaltsFormat(salts) { - err = errors.AppendError(err, NewError("cd_salts", centerrors.RequiredField)) + if isSameBytes(model.NextVersion(), model.ID()) || + isSameBytes(model.NextVersion(), model.CurrentVersion()) { + err = errors.AppendError(err, errors.New("identifiers re-used")) } return err }) } -func checkSaltsFormat(salts []*coredocumentpb.DocumentSalt) bool { - for _, s := range salts { - if !utils.Check32BytesFilled(s.Value) { - return false - } - } - return true -} - // signingRootValidator checks the existence of signing root -// recalculates the signing root and compares with existing one func signingRootValidator() Validator { return ValidatorFunc(func(_, model Model) error { - dm, err := model.PackCoreDocument() - if err != nil { - return err - } - - cd := dm.Document - if utils.IsEmptyByteSlice(cd.SigningRoot) { - return errors.New("signing root missing") - } - - dataRoot, err := model.CalculateDataRoot() + sr, err := model.CalculateSigningRoot() if err != nil { - return err + return errors.New("failed to get signing root: %v", err) } - tree, err := dm.GetDocumentSigningTree(dataRoot) - if err != nil { - return errors.New("failed to calculate signing root: %v", err) - } - - if !utils.IsSameByteSlice(cd.SigningRoot, tree.RootHash()) { - return errors.New("signing root mismatch") + if len(sr) != idSize { + return errors.New("signing root is invalid") } return nil @@ -211,23 +150,13 @@ func signingRootValidator() Validator { // recalculates the document root and compares with existing one func documentRootValidator() Validator { return ValidatorFunc(func(_, model Model) error { - dm, err := model.PackCoreDocument() + dr, err := model.CalculateDocumentRoot() if err != nil { - return err - } - - cd := dm.Document - if utils.IsEmptyByteSlice(cd.DocumentRoot) { - return errors.New("document root missing") - } - - tree, err := dm.GetDocumentRootTree() - if err != nil { - return errors.New("failed to calculate document root: %v", err) + return errors.New("failed to get document root: %v", err) } - if !utils.IsSameByteSlice(cd.DocumentRoot, tree.RootHash()) { - return errors.New("document root mismatch") + if len(dr) != idSize { + return errors.New("document root is invalid") } return nil @@ -238,30 +167,30 @@ func documentRootValidator() Validator { // re-calculates the signature and compares with existing one // assumes signing_root is already generated and verified // Note: this needs to used only before document is sent for signatures from the collaborators -func readyForSignaturesValidator(didBytes, priv, pub []byte) Validator { +func readyForSignaturesValidator(id, priv, pub []byte) Validator { return ValidatorFunc(func(_, model Model) error { - dm, err := model.PackCoreDocument() + sr, err := model.CalculateSigningRoot() if err != nil { - return err + return errors.New("failed to generate signing root: %v", err) } - cd := dm.Document - if len(cd.Signatures) != 1 { + signatures := model.Signatures() + if len(signatures) != 1 { return errors.New("expecting only one signature") } - s := crypto.Sign(didBytes, priv, pub, cd.SigningRoot) - sh := cd.Signatures[0] + s := crypto.Sign(id, priv, pub, sr) + sh := signatures[0] if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { - err = errors.AppendError(err, NewError("cd_entity_id", "entity ID mismatch")) + err = errors.AppendError(err, errors.New("entity ID mismatch")) } if !utils.IsSameByteSlice(s.PublicKey, sh.PublicKey) { - err = errors.AppendError(err, NewError("cd_public_key", "public key mismatch")) + err = errors.AppendError(err, errors.New("public key mismatch")) } if !utils.IsSameByteSlice(s.Signature, sh.Signature) { - err = errors.AppendError(err, NewError("cd_signature", "signature mismatch")) + err = errors.AppendError(err, errors.New("signature mismatch")) } return err @@ -274,22 +203,21 @@ func readyForSignaturesValidator(didBytes, priv, pub []byte) Validator { // Note: this will break the current flow where we proceed to anchor even signatures verification fails func signaturesValidator(idService identity.ServiceDID) Validator { return ValidatorFunc(func(_, model Model) error { - dm, err := model.PackCoreDocument() + sr, err := model.CalculateSigningRoot() if err != nil { - return err + return errors.New("failed to get signing root: %v", err) } - cd := dm.Document - if len(cd.Signatures) < 1 { + signatures := model.Signatures() + if len(signatures) < 1 { return errors.New("atleast one signature expected") } - for _, sig := range cd.Signatures { - erri := idService.ValidateSignature(sig, cd.SigningRoot) - if erri != nil { + for _, sig := range signatures { + if erri := idService.ValidateSignature(&sig, sr); erri != nil { err = errors.AppendError( - erri, - errors.New(fmt.Sprintf("signature_%s", hexutil.Encode(sig.EntityId)), fmt.Sprintf("signature verification failed: %v", err))) + err, + errors.New("signature_%s verification failed: %v", hexutil.Encode(sig.EntityId), erri)) } } return err @@ -299,19 +227,18 @@ func signaturesValidator(idService identity.ServiceDID) Validator { // anchoredValidator checks if the document root matches the one on chain with specific anchorID // assumes document root is generated and verified func anchoredValidator(repo anchors.AnchorRepository) Validator { - return ValidatorFunc(func(_, new Model) error { - dm, err := new.PackCoreDocument() + return ValidatorFunc(func(_, model Model) error { + anchorID, err := anchors.ToAnchorID(model.CurrentVersion()) if err != nil { - return errors.New("failed to get core document: %v", err) + return errors.New("failed to get anchorID: %v", err) } - cd := dm.Document - anchorID, err := anchors.ToAnchorID(cd.CurrentVersion) + dr, err := model.CalculateDocumentRoot() if err != nil { - return errors.New("failed to get anchorID: %v", err) + return errors.New("failed to get document root: %v", err) } - docRoot, err := anchors.ToDocumentRoot(cd.DocumentRoot) + docRoot, err := anchors.ToDocumentRoot(dr) if err != nil { return errors.New("failed to get document root: %v", err) } @@ -367,11 +294,11 @@ func PostAnchoredValidator(idService identity.ServiceDID, repo anchors.AnchorRep // signingRootValidator // readyForSignaturesValidator // should be called after sender signing the document and before requesting the document -func PreSignatureRequestValidator(centIDBytes, priv, pub []byte) ValidatorGroup { +func PreSignatureRequestValidator(id, priv, pub []byte) ValidatorGroup { return ValidatorGroup{ baseValidator(), signingRootValidator(), - readyForSignaturesValidator(centIDBytes, priv, pub), + readyForSignaturesValidator(id, priv, pub), } } diff --git a/documents/validator_test.go b/documents/validator_test.go index b69bd6e41..7bfdfc3a1 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -5,18 +5,14 @@ package documents import ( "testing" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" - testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" - "github.com/golang/protobuf/ptypes/any" - "github.com/stretchr/testify/mock" - - "github.com/centrifuge/go-centrifuge/errors" "github.com/stretchr/testify/assert" ) @@ -131,76 +127,66 @@ func TestUpdateVersionValidator(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "need both the old and new model") - // old model pack core doc fail - old := mockModel{} - newM := mockModel{} - old.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = uvv.Validate(old, newM) - old.AssertExpectations(t) + old := new(mockModel) + old.On("CalculateDocumentRoot").Return(nil, errors.New("errors")).Once() + err = uvv.Validate(old, new(mockModel)) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch old core document") - - // newM model pack core doc fail - oldDM := NewCoreDocModel() - oldCD := oldDM.Document - oldCD.DocumentRoot = utils.RandomSlice(32) - old.On("PackCoreDocument").Return(oldDM, nil).Once() - newM.On("PackCoreDocument").Return(nil, errors.New("error")).Once() - err = uvv.Validate(old, newM) old.AssertExpectations(t) - newM.AssertExpectations(t) + + old = new(mockModel) + old.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil).Once() + old.On("ID").Return(nil).Once() + old.On("CurrentVersion").Return(nil).Once() + old.On("NextVersion").Return(nil).Once() + nm := new(mockModel) + nm.On("ID").Return(utils.RandomSlice(32)).Once() + nm.On("CurrentVersion").Return(utils.RandomSlice(32)).Once() + nm.On("NextVersion").Return(utils.RandomSlice(32)).Once() + nm.On("PreviousVersion").Return(utils.RandomSlice(32)).Once() + nm.On("PreviousDocumentRoot").Return(utils.RandomSlice(32)).Once() + err = uvv.Validate(old, nm) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to fetch new core document") - - // mismatched identifiers - newDM := NewCoreDocModel() - newCD := newDM.Document - newCD.DocumentRoot = utils.RandomSlice(32) - newCD.NextVersion = nil - old.On("PackCoreDocument").Return(oldDM, nil).Once() - newM.On("PackCoreDocument").Return(newDM, nil).Once() - err = uvv.Validate(old, newM) old.AssertExpectations(t) - newM.AssertExpectations(t) - assert.Error(t, err) - assert.Equal(t, 5, errors.Len(err)) - - // success - newDM, err = oldDM.PrepareNewVersion(nil) - assert.Nil(t, err) - old.On("PackCoreDocument").Return(oldDM, nil).Once() - newM.On("PackCoreDocument").Return(newDM, nil).Once() - err = uvv.Validate(old, newM) + nm.AssertExpectations(t) + + old = new(mockModel) + dpr := utils.RandomSlice(32) + pv := utils.RandomSlice(32) + di := utils.RandomSlice(32) + cv := utils.RandomSlice(32) + nv := utils.RandomSlice(32) + old.On("CalculateDocumentRoot").Return(dpr, nil).Once() + old.On("ID").Return(di).Once() + old.On("CurrentVersion").Return(pv).Once() + old.On("NextVersion").Return(cv).Once() + nm = new(mockModel) + nm.On("ID").Return(di).Once() + nm.On("CurrentVersion").Return(cv).Once() + nm.On("NextVersion").Return(nv).Once() + nm.On("PreviousVersion").Return(pv).Once() + nm.On("PreviousDocumentRoot").Return(dpr).Once() + err = uvv.Validate(old, nm) + assert.NoError(t, err) old.AssertExpectations(t) - newM.AssertExpectations(t) - assert.Nil(t, err) + nm.AssertExpectations(t) + } func TestValidator_baseValidator(t *testing.T) { bv := baseValidator() - // fail getCoreDocument - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + model := new(mockModel) + model.On("ID").Return(nil).Times(2) + model.On("CurrentVersion").Return(nil).Times(2) + model.On("NextVersion").Return(nil).Times(3) err := bv.Validate(nil, model) - model.AssertExpectations(t) - assert.Error(t, err) - - // failed validator - model = mockModel{} - dm := NewCoreDocModel() - cd := dm.Document - cd.DocumentRoot = utils.RandomSlice(32) - model.On("PackCoreDocument").Return(dm, nil).Once() - err = bv.Validate(nil, model) assert.Error(t, err) - assert.Equal(t, "cd_salts : Required field", errors.GetErrs(err)[0].Error()) // success - model = mockModel{} - cd.DataRoot = utils.RandomSlice(32) - dm.setCoreDocumentSalts() - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("ID").Return(utils.RandomSlice(32)).Times(2) + model.On("CurrentVersion").Return(utils.RandomSlice(32)).Times(2) + model.On("NextVersion").Return(utils.RandomSlice(32)).Times(3) err = bv.Validate(nil, model) assert.Nil(t, err) } @@ -208,89 +194,51 @@ func TestValidator_baseValidator(t *testing.T) { func TestValidator_signingRootValidator(t *testing.T) { sv := signingRootValidator() - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + // failed to get signing root + model := new(mockModel) + model.On("CalculateSigningRoot").Return(nil, errors.New("error")).Once() err := sv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) - - // missing signing_root - dm := NewCoreDocModel() - cd := dm.Document - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - err = sv.Validate(nil, model) model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "signing root missing") - // mismatch signing roots - cd.SigningRoot = utils.RandomSlice(32) - cd.EmbeddedData = &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: []byte{}, - } - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + // invalid signing root + model = new(mockModel) + model.On("CalculateSigningRoot").Return(utils.RandomSlice(30), nil).Once() err = sv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "signing root mismatch") + model.AssertExpectations(t) // success - tree, err := dm.GetDocumentSigningTree(cd.DataRoot) - assert.Nil(t, err) - cd.SigningRoot = tree.RootHash() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - model.On("CalculateDataRoot").Return(cd.DataRoot, nil) + model = new(mockModel) + model.On("CalculateSigningRoot").Return(utils.RandomSlice(32), nil).Once() err = sv.Validate(nil, model) + assert.NoError(t, err) model.AssertExpectations(t) - assert.Nil(t, err) } func TestValidator_documentRootValidator(t *testing.T) { dv := documentRootValidator() - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + // failed to get document root + model := new(mockModel) + model.On("CalculateDocumentRoot").Return(nil, errors.New("error")).Once() err := dv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) - - // missing document root - dm := NewCoreDocModel() - cd := dm.Document - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - err = dv.Validate(nil, model) model.AssertExpectations(t) - assert.Error(t, err) - assert.Contains(t, err.Error(), "document root missing") - // mismatch signing roots - cd.DocumentRoot = utils.RandomSlice(32) - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + // invalid signing root + model = new(mockModel) + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(30), nil).Once() err = dv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "document root mismatch") + model.AssertExpectations(t) // success - tree, err := dm.GetDocumentRootTree() - assert.Nil(t, err) - cd.DocumentRoot = tree.RootHash() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil).Once() err = dv.Validate(nil, model) + assert.NoError(t, err) model.AssertExpectations(t) - assert.Nil(t, err) } func TestValidator_selfSignatureValidator(t *testing.T) { @@ -301,94 +249,99 @@ func TestValidator_selfSignatureValidator(t *testing.T) { assert.NoError(t, err) rfsv := readyForSignaturesValidator(accID, keys[identity.KeyPurposeSigning].PrivateKey, keys[identity.KeyPurposeSigning].PublicKey) - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + // fail to get signing root + model := new(mockModel) + model.On("CalculateSigningRoot").Return(nil, errors.New("error")).Once() err = rfsv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) + model.AssertExpectations(t) // signature length mismatch - dm := NewCoreDocModel() - cd := dm.Document - cd.DocumentRoot = utils.RandomSlice(32) - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + sr := utils.RandomSlice(32) + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() err = rfsv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) + model.AssertExpectations(t) assert.Contains(t, err.Error(), "expecting only one signature") // mismatch - cd.SigningRoot = utils.RandomSlice(32) s := &coredocumentpb.Signature{ Signature: utils.RandomSlice(32), EntityId: utils.RandomSlice(6), PublicKey: utils.RandomSlice(32), } - cd.Signatures = append(cd.Signatures, s) - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() + model.sigs = append(model.sigs, s) err = rfsv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Equal(t, 3, errors.Len(err)) // success - cd.SigningRoot = utils.RandomSlice(32) - - signature, err := account.SignMsg(cd.SigningRoot) + c, err := identity.GetIdentityConfig(cfg) assert.Nil(t, err) - - cd.Signatures = []*coredocumentpb.Signature{signature} - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + s = identity.Sign(c, identity.KeyPurposeSigning, sr) + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() + model.sigs = append(model.sigs, s) err = rfsv.Validate(nil, model) model.AssertExpectations(t) - assert.Nil(t, err) + assert.NoError(t, err) } func TestValidator_signatureValidator(t *testing.T) { srv := &testingcommons.MockIdentityService{} ssv := signaturesValidator(srv) - // fail getCoreDoc - model := mockModel{} - model.On("PackCoreDocument").Return(nil, errors.New("err")).Once() + // fail to get signing root + model := new(mockModel) + model.On("CalculateSigningRoot").Return(nil, errors.New("error")).Once() err := ssv.Validate(nil, model) - model.AssertExpectations(t) assert.Error(t, err) + model.AssertExpectations(t) // signature length mismatch - dm := NewCoreDocModel() - cd := dm.Document - dm.setCoreDocumentSalts() - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + sr := utils.RandomSlice(32) + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() err = ssv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "atleast one signature expected") // failed validation - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("fail")).Once() - s := &coredocumentpb.Signature{EntityId: utils.RandomSlice(7)} - cd.Signatures = append(cd.Signatures, s) + s := &coredocumentpb.Signature{ + Signature: utils.RandomSlice(32), + EntityId: utils.RandomSlice(6), + PublicKey: utils.RandomSlice(32), + } + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() + model.sigs = append(model.sigs, s) + srv = new(testingcommons.MockIdentityService) + srv.On("ValidateSignature", s, sr).Return(errors.New("error")).Once() + ssv = signaturesValidator(srv) err = ssv.Validate(nil, model) model.AssertExpectations(t) + srv.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "signature verification failed") + assert.Contains(t, err.Error(), "verification failed") // success - model = mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() - srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() - cd.SigningRoot = utils.RandomSlice(32) - cd.Signatures = []*coredocumentpb.Signature{{}} - + model = new(mockModel) + model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("Signatures").Return().Once() + model.sigs = append(model.sigs, s) + srv = new(testingcommons.MockIdentityService) + srv.On("ValidateSignature", s, sr).Return(nil).Once() + ssv = signaturesValidator(srv) err = ssv.Validate(nil, model) model.AssertExpectations(t) srv.AssertExpectations(t) @@ -404,20 +357,26 @@ func TestValidator_anchoredValidator(t *testing.T) { av := anchoredValidator(mockRepo{}) // failed anchorID - model := &mockModel{} - dm := NewCoreDocModel() - cd := dm.Document - cd.CurrentVersion = utils.RandomSlice(30) - model.On("PackCoreDocument").Return(dm, nil).Once() + model := new(mockModel) + model.On("CurrentVersion").Return(nil).Once() err := av.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get anchorID") // failed docRoot - model = &mockModel{} - cd.CurrentVersion = utils.RandomSlice(32) - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CurrentVersion").Return(utils.RandomSlice(32)).Once() + model.On("CalculateDocumentRoot").Return(nil, errors.New("error")).Once() + err = av.Validate(nil, model) + model.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get document root") + + // invalid doc root + model = new(mockModel) + model.On("CurrentVersion").Return(utils.RandomSlice(32)).Once() + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(30), nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) @@ -428,11 +387,10 @@ func TestValidator_anchoredValidator(t *testing.T) { assert.Nil(t, err) r := &mockRepo{} av = anchoredValidator(r) - cd.CurrentVersion = anchorID[:] r.On("GetDocumentRootOf", anchorID).Return(nil, errors.New("error")).Once() - cd.DocumentRoot = utils.RandomSlice(32) - model = &mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CurrentVersion").Return(anchorID[:]).Once() + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) @@ -444,9 +402,9 @@ func TestValidator_anchoredValidator(t *testing.T) { r = &mockRepo{} av = anchoredValidator(r) r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - cd.DocumentRoot = utils.RandomSlice(32) - model = &mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CurrentVersion").Return(anchorID[:]).Once() + model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) @@ -457,128 +415,15 @@ func TestValidator_anchoredValidator(t *testing.T) { r = &mockRepo{} av = anchoredValidator(r) r.On("GetDocumentRootOf", anchorID).Return(docRoot, nil).Once() - cd.DocumentRoot = docRoot[:] - model = &mockModel{} - model.On("PackCoreDocument").Return(dm, nil).Once() + model = new(mockModel) + model.On("CurrentVersion").Return(anchorID[:]).Once() + model.On("CalculateDocumentRoot").Return(docRoot[:], nil).Once() err = av.Validate(nil, model) model.AssertExpectations(t) r.AssertExpectations(t) assert.Nil(t, err) } -var ( - id1 = utils.RandomSlice(32) - id2 = utils.RandomSlice(32) - id3 = utils.RandomSlice(32) - id4 = utils.RandomSlice(32) - id5 = utils.RandomSlice(32) -) - -func TestValidate_baseValidator(t *testing.T) { - tests := []struct { - doc *coredocumentpb.CoreDocument - key string - }{ - // empty salts in document - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - DataRoot: id5, - }, - key: "[cd_salts : Required field]", - }, - - // salts wrong length previous root - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - CoredocumentSalts: []*coredocumentpb.DocumentSalt{ - {Value: id1}, - {Value: id2}, - {Value: id3}, - {Value: id5[5:]}, - }, - }, - key: "[cd_salts : Required field]", - }, - - // repeated identifiers - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id3, - DataRoot: id5, - CoredocumentSalts: []*coredocumentpb.DocumentSalt{ - {Value: id1}, - {Value: id2}, - {Value: id3}, - {Value: id5}, - }, - }, - key: "[cd_overall : Identifier re-used]", - }, - - // repeated identifiers - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id2, - DataRoot: id5, - CoredocumentSalts: []*coredocumentpb.DocumentSalt{ - {Value: id1}, - {Value: id2}, - {Value: id3}, - {Value: id5}, - }, - }, - key: "[cd_overall : Identifier re-used]", - }, - - // All okay - { - doc: &coredocumentpb.CoreDocument{ - DocumentRoot: id1, - DocumentIdentifier: id2, - CurrentVersion: id3, - NextVersion: id4, - DataRoot: id5, - CoredocumentSalts: []*coredocumentpb.DocumentSalt{ - {Value: id1}, - {Value: id2}, - {Value: id3}, - {Value: id5}, - }, - }, - }, - } - - baseValidator := baseValidator() - - for _, c := range tests { - model := mockModel{} - model.On("PackCoreDocument", mock.Anything).Return(&CoreDocumentModel{c.doc, nil}, nil).Once() - - err := baseValidator.Validate(nil, &model) - if c.key == "" { - assert.Nil(t, err) - continue - } - - assert.Equal(t, c.key, err.Error()) - - } -} - func TestPostAnchoredValidator(t *testing.T) { pav := PostAnchoredValidator(nil, nil) assert.Len(t, pav, 2) diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 95cfec5a5..0b5f9212f 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -77,19 +77,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return mreq, err } - coreDoc, err := model.PackCoreDocument() - if err != nil { - return mreq, err - } - - dataRoot, err := model.CalculateDataRoot() - if err != nil { - return mreq, err - } - - pfs, err := coreDoc.GetNFTProofs( - dataRoot, - cid, + pfs, err := model.CreateNFTProofs(cid, req.RegistryAddress, tokenID[:], req.SubmitTokenProof, @@ -99,12 +87,17 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke } docProofs.FieldProofs = append(docProofs.FieldProofs, pfs...) - anchorID, err := anchors.ToAnchorID(coreDoc.Document.CurrentVersion) + anchorID, err := anchors.ToAnchorID(model.CurrentVersion()) + if err != nil { + return mreq, err + } + + dr, err := model.CalculateDocumentRoot() if err != nil { return mreq, err } - rootHash, err := anchors.ToDocumentRoot(coreDoc.Document.DocumentRoot) + rootHash, err := anchors.ToDocumentRoot(dr) if err != nil { return mreq, err } @@ -142,13 +135,8 @@ func (s *ethereumPaymentObligation) MintNFT(ctx context.Context, req MintNFTRequ return nil, nil, err } - dm, err := model.PackCoreDocument() - if err != nil { - return nil, nil, err - } - // check if the nft is successfully minted already - if dm.IsNFTMinted(s, req.RegistryAddress) { + if model.IsNFTMinted(s, req.RegistryAddress) { return nil, nil, errors.NewTypedError(ErrNFTMinted, errors.New("registry %v", req.RegistryAddress.String())) } @@ -174,19 +162,7 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - dm, err := model.PackCoreDocument() - if err != nil { - errOut <- err - return - } - - ndm, err := dm.AddNFT(req.GrantNFTReadAccess, req.RegistryAddress, tokenID[:]) - if err != nil { - errOut <- err - return - } - - model, err = s.docSrv.DeriveFromCoreDocumentModel(ndm) + err = model.AddNFT(req.GrantNFTReadAccess, req.RegistryAddress, tokenID[:]) if err != nil { errOut <- err return diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 3780c4e42..e4bb8812b 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/documents" @@ -20,6 +18,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" @@ -154,12 +153,12 @@ func TestPaymentObligationService(t *testing.T) { { "happypath", func() (testingdocuments.MockService, *MockPaymentObligation, testingcommons.MockIdentityService, testingcommons.MockEthClient, testingconfig.MockConfig, *testingutils.MockQueue, *testingtx.MockTxManager) { - coreDocModel := documents.NewCoreDocModel() - coreDoc := coreDocModel.Document - coreDoc.DocumentRoot = utils.RandomSlice(32) - proof := getDummyProof(coreDoc) + cd, err := documents.NewCoreDocumentWithCollaborators(nil) + assert.NoError(t, err) + cd.Document.DocumentRoot = utils.RandomSlice(32) + proof := getDummyProof(&cd.Document) docServiceMock := testingdocuments.MockService{} - docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocumentModel: coreDocModel}, nil) + docServiceMock.On("GetCurrentVersion", decodeHex("0x1212")).Return(&invoice.Invoice{InvoiceNumber: "1232", CoreDocument: cd}, nil) docServiceMock.On("CreateProofs", decodeHex("0x1212"), []string{"collaborators[0]"}).Return(proof, nil) paymentObligationMock := &MockPaymentObligation{} idServiceMock := testingcommons.MockIdentityService{} diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 9ed65ed30..294c54a30 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -91,8 +91,7 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address assert.Nil(t, err) // get ID - id, err := modelUpdated.ID() - assert.Nil(t, err, "should not error out when getting invoice ID") + id := modelUpdated.ID() // call mint // assert no error depositAddr := "0xf72855759a39fb75fc7341139f5d7a3974d4da08" @@ -130,9 +129,8 @@ func TestPaymentObligationService_mint_grant_read_access(t *testing.T) { tokenID := mintNFT(t, ctx, req, cid, registry) doc, err := invSrv.GetCurrentVersion(ctx, id) assert.NoError(t, err) - md, err := doc.PackCoreDocument() + cd, err := doc.PackCoreDocument() assert.NoError(t, err) - cd := md.Document assert.Len(t, cd.Roles, 2) assert.Len(t, cd.Roles[1].Nfts, 1) newNFT := cd.Roles[1].Nfts[0] @@ -189,7 +187,7 @@ func mintNFTWithProofs(t *testing.T, grantAccess, tokenProof, readAccessProof bo if grantAccess { roleCount++ } - assert.Len(t, cd.Document.Roles, roleCount) + assert.Len(t, cd.Roles, roleCount) } func TestEthereumPaymentObligation_MintNFT(t *testing.T) { diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index a84859a9c..54b64bda5 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/p2p/receiver" ) @@ -35,8 +36,13 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { return errors.New("identity service not initialised") } + tokenRegistry, ok := ctx[nft.BootstrappedPayObService].(documents.TokenRegistry) + if !ok { + return errors.New("token registry is not initialised") + } + ctx[bootstrap.BootstrappedPeer] = &peer{config: cfgService, idService: idService, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) + return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, tokenRegistry) }} return nil } diff --git a/p2p/bootstrapper_test.go b/p2p/bootstrapper_test.go index 6aa094a86..f8a62ed5d 100644 --- a/p2p/bootstrapper_test.go +++ b/p2p/bootstrapper_test.go @@ -10,9 +10,11 @@ import ( "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/nft" "github.com/centrifuge/go-centrifuge/node" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/stretchr/testify/assert" ) @@ -32,6 +34,7 @@ func TestBootstrapper_Bootstrap(t *testing.T) { ids := new(testingcommons.MockIdentityService) m[identity.BootstrappedDIDService] = ids m[documents.BootstrappedDocumentService] = documents.DefaultService(nil, nil, documents.NewServiceRegistry(), ids) + m[nft.BootstrappedPayObService] = new(testingdocuments.MockRegistry) err = b.Bootstrap(m) assert.Nil(t, err) diff --git a/p2p/client.go b/p2p/client.go index 89cca7220..fe5adb2eb 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/errors" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/centerrors" @@ -27,7 +28,9 @@ func (s *peer) SendAnchoredDocument(ctx context.Context, receiverID identity.DID return nil, err } - peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) + peerCtx, cancel := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) + defer cancel() + tc, err := s.config.GetAccount(receiverID[:]) if err == nil { // this is a local account @@ -124,7 +127,7 @@ func (s *peer) getPeerID(id identity.DID) (libp2pPeer.ID, error) { } // getSignatureForDocument requests the target node to sign the document -func (s *peer) getSignatureForDocument(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.DID) (*p2ppb.SignatureResponse, error) { +func (s *peer) getSignatureForDocument(ctx context.Context, cd coredocumentpb.CoreDocument, id identity.DID) (*p2ppb.SignatureResponse, error) { nc, err := s.config.GetConfig() if err != nil { return nil, err @@ -132,9 +135,7 @@ func (s *peer) getSignatureForDocument(ctx context.Context, model documents.Core var resp *p2ppb.SignatureResponse var header *p2ppb.Header - doc := model.Document - - tc, err := s.config.GetAccount(receiverCentID[:]) + tc, err := s.config.GetAccount(id[:]) if err == nil { // this is a local account h := s.handlerCreator() @@ -144,28 +145,28 @@ func (s *peer) getSignatureForDocument(ctx context.Context, model documents.Core return nil, err } - resp, err = h.RequestDocumentSignature(localPeerCtx, &p2ppb.SignatureRequest{Document: doc}) + resp, err = h.RequestDocumentSignature(localPeerCtx, &p2ppb.SignatureRequest{Document: &cd}) if err != nil { return nil, err } header = &p2ppb.Header{NodeVersion: version.GetVersion().String()} } else { // this is a remote account - err = s.idService.Exists(ctx, receiverCentID) + err = s.idService.Exists(ctx, id) if err != nil { return nil, err } - receiverPeer, err := s.getPeerID(receiverCentID) + receiverPeer, err := s.getPeerID(id) if err != nil { return nil, err } - envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: doc}) + envelope, err := p2pcommon.PrepareP2PEnvelope(ctx, nc.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) if err != nil { return nil, err } log.Infof("Requesting signature from %s\n", receiverPeer) - recv, err := s.mes.SendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForDID(&receiverCentID)) + recv, err := s.mes.SendMessage(ctx, receiverPeer, envelope, p2pcommon.ProtocolForDID(&id)) if err != nil { return nil, err } @@ -188,12 +189,12 @@ func (s *peer) getSignatureForDocument(ctx context.Context, model documents.Core header = recvEnvelope.Header } - err = validateSignatureResp(s.idService, receiverCentID, &model, header, resp) + err = validateSignatureResp(s.idService, id, cd.SigningRoot, header, resp) if err != nil { return nil, err } - log.Infof("Signature successfully received from %s\n", receiverCentID) + log.Infof("Signature successfully received from %s\n", id) return resp, nil } @@ -202,44 +203,44 @@ type signatureResponseWrap struct { err error } -func (s *peer) getSignatureAsync(ctx context.Context, model documents.CoreDocumentModel, receiverCentID identity.DID, out chan<- signatureResponseWrap) { - resp, err := s.getSignatureForDocument(ctx, model, receiverCentID) +func (s *peer) getSignatureAsync(ctx context.Context, cd coredocumentpb.CoreDocument, id identity.DID, out chan<- signatureResponseWrap) { + resp, err := s.getSignatureForDocument(ctx, cd, id) out <- signatureResponseWrap{ resp: resp, err: err, } } -// GetSignaturesForDocument requests peer nodes for the signature and verifies them -func (s *peer) GetSignaturesForDocument(ctx context.Context, model *documents.CoreDocumentModel) error { +// GetSignaturesForDocument requests peer nodes for the signature, verifies them, and returns those signatures. +func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Model) (signatures []*coredocumentpb.Signature, err error) { in := make(chan signatureResponseWrap) defer close(in) nc, err := s.config.GetConfig() if err != nil { - return err + return nil, err } self, err := contextutil.Self(ctx) if err != nil { - return centerrors.Wrap(err, "failed to get self") + return nil, errors.New("failed to get self ID") } - extCollaborators, err := model.GetExternalCollaborators(self.ID) + cs, err := model.GetCollaborators(self.ID) if err != nil { - return centerrors.Wrap(err, "failed to get external collaborators") + return nil, errors.New("failed to get external collaborators") + } + + cd, err := model.PackCoreDocument() + if err != nil { + return nil, errors.New("failed to pack core document: %v", err) } - doc := model.Document var count int peerCtx, _ := context.WithTimeout(ctx, nc.GetP2PConnectionTimeout()) - for _, collaborator := range extCollaborators { - collaboratorID := identity.NewDIDFromBytes(collaborator) + for _, c := range cs { count++ - m := *model - nd := *doc - m.Document = &nd - go s.getSignatureAsync(peerCtx, m, collaboratorID, in) + go s.getSignatureAsync(peerCtx, cd, c, in) } var responses []signatureResponseWrap @@ -254,10 +255,10 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, model *documents.Co continue } - doc.Signatures = append(doc.Signatures, resp.resp.Signature) + signatures = append(signatures, resp.resp.Signature) } - return nil + return signatures, nil } func convertClientError(recv *p2ppb.Envelope) error { @@ -269,7 +270,13 @@ func convertClientError(recv *p2ppb.Envelope) error { return errors.New(resp.Message) } -func validateSignatureResp(identityService identity.ServiceDID, receiver identity.DID, model *documents.CoreDocumentModel, header *p2ppb.Header, resp *p2ppb.SignatureResponse) error { +func validateSignatureResp( + identityService identity.ServiceDID, + receiver identity.DID, + signingRoot []byte, + header *p2ppb.Header, + resp *p2ppb.SignatureResponse) error { + compatible := version.CheckVersion(header.NodeVersion) if !compatible { return version.IncompatibleVersionError(header.NodeVersion) @@ -280,8 +287,7 @@ func validateSignatureResp(identityService identity.ServiceDID, receiver identit return centerrors.New(code.AuthenticationFailed, err.Error()) } - doc := model.Document - err = identityService.ValidateSignature(resp.Signature, doc.SigningRoot) + err = identityService.ValidateSignature(resp.Signature, signingRoot) if err != nil { return centerrors.New(code.AuthenticationFailed, fmt.Sprintf("signature invalid with err: %s", err.Error())) } diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index bfb92d441..6878fbf3a 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -8,24 +8,21 @@ import ( "os" "testing" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - - "github.com/centrifuge/go-centrifuge/contextutil" - - "github.com/ethereum/go-ethereum/common" - - "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) @@ -35,7 +32,6 @@ var ( idService identity.ServiceDID idFactory identity.Factory cfgStore config.Service - docService documents.Service defaultDID identity.DID ) @@ -47,7 +43,6 @@ func TestMain(m *testing.M) { idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) client = ctx[bootstrap.BootstrappedPeer].(documents.Client) - docService = ctx[documents.BootstrappedDocumentService].(documents.Service) tc, _ := configstore.TempAccount("", cfg) didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) assert.NoError(&testing.T{}, err) @@ -69,31 +64,35 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { acci.IdentityID = defaultDID[:] ctxh, err := contextutil.New(context.Background(), acci) assert.Nil(t, err) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) - err = client.GetSignaturesForDocument(ctxh, dm) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + signs, err := client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) - assert.Equal(t, 2, len(dm.Document.Signatures)) + assert.NotNil(t, signs) } func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) - ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) - err = client.GetSignaturesForDocument(ctxh, dm) + acc, err := configstore.NewAccount("", cfg) + assert.Nil(t, err) + acci := acc.(*configstore.Account) + acci.IdentityID = defaultDID[:] + ctxh, err := contextutil.New(context.Background(), acci) + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + signs, err := client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) // one signature would be missing - assert.Equal(t, 1, len(dm.Document.Signatures)) + assert.Equal(t, 0, len(signs)) } func TestClient_SendAnchoredDocument(t *testing.T) { tc, cid, err := createLocalCollaborator(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}, defaultDID) - - _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: dm.Document}) - if assert.Error(t, err) { - assert.Equal(t, "[1]document is invalid: [mismatched document roots]", err.Error()) - } + dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) + cd, err := dm.PackCoreDocument() + assert.NoError(t, err) + _, err = client.SendAnchoredDocument(ctxh, cid, &p2ppb.AnchorDocumentRequest{Document: &cd}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "mismatched document roots") } func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account, identity.DID, error) { @@ -118,31 +117,26 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account return tcr, did, err } -func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte, localID identity.DID) *documents.CoreDocumentModel { +func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) documents.Model { idConfig, err := identity.GetIdentityConfig(cfg) + idConfig.ID = defaultDID assert.Nil(t, err) - idConfig.ID = localID - dm, err := testingdocuments.GenerateCoreDocumentModelWithCollaborators(collaborators) - assert.NoError(t, err) - m, err := docService.DeriveFromCoreDocumentModel(dm) - assert.Nil(t, err) - - droot, err := m.CalculateDataRoot() - assert.Nil(t, err) - - dm, err = m.PackCoreDocument() + payalod := testingdocuments.CreatePOPayload() + var cs []string + for _, c := range collaborators { + cs = append(cs, hexutil.Encode(c)) + } + payalod.Collaborators = cs + po := new(purchaseorder.PurchaseOrder) + err = po.InitPurchaseOrderInput(payalod, idConfig.ID.String()) assert.NoError(t, err) - - tree, err := dm.GetDocumentSigningTree(droot) + _, err = po.CalculateDataRoot() assert.NoError(t, err) - dm.Document.SigningRoot = tree.RootHash() - - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, dm.Document.SigningRoot) + sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - dm.Document.Signatures = []*coredocumentpb.Signature{sig} - - tree, err = dm.GetDocumentRootTree() + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) + po.AppendSignatures(sig) + _, err = po.CalculateDocumentRoot() assert.NoError(t, err) - dm.Document.DocumentRoot = tree.RootHash() - return dm + return po } diff --git a/p2p/client_test.go b/p2p/client_test.go index a83d405c1..97779210b 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -6,23 +6,23 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/documents" - - "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/p2p/common" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/golang/protobuf/proto" - - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" - libp2pPeer "github.com/libp2p/go-libp2p-peer" - "github.com/libp2p/go-libp2p-protocol" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/p2p/common" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/version" + "github.com/golang/protobuf/proto" + libp2pPeer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-protocol" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -43,7 +43,6 @@ func (mm *MockMessenger) SendMessage(ctx context.Context, p libp2pPeer.ID, pmes func TestGetSignatureForDocument_fail_connect(t *testing.T) { centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") - assert.NoError(t, err) c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -51,17 +50,14 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - coreDoc := coreDocModel.Document - assert.Nil(t, err, "centrifugeId not initialized correctly ") + _, cd := createCDWithEmbeddedPO(t) - _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) assert.NoError(t, err, "signature request could not be created") m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(nil, errors.New("some error")) - resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, cd, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Nil(t, resp, "must be nil") @@ -70,6 +66,7 @@ func TestGetSignatureForDocument_fail_connect(t *testing.T) { func TestGetSignatureForDocument_fail_version_check(t *testing.T) { centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") assert.NoError(t, err) + c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -77,15 +74,13 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - coreDoc := coreDocModel.Document + _, cd := createCDWithEmbeddedPO(t) - _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) assert.NoError(t, err, "signature request could not be created") m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(testClient.createSignatureResp("", nil), nil) - resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, cd, centrifugeId) m.AssertExpectations(t) assert.Error(t, err, "must fail") assert.Contains(t, err.Error(), "Incompatible version") @@ -94,7 +89,6 @@ func TestGetSignatureForDocument_fail_version_check(t *testing.T) { func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { centrifugeId, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") - assert.NoError(t, err) c, err := cfg.GetConfig() assert.NoError(t, err) c = updateKeys(c) @@ -102,20 +96,16 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { idService := getIDMocks(ctx, centrifugeId) m := &MockMessenger{} testClient := &peer{config: cfg, idService: idService, mes: m, disablePeerStore: true} - coreDocModel, err := testingdocuments.GenerateCoreDocumentModel() - assert.NoError(t, err) - coreDoc := coreDocModel.Document + _, cd := createCDWithEmbeddedPO(t) - assert.Nil(t, err, "centrifugeId not initialized correctly ") - - _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: coreDoc}) + _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) assert.NoError(t, err, "signature request could not be created") randomBytes := utils.RandomSlice(identity.CentIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) - resp, err := testClient.getSignatureForDocument(ctx, *coreDocModel, centrifugeId) + resp, err := testClient.getSignatureForDocument(ctx, cd, centrifugeId) m.AssertExpectations(t) assert.Nil(t, resp, "must be nil") @@ -152,3 +142,18 @@ func (s *peer) createSignatureResp(centNodeVer string, signature *coredocumentpb return &protocolpb.P2PEnvelope{Body: reqB} } + +func createCDWithEmbeddedPO(t *testing.T) (documents.Model, coredocumentpb.CoreDocument) { + po := new(purchaseorder.PurchaseOrder) + err := po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), testingidentity.GenerateRandomDID().String()) + assert.NoError(t, err) + _, err = po.CalculateDataRoot() + assert.NoError(t, err) + _, err = po.CalculateSigningRoot() + assert.NoError(t, err) + _, err = po.CalculateDocumentRoot() + assert.NoError(t, err) + cd, err := po.PackCoreDocument() + assert.NoError(t, err) + return po, cd +} diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index c962cb57c..0adb64980 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -13,6 +13,7 @@ import ( "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" pb "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" + "github.com/ethereum/go-ethereum/common" "github.com/golang/protobuf/proto" "github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-protocol" @@ -23,17 +24,20 @@ type Handler struct { config config.Service handshakeValidator ValidatorGroup docSrv documents.Service + tokenRegistry documents.TokenRegistry } // New returns an implementation of P2PServiceServer func New( config config.Service, handshakeValidator ValidatorGroup, - docSrv documents.Service) *Handler { + docSrv documents.Service, + tokenRegistry documents.TokenRegistry) *Handler { return &Handler{ config: config, handshakeValidator: handshakeValidator, docSrv: docSrv, + tokenRegistry: tokenRegistry, } } @@ -111,12 +115,11 @@ func (srv *Handler) HandleRequestDocumentSignature(ctx context.Context, peer pee // Existing signatures on the document will be verified // Document will be stored to the repository for state management func (srv *Handler) RequestDocumentSignature(ctx context.Context, sigReq *p2ppb.SignatureRequest) (*p2ppb.SignatureResponse, error) { - dm := new(documents.CoreDocumentModel) - if sigReq.Document == nil { - return nil, errors.New("nil core document") + if sigReq == nil || sigReq.Document == nil { + return nil, errors.New("nil document provided") } - dm.Document = sigReq.Document - model, err := srv.docSrv.DeriveFromCoreDocumentModel(dm) + + model, err := srv.docSrv.DeriveFromCoreDocument(*sigReq.Document) if err != nil { return nil, errors.New("failed to derive from core doc: %v", err) } @@ -157,9 +160,11 @@ func (srv *Handler) HandleSendAnchoredDocument(ctx context.Context, peer peer.ID // SendAnchoredDocument receives a new anchored document, validates and updates the document in DB func (srv *Handler) SendAnchoredDocument(ctx context.Context, docReq *p2ppb.AnchorDocumentRequest, senderID []byte) (*p2ppb.AnchorDocumentResponse, error) { - dm := new(documents.CoreDocumentModel) - dm.Document = docReq.Document - model, err := srv.docSrv.DeriveFromCoreDocumentModel(dm) + if docReq == nil || docReq.Document == nil { + return nil, errors.New("nil document provided") + } + + model, err := srv.docSrv.DeriveFromCoreDocument(*docReq.Document) if err != nil { return nil, errors.New("failed to derive from core doc: %v", err) } @@ -201,47 +206,56 @@ func (srv *Handler) HandleGetDocument(ctx context.Context, peer peer.ID, protoc } // GetDocument receives document identifier and retrieves the corresponding CoreDocument from the repository -func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requesterCentID identity.DID) (*p2ppb.GetDocumentResponse, error) { - // if the document request contains an access token request, check the document indicated by the delegating document identifier for the access token - if docReq.AccessTokenRequest != nil { - model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.AccessTokenRequest.DelegatingDocumentIdentifier) - if err != nil { - return nil, err - } - dm, err := model.PackCoreDocument() - if err != nil { - return nil, err - } - err = dm.ValidateDocumentAccess(docReq, requesterCentID) - if err != nil { - return nil, err - } - // if the access token passes validation, return the requested document indicated in the parent GetDocumentRequest - reqModel, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) - if err != nil { - return nil, err - } - reqDm, err := reqModel.PackCoreDocument() - if err != nil { - return nil, err - } - return &p2ppb.GetDocumentResponse{Document: reqDm.Document}, nil - } - // if the document request requires NFT or Peer validation, validate the request based on the document identifier in the GetDocumentRequest +func (srv *Handler) GetDocument(ctx context.Context, docReq *p2ppb.GetDocumentRequest, requester identity.DID) (*p2ppb.GetDocumentResponse, error) { model, err := srv.docSrv.GetCurrentVersion(ctx, docReq.DocumentIdentifier) if err != nil { return nil, err } - dm, err := model.PackCoreDocument() - if err != nil { + + if srv.validateDocumentAccess(ctx, docReq, model, requester) != nil { return nil, err } - err = dm.ValidateDocumentAccess(docReq, requesterCentID) + + cd, err := model.PackCoreDocument() if err != nil { return nil, err } - // return requested document if validation checks pass - return &p2ppb.GetDocumentResponse{Document: dm.Document}, nil + + return &p2ppb.GetDocumentResponse{Document: &cd}, nil +} + +// validateDocumentAccess validates the GetDocument request against the AccessType indicated in the request +func (srv *Handler) validateDocumentAccess(ctx context.Context, docReq *p2ppb.GetDocumentRequest, m documents.Model, peer identity.DID) error { + // checks which access type is relevant for the request + switch docReq.AccessType { + case p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION: + if !m.AccountCanRead(peer) { + return errors.New("requester does not have access") + } + case p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION: + registry := common.BytesToAddress(docReq.NftRegistryAddress) + if m.NFTOwnerCanRead(srv.tokenRegistry, registry, docReq.NftTokenId, peer) != nil { + return errors.New("requester does not have access") + } + case p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION: + // check the document indicated by the delegating document identifier for the access token + if docReq.AccessTokenRequest == nil { + return errors.New("access token request is nil") + } + + m, err := srv.docSrv.GetCurrentVersion(ctx, docReq.AccessTokenRequest.DelegatingDocumentIdentifier) + if err != nil { + return err + } + + err = m.ATOwnerCanRead(docReq.AccessTokenRequest.AccessTokenId, docReq.DocumentIdentifier, peer) + if err != nil { + return err + } + default: + return errors.New("invalid access type") + } + return nil } func convertToErrorEnvelop(err error) (*pb.P2PEnvelope, error) { diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index c61808f97..f03173788 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -9,19 +9,9 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/config/configstore" - "github.com/centrifuge/go-centrifuge/testingutils/documents" - "github.com/ethereum/go-ethereum/common" - - "github.com/centrifuge/centrifuge-protobufs/documenttypes" - "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" - "github.com/golang/protobuf/ptypes/any" - + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -30,12 +20,14 @@ import ( "github.com/centrifuge/go-centrifuge/contextutil" cented25519 "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/common" "github.com/centrifuge/go-centrifuge/p2p/receiver" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/protocol" "github.com/centrifuge/go-centrifuge/storage" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" @@ -62,7 +54,7 @@ func TestMain(m *testing.M) { anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) - handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv) + handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, new(testingdocuments.MockRegistry)) defaultDID = createIdentity(&testing.T{}) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() @@ -78,89 +70,6 @@ func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { assert.Nil(t, resp, "must be nil") } -func updateDocument(t *testing.T, dm *documents.CoreDocumentModel, centrifugeId identity.DID, ctxh context.Context) { - - dm = prepareDocumentForP2PHandler(t, dm, centrifugeId) - - ed := dm.Document.EmbeddedData - edsalts := dm.Document.EmbeddedDataSalts - - req := getSignatureRequest(dm) - resp, err := handler.RequestDocumentSignature(ctxh, req) - assert.NoError(t, err) - dm.Document.EmbeddedData = ed - dm.Document.EmbeddedDataSalts = edsalts - - // Add signature received - dm.Document.Signatures = append(dm.Document.Signatures, resp.Signature) - tree, err := dm.GetDocumentRootTree() - assert.NoError(t, err) - dm.Document.DocumentRoot = tree.RootHash() - - cdSalts, _ := documents.GenerateNewSalts(dm.Document, "", nil) - dm.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) -} - -func TestHandler_GetDocumentSucceeds(t *testing.T) { - // generate identity for testing - didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) - assert.NoError(t, err) - did := identity.NewDID(*didAddr) - tc, err := configstore.TempAccount("", cfg) - assert.NoError(t, err) - tcr := tc.(*configstore.Account) - tcr.IdentityID = did[:] - cid, err := testingidentity.CreateAccountIDWithKeys(cfg.GetEthereumContextWaitTimeout(), tcr, idService, idFactory) - assert.NoError(t, err) - - // generate initial core doc with collaborators - ctxh := testingconfig.CreateAccountContext(t, cfg) - dm, err := testingdocuments.GenerateCoreDocumentModelWithCollaborators([][]byte{cid[:]}) - assert.Nil(t, err) - - updateDocument(t, dm, cid, ctxh) - - // Retrieve document from repository with requester verification access type - getReq := getDocumentRequestPeer(dm) - getDocResp, err := handler.GetDocument(ctxh, getReq, cid) - assert.Nil(t, err) - assert.ObjectsAreEqual(getDocResp.Document, dm.Document) - - // Retrieve document from repository with access token verification access type - // TODO : will fail until signature validation scheme is changed - //docID := hexutil.Encode(dm.Document.DocumentIdentifier) - //at := documentpb.AccessTokenParams{ - // Grantee: cid.String(), - // DocumentIdentifier: docID, - //} - //dm, err = dm.AddAccessTokenToReadRules(ctxh, at) - //assert.NoError(t, err) - //dm, err = dm.PrepareNewVersion(nil) - //assert.NoError(t, err) - //updateDocument(t, dm, cid, ctxh) - // - //role := dm.Document.Roles[1] - //token := role.AccessTokens[0] - //accessTokenReq := getDocumentRequestAccessToken(dm, token.Identifier) - //getDocResp, err = handler.GetDocument(ctxh, accessTokenReq, cid) - //assert.Nil(t, err) - //assert.ObjectsAreEqual(getDocResp.Document, dm.Document) - - // Retrieve document from repository with nft verification access type - // TODO: will currently always work because token owner is a collaborator - registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") - tokenID := utils.RandomSlice(32) - err = dm.AddNFTToReadRules(registry, tokenID) - dm, err = dm.PrepareNewVersion(nil) - assert.NoError(t, err) - updateDocument(t, dm, cid, ctxh) - - nftReq := getDocumentRequestNft(dm, registry, tokenID) - getDocResp, err = handler.GetDocument(ctxh, nftReq, cid) - assert.Nil(t, err) - assert.ObjectsAreEqual(getDocResp.Document, dm.Document) -} - func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) tc, err := configstore.NewAccount("", cfg) @@ -171,9 +80,8 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { assert.Nil(t, err) _, err = cfgService.CreateAccount(acc) assert.NoError(t, err) - dm := prepareDocumentForP2PHandler(t, nil, centID) - req := getSignatureRequest(dm) - p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, req) + _, cd := prepareDocumentForP2PHandler(t, nil) + p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctxh, cfg.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) pub, _ := acc.GetP2PKeyPair() publicKey, err := cented25519.GetPublicSigningKey(pub) @@ -189,113 +97,73 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { resp := resolveSignatureResponse(t, p2pResp) assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - doc := dm.Document - assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") -} - -func TestHandler_RequestDocumentSignature_verification_fail(t *testing.T) { - ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil, defaultDID) - doc := dm.Document - doc.SigningRoot = nil - req := getSignatureRequest(dm) - resp, err := handler.RequestDocumentSignature(ctxh, req) - assert.NotNil(t, err, "must be non nil") - assert.Nil(t, resp, "must be nil") - assert.Contains(t, err.Error(), "signing root missing") + assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { - dm := prepareDocumentForP2PHandler(t, nil, defaultDID) - ed := dm.Document.EmbeddedData - edsalts := dm.Document.EmbeddedDataSalts - req := getSignatureRequest(dm) - tc, err := configstore.NewAccount("", cfg) - assert.Nil(t, err) - acc := tc.(*configstore.Account) - acc.IdentityID = defaultDID[:] - ctxh, err := contextutil.New(context.Background(), acc) - assert.Nil(t, err) - - resp, err := handler.RequestDocumentSignature(ctxh, req) + _, cd := prepareDocumentForP2PHandler(t, nil) + ctxh := testingconfig.CreateAccountContext(t, cfg) + resp, err := handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") - dm.Document.EmbeddedData = ed - dm.Document.EmbeddedDataSalts = edsalts - - req = getSignatureRequest(dm) - resp, err = handler.RequestDocumentSignature(ctxh, req) + resp, err = handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.NotNil(t, err, "must not be nil") assert.Contains(t, err.Error(), storage.ErrRepositoryModelCreateKeyExists.Error()) } func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil, defaultDID) - req := getSignatureRequest(dm) - doc := dm.Document - resp, err := handler.RequestDocumentSignature(ctxh, req) + po, cd := prepareDocumentForP2PHandler(t, nil) + resp, err := handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") + //Update document - newDM, err := dm.PrepareNewVersion(nil) - assert.Nil(t, err) - updateDocumentForP2Phandler(t, newDM) - newDM = prepareDocumentForP2PHandler(t, newDM, defaultDID) - req = getSignatureRequest(newDM) - resp, err = handler.RequestDocumentSignature(ctxh, req) + po, cd = updateDocumentForP2Phandler(t, po) + resp, err = handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig = resp.Signature - newDoc := newDM.Document - assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil, defaultDID) - newDM, err := dm.PrepareNewVersion(nil) - assert.Nil(t, err) - newDoc := newDM.Document - assert.NotEqual(t, newDoc.DocumentIdentifier, newDoc.CurrentVersion) - updateDocumentForP2Phandler(t, newDM) - newDM = prepareDocumentForP2PHandler(t, newDM, defaultDID) - req := getSignatureRequest(newDM) - resp, err := handler.RequestDocumentSignature(ctxh, req) + po, cd := prepareDocumentForP2PHandler(t, nil) + po, cd = updateDocumentForP2Phandler(t, po) + assert.NotEqual(t, cd.DocumentIdentifier, cd.CurrentVersion) + resp, err := handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, newDoc.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_RequestDocumentSignature(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - dm := prepareDocumentForP2PHandler(t, nil, defaultDID) - doc := dm.Document - req := getSignatureRequest(dm) - resp, err := handler.RequestDocumentSignature(ctxh, req) + _, cd := prepareDocumentForP2PHandler(t, nil) + resp, err := handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err, "must be nil") assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, doc.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") } func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { - centrifugeId := createIdentity(t) - dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) + _, cd := prepareDocumentForP2PHandler(t, nil) // Anchor document - doc := dm.Document idConfig, err := identity.GetIdentityConfig(cfg) - anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) - docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) + anchorIDTyped, _ := anchors.ToAnchorID(cd.CurrentVersion) + docRootTyped, _ := anchors.ToDocumentRoot(cd.DocumentRoot) + ctx := testingconfig.CreateAccountContext(t, cfg) anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) @@ -303,8 +171,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { watchCommittedAnchor := <-anchorConfirmations assert.True(t, watchCommittedAnchor, "No error should be thrown by context") - anchorReq := getAnchoredRequest(dm) - anchorResp, err := handler.SendAnchoredDocument(ctx, anchorReq, idConfig.ID[:]) + anchorResp, err := handler.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: &cd}, idConfig.ID[:]) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) assert.Nil(t, anchorResp) @@ -312,12 +179,9 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { ctxh := testingconfig.CreateAccountContext(t, cfg) - doc := prepareDocumentForP2PHandler(t, nil, defaultDID) - req := getAnchoredRequest(doc) - req.Document = nil id, err := cfg.GetIdentityID() assert.NoError(t, err) - resp, err := handler.SendAnchoredDocument(ctxh, req, id) + resp, err := handler.SendAnchoredDocument(ctxh, &p2ppb.AnchorDocumentRequest{}, id) assert.NotNil(t, err) assert.Nil(t, resp, "must be nil") } @@ -332,33 +196,27 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { ctxh, err := contextutil.New(context.Background(), tc) assert.Nil(t, err) - dm := prepareDocumentForP2PHandler(t, nil, centrifugeId) - ed := dm.Document.EmbeddedData - edsalts := dm.Document.EmbeddedDataSalts - req := getSignatureRequest(dm) - resp, err := handler.RequestDocumentSignature(ctxh, req) + po, cd := prepareDocumentForP2PHandler(t, nil) + resp, err := handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) assert.Nil(t, err) assert.NotNil(t, resp) - dm.Document.EmbeddedData = ed - dm.Document.EmbeddedDataSalts = edsalts // Add signature received - doc := dm.Document - doc.Signatures = append(doc.Signatures, resp.Signature) - tree, _ := dm.GetDocumentRootTree() - doc.DocumentRoot = tree.RootHash() + po.AppendSignatures(resp.Signature) + tree, err := po.DocumentRootTree() + po.Document.DocumentRoot = tree.RootHash() // Anchor document - anchorIDTyped, _ := anchors.ToAnchorID(doc.CurrentVersion) - docRootTyped, _ := anchors.ToDocumentRoot(doc.DocumentRoot) + anchorIDTyped, _ := anchors.ToAnchorID(po.Document.CurrentVersion) + docRootTyped, _ := anchors.ToDocumentRoot(po.Document.DocumentRoot) anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations assert.True(t, watchCommittedAnchor, "No error should be thrown by context") - - anchorReq := getAnchoredRequest(dm) - anchorResp, err := handler.SendAnchoredDocument(ctxh, anchorReq, centrifugeId[:]) + cd, err = po.PackCoreDocument() + assert.NoError(t, err) + anchorResp, err := handler.SendAnchoredDocument(ctxh, &p2ppb.AnchorDocumentRequest{Document: &cd}, centrifugeId[:]) assert.Nil(t, err) assert.NotNil(t, anchorResp, "must be non nil") assert.True(t, anchorResp.Accepted) @@ -403,87 +261,34 @@ func createIdentity(t *testing.T) identity.DID { return *did } -func prepareDocumentForP2PHandler(t *testing.T, dm *documents.CoreDocumentModel, did identity.DID) *documents.CoreDocumentModel { +func prepareDocumentForP2PHandler(t *testing.T, po *purchaseorder.PurchaseOrder) (*purchaseorder.PurchaseOrder, coredocumentpb.CoreDocument) { idConfig, err := identity.GetIdentityConfig(cfg) - idConfig.ID = did - assert.NoError(t, err) - if dm == nil { - dm, err = testingdocuments.GenerateCoreDocumentModel() - assert.Nil(t, err) - } - m, err := docSrv.DeriveFromCoreDocumentModel(dm) - assert.Nil(t, err) - - droot, err := m.CalculateDataRoot() assert.Nil(t, err) - - dm, err = m.PackCoreDocument() + idConfig.ID = defaultDID + if po == nil { + payload := testingdocuments.CreatePOPayload() + po = new(purchaseorder.PurchaseOrder) + err = po.InitPurchaseOrderInput(payload, idConfig.ID.String()) + assert.NoError(t, err) + } + _, err = po.CalculateDataRoot() assert.NoError(t, err) - - doc := dm.Document - tree, err := dm.GetDocumentSigningTree(droot) + sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - doc.SigningRoot = tree.RootHash() - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, doc.SigningRoot) - doc.Signatures = []*coredocumentpb.Signature{sig} - tree, err = dm.GetDocumentRootTree() + sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) + po.AppendSignatures(sig) + _, err = po.CalculateDocumentRoot() assert.NoError(t, err) - doc.DocumentRoot = tree.RootHash() - return dm -} - -func updateDocumentForP2Phandler(t *testing.T, model *documents.CoreDocumentModel) { - invData := &invoicepb.InvoiceData{} - dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) - - serializedInv, err := proto.Marshal(invData) + cd, err := po.PackCoreDocument() assert.NoError(t, err) - doc := model.Document - doc.EmbeddedData = &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInv, - } - doc.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) - cdSalts, _ := documents.GenerateCoreDocSalts(doc) - doc.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) -} - -func getAnchoredRequest(dm *documents.CoreDocumentModel) *p2ppb.AnchorDocumentRequest { - doc := *dm.Document - return &p2ppb.AnchorDocumentRequest{Document: &doc} -} - -func getSignatureRequest(dm *documents.CoreDocumentModel) *p2ppb.SignatureRequest { - doc := *dm.Document - return &p2ppb.SignatureRequest{Document: &doc} + return po, cd } -func getDocumentRequestPeer(dm *documents.CoreDocumentModel) *p2ppb.GetDocumentRequest { - return &p2ppb.GetDocumentRequest{ - DocumentIdentifier: dm.Document.DocumentIdentifier, - AccessType: p2ppb.AccessType_ACCESS_TYPE_REQUESTER_VERIFICATION, - } -} - -func getDocumentRequestNft(dm *documents.CoreDocumentModel, registry common.Address, tokenID []byte) *p2ppb.GetDocumentRequest { - return &p2ppb.GetDocumentRequest{ - DocumentIdentifier: dm.Document.DocumentIdentifier, - AccessType: p2ppb.AccessType_ACCESS_TYPE_NFT_OWNER_VERIFICATION, - NftRegistryAddress: registry[:], - NftTokenId: tokenID, - } -} - -func getDocumentRequestAccessToken(dm *documents.CoreDocumentModel, tokenID []byte) *p2ppb.GetDocumentRequest { - atr := &p2ppb.AccessTokenRequest{ - DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, - AccessTokenId: tokenID, - } - return &p2ppb.GetDocumentRequest{ - DocumentIdentifier: dm.Document.DocumentIdentifier, - AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, - AccessTokenRequest: atr, - } +func updateDocumentForP2Phandler(t *testing.T, po *purchaseorder.PurchaseOrder) (*purchaseorder.PurchaseOrder, coredocumentpb.CoreDocument) { + cd, err := po.CoreDocument.PrepareNewVersion(nil, true) + assert.NoError(t, err) + po.CoreDocument = cd + return prepareDocumentForP2PHandler(t, po) } func resolveSignatureResponse(t *testing.T, p2pEnv *protocolpb.P2PEnvelope) *p2ppb.SignatureResponse { diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index fb92132e2..6da90b801 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -24,6 +24,7 @@ import ( "github.com/centrifuge/go-centrifuge/storage/leveldb" testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/documents" "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/version" "github.com/ethereum/go-ethereum/common/hexutil" @@ -69,7 +70,7 @@ func TestMain(m *testing.M) { _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv) + handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv, new(testingdocuments.MockRegistry)) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) @@ -77,7 +78,6 @@ func TestMain(m *testing.M) { func TestHandler_RequestDocumentSignature_nilDocument(t *testing.T) { req := &p2ppb.SignatureRequest{} - resp, err := handler.RequestDocumentSignature(context.Background(), req) assert.Error(t, err, "must return error") assert.Nil(t, resp, "must be nil") @@ -172,21 +172,22 @@ func TestHandler_HandleInterceptor_NilDocument(t *testing.T) { id, _ := cfg.GetIdentityID() resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") - assert.Contains(t, err.Error(), "nil core document") + assert.Contains(t, err.Error(), "nil document provided") assert.Nil(t, resp, "must be nil") } func TestHandler_HandleInterceptor_getServiceAndModel_fail(t *testing.T) { ctx := testingconfig.CreateAccountContext(t, cfg) - dm := documents.NewCoreDocModel() - req := &p2ppb.AnchorDocumentRequest{Document: dm.Document} + cd, err := documents.NewCoreDocumentWithCollaborators(nil) + assert.NoError(t, err) + req := &p2ppb.AnchorDocumentRequest{Document: &cd.Document} p2pEnv, err := p2pcommon.PrepareP2PEnvelope(ctx, cfg.GetNetworkID(), p2pcommon.MessageTypeSendAnchoredDoc, req) assert.NoError(t, err) id, _ := cfg.GetIdentityID() resp, err := handler.HandleInterceptor(context.Background(), defaultPID, protocol.ID(hexutil.Encode(id)), p2pEnv) assert.Error(t, err, "must return error") - assert.Contains(t, err.Error(), "core document is nil") + assert.Contains(t, err.Error(), "core document embed data is nil") assert.Nil(t, resp, "must be nil") } diff --git a/p2p/receiver/validator_test.go b/p2p/receiver/validator_test.go index 99d79f3be..73c29a865 100644 --- a/p2p/receiver/validator_test.go +++ b/p2p/receiver/validator_test.go @@ -17,11 +17,7 @@ import ( testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" ) -var ( - key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - id1 = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} -) +var id1 = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} func TestValidate_versionValidator(t *testing.T) { vv := versionValidator() diff --git a/p2p/server_test.go b/p2p/server_test.go index 1eb95a1cd..9f5ddcf18 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -10,22 +10,20 @@ import ( "testing" "time" - "github.com/centrifuge/go-centrifuge/transactions/txv1" - "github.com/centrifuge/go-centrifuge/anchors" - - "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/p2p/receiver" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" testingcommons "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/utils" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" @@ -70,7 +68,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { cfgMock := mockmockConfigStore(n) assert.NoError(t, err) cp2p := &peer{config: cfgMock, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgMock, receiver.HandshakeValidator(n.NetworkID, idService), nil) + return receiver.New(cfgMock, receiver.HandshakeValidator(n.NetworkID, idService), nil, new(testingdocuments.MockRegistry)) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) diff --git a/queue/server.go b/queue/server.go index e92947c12..02cf0fe4a 100644 --- a/queue/server.go +++ b/queue/server.go @@ -13,8 +13,7 @@ import ( // Constants are commonly used by all the tasks through kwargs. const ( - BlockHeightParam string = "BlockHeight" - TimeoutParam string = "Timeout" + TimeoutParam string = "Timeout" ) var log = logging.Logger("queue-server") @@ -91,6 +90,8 @@ func (qs *Server) Start(ctx context.Context, wg *sync.WaitGroup, startupErr chan // RegisterTaskType registers a task type on the queue server func (qs *Server) RegisterTaskType(name string, task interface{}) { + qs.lock.Lock() + defer qs.lock.Unlock() qs.taskTypes = append(qs.taskTypes, task.(TaskType)) } @@ -136,17 +137,6 @@ func GetDuration(key interface{}) (time.Duration, error) { return time.Duration(f64), nil } -// ParseBlockHeight parses blockHeight interface param to uint64 -func ParseBlockHeight(valMap map[string]interface{}) (uint64, error) { - if bhi, ok := valMap[BlockHeightParam]; ok { - bhf, ok := bhi.(float64) - if ok { - return uint64(bhf), nil - } - } - return 0, errors.New("value can not be parsed") -} - // TaskQueuer can be implemented by any queueing system type TaskQueuer interface { EnqueueJob(taskTypeName string, params map[string]interface{}) (TaskResult, error) diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 3a6633209..3abb5914f 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -2,16 +2,11 @@ package testingdocuments import ( "context" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/gogo/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/golang/protobuf/ptypes/timestamp" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" - "time" ) type MockService struct { @@ -39,7 +34,7 @@ func (m *MockService) CreateProofsForVersion(ctx context.Context, documentID, ve return args.Get(0).(*documents.DocumentProof), args.Error(1) } -func (m *MockService) DeriveFromCoreDocument(cd *coredocumentpb.CoreDocument) (documents.Model, error) { +func (m *MockService) DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (documents.Model, error) { args := m.Called(cd) return args.Get(0).(documents.Model), args.Error(1) } @@ -62,17 +57,21 @@ func (m *MockService) Exists(ctx context.Context, documentID []byte) bool { type MockModel struct { documents.Model mock.Mock - CoreDocumentModel *documents.CoreDocumentModel } -func (m *MockModel) PackCoreDocument() (*documents.CoreDocumentModel, error) { +func (m *MockModel) CurrentVersion() []byte { + args := m.Called() + return args.Get(0).([]byte) +} + +func (m *MockModel) PackCoreDocument() (coredocumentpb.CoreDocument, error) { args := m.Called() - dm, _ := args.Get(0).(*documents.CoreDocumentModel) + dm, _ := args.Get(0).(coredocumentpb.CoreDocument) return dm, args.Error(1) } -func (m *MockModel) UnpackCoreDocument(model *documents.CoreDocumentModel) error { - args := m.Called(model) +func (m *MockModel) UnpackCoreDocument(cd coredocumentpb.CoreDocument) error { + args := m.Called(cd) return args.Error(0) } @@ -82,50 +81,12 @@ func (m *MockModel) JSON() ([]byte, error) { return data, args.Error(1) } -func GenerateCoreDocumentModelWithCollaborators(collaborators [][]byte) (*documents.CoreDocumentModel, error) { - dueDate := time.Now().Add(4 * 24 * time.Hour) - invData := &invoicepb.InvoiceData{ - InvoiceNumber: "2132131", - GrossAmount: 123, - NetAmount: 123, - Currency: "EUR", - DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, - } - dataSalts, _ := documents.GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) - serializedInv, _ := proto.Marshal(invData) - var dm *documents.CoreDocumentModel - if collaborators != nil { - var collabs []string - for _, c := range collaborators { - encoded := hexutil.Encode(c) - collabs = append(collabs, encoded) - } - m, err := documents.NewWithCollaborators(collabs) - if err != nil { - return nil, err - } - dm = m - } else { - dm = documents.NewCoreDocModel() - } - dm.Document.EmbeddedData = &any.Any{ - TypeUrl: documenttypes.InvoiceDataTypeUrl, - Value: serializedInv, - } - dm.Document.EmbeddedDataSalts = documents.ConvertToProtoSalts(dataSalts) - - cdSalts, _ := documents.GenerateCoreDocSalts(dm.Document) - dm.Document.CoredocumentSalts = documents.ConvertToProtoSalts(cdSalts) - mockModel := MockModel{ - CoreDocumentModel: dm, - } - return mockModel.CoreDocumentModel, nil -} - -func GenerateCoreDocumentModel() (*documents.CoreDocumentModel, error) { - dm, err := GenerateCoreDocumentModelWithCollaborators(nil) - if err != nil { - return nil, err - } - return dm, nil +type MockRegistry struct { + mock.Mock +} + +func (m MockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.Address, error) { + args := m.Called(registry, tokenID) + addr, _ := args.Get(0).(common.Address) + return addr, args.Error(1) } From 9c6c952f3ed4142de40339f512d267e7cc3b92b6 Mon Sep 17 00:00:00 2001 From: Charly Date: Wed, 27 Feb 2019 14:31:23 +0100 Subject: [PATCH 204/220] Use getter method instead of public variable in anchor contract (#783) --- Makefile | 2 +- anchors/service.go | 8 ++++++-- anchors/service_test.go | 18 ++++++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index c46438a3f..d96d836f7 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ install-deps: ## Install Dependencies @mv ./bin/* $(GOPATH)/bin/; rm -rf ./bin lint-check: ## runs linters on go code - @gometalinter --disable-all --enable=golint --enable=goimports --enable=vet --enable=nakedret \ + @gometalinter --exclude=anchors/service.go --disable-all --enable=golint --enable=goimports --enable=vet --enable=nakedret \ --enable=staticcheck --vendor --skip=resources --skip=testingutils --skip=protobufs --deadline=1m ./...; format-go: ## formats go code diff --git a/anchors/service.go b/anchors/service.go index c83bd74eb..bd13e5705 100644 --- a/anchors/service.go +++ b/anchors/service.go @@ -20,7 +20,10 @@ import ( type anchorRepositoryContract interface { PreCommit(opts *bind.TransactOpts, _anchorID *big.Int, signingRoot [32]byte, expirationBlock *big.Int) (*types.Transaction, error) Commit(opts *bind.TransactOpts, anchorID *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) - Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) + GetAnchorById(opts *bind.CallOpts, anchorID *big.Int) (struct { + AnchorId *big.Int + DocumentRoot [32]byte + }, error) } type service struct { @@ -39,7 +42,8 @@ func newService(config Config, anchorContract anchorRepositoryContract, queue *q func (s *service) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered opts, _ := s.client.GetGethCallOpts(false) - return s.anchorRepositoryContract.Commits(opts, anchorID.BigInt()) + r, err := s.anchorRepositoryContract.GetAnchorById(opts, anchorID.BigInt()) + return r.DocumentRoot, err } // PreCommitAnchor will call the transaction PreCommit on the smart contract diff --git a/anchors/service_test.go b/anchors/service_test.go index 5c7de4e64..484403a03 100644 --- a/anchors/service_test.go +++ b/anchors/service_test.go @@ -21,10 +21,20 @@ type mockAnchorRepo struct { anchorRepositoryContract } -func (m *mockAnchorRepo) Commits(opts *bind.CallOpts, anchorID *big.Int) (docRoot [32]byte, err error) { +func (m *mockAnchorRepo) GetAnchorById(opts *bind.CallOpts, anchorID *big.Int) (struct { + AnchorId *big.Int + DocumentRoot [32]byte +}, error) { args := m.Called(opts, anchorID) - docRoot, _ = args.Get(0).([32]byte) - return docRoot, args.Error(1) + type Response struct { + AnchorId *big.Int + DocumentRoot [32]byte + } + r := Response{} + dr := args.Get(0).([32]byte) + r.DocumentRoot = dr + + return r, args.Error(1) } func TestCorrectCommitSignatureGen(t *testing.T) { @@ -75,7 +85,7 @@ func TestGetDocumentRootOf(t *testing.T) { ethClient.On("GetGethCallOpts").Return(nil) ethRepo := newService(cfg, repo, nil, ethClient, nil) docRoot := utils.RandomByte32() - repo.On("Commits", mock.Anything, mock.Anything).Return(docRoot, nil) + repo.On("GetAnchorById", mock.Anything, mock.Anything).Return(docRoot, nil) gotRoot, err := ethRepo.GetDocumentRootOf(anchorID) repo.AssertExpectations(t) assert.Nil(t, err) From 2030867faac28f65bb2fa5f6b57dd2f9e7d82361 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 28 Feb 2019 10:17:55 +0100 Subject: [PATCH 205/220] Sign with secp (#780) * Sign with secp * fix tests * wip fix tests * fix tests * merge conflicts * crypto * comments * simplified validator * merge conflicts --- build/resources/signingKey.key.pem | 3 +- build/resources/signingKey.pub.pem | 3 +- cmd/centrifuge/sign_message.go | 4 +- cmd/centrifuge/verify_message.go | 14 +++-- cmd/common.go | 6 +- cmd/common_test.go | 8 +-- config/configstore/model.go | 13 +++-- config/configstore/service.go | 2 +- crypto/ed25519/ed25519_test.go | 4 +- crypto/secp256k1/secp256k1.go | 16 +++--- crypto/secp256k1/secp256k1_test.go | 6 +- crypto/sign.go | 36 +----------- crypto/sign_test.go | 70 +++++++++--------------- crypto/verify.go | 16 ++---- crypto/verify_test.go | 35 +++++++++++- documents/documents_test/service_test.go | 42 ++++++-------- documents/processor.go | 26 ++++----- documents/processor_test.go | 53 +++++++++++------- documents/read_acls.go | 2 +- documents/service.go | 49 ++++++++++++----- documents/validator.go | 58 ++------------------ documents/validator_test.go | 68 ++++++++++++----------- identity/did.go | 15 ++--- identity/ideth/service.go | 21 +++---- p2p/client_integration_test.go | 13 ++++- p2p/receiver/handler_integration_test.go | 30 +++++++--- resources/data.go | 4 +- 27 files changed, 295 insertions(+), 322 deletions(-) diff --git a/build/resources/signingKey.key.pem b/build/resources/signingKey.key.pem index 6a4321dc4..542909937 100644 --- a/build/resources/signingKey.key.pem +++ b/build/resources/signingKey.key.pem @@ -1,4 +1,3 @@ -----BEGIN PRIVATE KEY----- -d2NmjdH+vsF3E6jhIvOnFT2Y2iqDDcEUoDCni0sAeixxMbemBOBA/C7JaGWg5N39Jqarr88xhqBZ -qHzp9yJ3sw== +9ezdcXuufDTbJs1L5KUqpHzvy7b2RDwIv+Hm+0igkmY= -----END PRIVATE KEY----- diff --git a/build/resources/signingKey.pub.pem b/build/resources/signingKey.pub.pem index 818cffe36..3765ae51c 100644 --- a/build/resources/signingKey.pub.pem +++ b/build/resources/signingKey.pub.pem @@ -1,3 +1,4 @@ -----BEGIN PUBLIC KEY----- -cTG3pgTgQPwuyWhloOTd/Samq6/PMYagWah86fcid7M= +BK0k7zG5ygwJx5UPMu8+ggcIfTPJ8ZZlt64IDaaC48CxucHDpPPSWFNTtswgaGiU +GdY2+CG35gvsMpK1nQj7C2E= -----END PUBLIC KEY----- diff --git a/cmd/centrifuge/sign_message.go b/cmd/centrifuge/sign_message.go index a7f94e0a7..2f9c82e4b 100644 --- a/cmd/centrifuge/sign_message.go +++ b/cmd/centrifuge/sign_message.go @@ -15,7 +15,6 @@ func init() { var privateKeyFileParam string var curveTypeParam string var messageParam string - var ethereumSignFlag bool var signMessageCmd = &cobra.Command{ Use: "sign", @@ -27,7 +26,7 @@ func init() { if err != nil { log.Fatal(err) } - signature, err := crypto.SignMessage(privateKey, []byte(messageParam), curveTypeParam, ethereumSignFlag) + signature, err := crypto.SignMessage(privateKey, []byte(messageParam), curveTypeParam) if err != nil { log.Fatal(err) } @@ -39,5 +38,4 @@ func init() { signMessageCmd.Flags().StringVarP(&messageParam, "message", "m", "", "message to sign") signMessageCmd.Flags().StringVarP(&privateKeyFileParam, "private", "p", "", "private key path") signMessageCmd.Flags().StringVarP(&curveTypeParam, "type", "t", "", "type of the curve (supported:'secp256k1')") - signMessageCmd.Flags().BoolVarP(ðereumSignFlag, "ethereum", "e", false, "sign message according to Ethereum specification") } diff --git a/cmd/centrifuge/verify_message.go b/cmd/centrifuge/verify_message.go index 28d0d4bed..f781af7d2 100644 --- a/cmd/centrifuge/verify_message.go +++ b/cmd/centrifuge/verify_message.go @@ -4,7 +4,9 @@ import ( "fmt" "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/spf13/cobra" ) @@ -16,7 +18,6 @@ func init() { var messageParam string var signatureParam string var publicKeyFileParam string - var ethereumSignFlag bool var verifyMsgCmd = &cobra.Command{ Use: "verify", @@ -29,11 +30,15 @@ func init() { } publicKey, err := utils.ReadKeyFromPemFile(publicKeyFileParam, utils.PublicKey) - if err != nil { log.Fatal(err) } - correct := crypto.VerifyMessage(publicKey, []byte(messageParam), signatureBytes, curveTypeParam, ethereumSignFlag) + + if curveTypeParam == crypto.CurveSecp256K1 { + pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(publicKey))) + publicKey = pk32[:] + } + correct := crypto.VerifyMessage(publicKey, []byte(messageParam), signatureBytes, curveTypeParam) fmt.Println(correct) }, } @@ -41,7 +46,6 @@ func init() { rootCmd.AddCommand(verifyMsgCmd) verifyMsgCmd.Flags().StringVarP(&messageParam, "message", "m", "", "message to verify") verifyMsgCmd.Flags().StringVarP(&publicKeyFileParam, "public", "q", "", "public key path") - verifyMsgCmd.Flags().StringVarP(&curveTypeParam, "type", "t", "", "type of the curve (supported:'secp256k1')") + verifyMsgCmd.Flags().StringVarP(&curveTypeParam, "type", "t", "", "type of the curve (supported:'ed25519', 'secp256k1')") verifyMsgCmd.Flags().StringVarP(&signatureParam, "signature", "s", "", "signature") - verifyMsgCmd.Flags().BoolVarP(ðereumSignFlag, "ethereum", "e", false, "verify message which was signed with Ethereum") } diff --git a/cmd/common.go b/cmd/common.go index 0c154b22d..807d9875d 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -26,9 +26,9 @@ func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetP2PKeyPair() signPub, signPvt := config.GetSigningKeyPair() ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() - crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, "ed25519") - crypto.GenerateSigningKeyPair(signPub, signPvt, "ed25519") - crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, "secp256k1") + crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, crypto.CurveEd25519) + crypto.GenerateSigningKeyPair(signPub, signPvt, crypto.CurveSecp256K1) + crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, crypto.CurveSecp256K1) } // CreateConfig creates a config file using provide parameters and the default config diff --git a/cmd/common_test.go b/cmd/common_test.go index 6e6b70506..0afc4aa6d 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -78,7 +78,7 @@ func TestCreateConfig(t *testing.T) { // Keys exists // type KeyPurposeEthMsgAuth idSrv := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) - pk, _, err := secp256k1.GetEthAuthKey(cfg.GetEthAuthKeyPair()) + pk, _, err := secp256k1.GetSigningKeyPair(cfg.GetEthAuthKeyPair()) assert.Nil(t, err) address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) assert.Nil(t, err) @@ -97,11 +97,11 @@ func TestCreateConfig(t *testing.T) { assert.Equal(t, big.NewInt(identity.KeyPurposeP2P), response.Purposes[0], "purpose should be P2P") // type KeyPurposeSigning - pk, _, err = ed25519.GetSigningKeyPair(cfg.GetSigningKeyPair()) + pk, _, err = secp256k1.GetSigningKeyPair(cfg.GetSigningKeyPair()) assert.Nil(t, err) - pk32, err = utils.SliceToByte32(pk) + address32Bytes = utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) assert.Nil(t, err) - response, _ = idSrv.GetKey(accountId, pk32) + response, _ = idSrv.GetKey(accountId, address32Bytes) assert.NotNil(t, response) assert.Equal(t, big.NewInt(identity.KeyPurposeSigning), response.Purposes[0], "purpose should be Signing") diff --git a/config/configstore/model.go b/config/configstore/model.go index fcacb0e7a..414fc16c3 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -546,12 +546,11 @@ func (acc *Account) GetEthereumContextWaitTimeout() time.Duration { // SignMsg signs a message with the signing key func (acc *Account) SignMsg(msg []byte) (*coredocumentpb.Signature, error) { - //TODO change signing keys to curve ed25519 keys, err := acc.GetKeys() if err != nil { return nil, err } - signature, err := crypto.SignMessage(keys[identity.KeyPurposeSigning].PrivateKey, msg, crypto.CurveEd25519, true) + signature, err := crypto.SignMessage(keys[identity.KeyPurposeSigning].PrivateKey, msg, crypto.CurveSecp256K1) if err != nil { return nil, err } @@ -587,19 +586,21 @@ func (acc *Account) GetKeys() (idKeys map[int]config.IDKey, err error) { PrivateKey: sk} } + //secp256k1 keys if _, ok := acc.keys[identity.KeyPurposeSigning]; !ok { - pk, sk, err := ed25519.GetSigningKeyPair(acc.GetSigningKeyPair()) + pk, sk, err := secp256k1.GetSigningKeyPair(acc.GetSigningKeyPair()) if err != nil { return idKeys, err } + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + acc.keys[identity.KeyPurposeSigning] = config.IDKey{ - PublicKey: pk, + PublicKey: address32Bytes[:], PrivateKey: sk} } - //secp256k1 keys if _, ok := acc.keys[identity.KeyPurposeEthMsgAuth]; !ok { - pk, sk, err := secp256k1.GetEthAuthKey(acc.GetEthAuthKeyPair()) + pk, sk, err := secp256k1.GetSigningKeyPair(acc.GetEthAuthKeyPair()) if err != nil { return idKeys, err } diff --git a/config/configstore/service.go b/config/configstore/service.go index 53bcd8275..bda26618b 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -134,7 +134,7 @@ func generateAccountKeys(keystore string, acc *Account, DID *identity.DID) (*Acc Pub: ePub, Priv: ePriv, } - err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, crypto.CurveEd25519) + err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, crypto.CurveSecp256K1) if err != nil { return nil, err } diff --git a/crypto/ed25519/ed25519_test.go b/crypto/ed25519/ed25519_test.go index 7f333cc55..b042591f9 100644 --- a/crypto/ed25519/ed25519_test.go +++ b/crypto/ed25519/ed25519_test.go @@ -25,8 +25,8 @@ func TestMain(m *testing.M) { } func TestPublicKeyToP2PKey(t *testing.T) { - expectedPeerId := "12D3KooWHSED5BoCN6ogf6e5Wk1H3pH63mT2Emki7wTTaAGD6bw8" - publicKey, err := GetPublicSigningKey("../../build/resources/signingKey.pub.pem") + expectedPeerId := "12D3KooWABdZBiW2MQyvqufkpKK45gkicbBtsaJU42mUAo4bVbTQ" + publicKey, err := GetPublicSigningKey("../../build/resources/p2pKey.pub.pem") assert.Nil(t, err) var bPk [32]byte diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index 9196e7e76..64b12af71 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -118,14 +118,14 @@ func VerifySignature(publicKey, message, signature []byte) bool { } -// GetEthAuthKey returns the public and private keys as byte array -func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { - privateKey, err := GetPrivateEthAuthKey(priv) +// GetSigningKeyPair returns the public and private keys as byte array +func GetSigningKeyPair(pub, priv string) (public, private []byte, err error) { + privateKey, err := GetPrivateSigningKey(priv) if err != nil { return nil, nil, errors.New("failed to read private key: %v", err) } - publicKey, err := GetPublicEthAuthKey(pub) + publicKey, err := GetPublicSigningKey(pub) if err != nil { return nil, nil, errors.New("failed to read public key: %v", err) } @@ -133,8 +133,8 @@ func GetEthAuthKey(pub, priv string) (public, private []byte, err error) { return publicKey, privateKey, nil } -// GetPrivateEthAuthKey returns the private key from the file -func GetPrivateEthAuthKey(fileName string) (key []byte, err error) { +// GetPrivateSigningKey returns the private key from the file +func GetPrivateSigningKey(fileName string) (key []byte, err error) { key, err = utils.ReadKeyFromPemFile(fileName, utils.PrivateKey) if err != nil { return nil, err @@ -142,8 +142,8 @@ func GetPrivateEthAuthKey(fileName string) (key []byte, err error) { return key, nil } -// GetPublicEthAuthKey returns the public key from the file -func GetPublicEthAuthKey(fileName string) (key []byte, err error) { +// GetPublicSigningKey returns the public key from the file +func GetPublicSigningKey(fileName string) (key []byte, err error) { key, err = utils.ReadKeyFromPemFile(fileName, utils.PublicKey) if err != nil { return nil, err diff --git a/crypto/secp256k1/secp256k1_test.go b/crypto/secp256k1/secp256k1_test.go index e9d97cb8c..ba4326417 100644 --- a/crypto/secp256k1/secp256k1_test.go +++ b/crypto/secp256k1/secp256k1_test.go @@ -150,7 +150,7 @@ func TestGetEthAuthKeyFromConfig(t *testing.T) { // bad public key path cfg.Set("keys.ethauth.publicKey", "bad path") - pubK, priK, err := GetEthAuthKey(cfg.GetEthAuthKeyPair()) + pubK, priK, err := GetSigningKeyPair(cfg.GetEthAuthKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) @@ -159,7 +159,7 @@ func TestGetEthAuthKeyFromConfig(t *testing.T) { // bad private key path cfg.Set("keys.ethauth.privateKey", "bad path") - pubK, priK, err = GetEthAuthKey(cfg.GetEthAuthKeyPair()) + pubK, priK, err = GetSigningKeyPair(cfg.GetEthAuthKeyPair()) assert.Error(t, err) assert.Nil(t, priK) assert.Nil(t, pubK) @@ -167,7 +167,7 @@ func TestGetEthAuthKeyFromConfig(t *testing.T) { cfg.Set("keys.ethauth.privateKey", pri) // success - pubK, priK, err = GetEthAuthKey(cfg.GetEthAuthKeyPair()) + pubK, priK, err = GetSigningKeyPair(cfg.GetEthAuthKeyPair()) assert.Nil(t, err) assert.NotNil(t, pubK) assert.NotNil(t, priK) diff --git a/crypto/sign.go b/crypto/sign.go index e50339229..199688991 100644 --- a/crypto/sign.go +++ b/crypto/sign.go @@ -2,52 +2,22 @@ package crypto import ( "strings" - "time" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/utils" "golang.org/x/crypto/ed25519" ) // SignMessage signs the message using the private key as the curveType provided. -// if ethereumSign is true, then the signature format is specific to ethereum. -func SignMessage(privateKey, message []byte, curveType string, ethereumSign bool) ([]byte, error) { +// if Secp256K1 curve provided, then the signature format is specific to ethereum. +func SignMessage(privateKey, message []byte, curveType string) ([]byte, error) { curveType = strings.ToLower(curveType) switch curveType { case CurveSecp256K1: - if ethereumSign { - return secp256k1.SignEthereum(message, privateKey) - } - - return secp256k1.Sign(message, privateKey) + return secp256k1.SignEthereum(message, privateKey) case CurveEd25519: return ed25519.Sign(privateKey, message), nil default: return nil, errors.New("curve %s not supported", curveType) } - -} - -// VerifySignature verifies the signature using ed25519 -func VerifySignature(pubKey, message, signature []byte) error { - valid := ed25519.Verify(pubKey, message, signature) - if !valid { - return errors.New("invalid signature") - } - - return nil -} - -// Sign the document with the private key and return the signature along with the public key for the verification -// assumes that signing root for the document is generated -// Deprecated -func Sign(id []byte, privateKey []byte, pubKey []byte, payload []byte) *coredocumentpb.Signature { - return &coredocumentpb.Signature{ - EntityId: id, - PublicKey: pubKey, - Signature: ed25519.Sign(privateKey, payload), - Timestamp: utils.ToTimestamp(time.Now().UTC()), - } } diff --git a/crypto/sign_test.go b/crypto/sign_test.go index b2a0948a6..52c09d2cd 100644 --- a/crypto/sign_test.go +++ b/crypto/sign_test.go @@ -3,51 +3,45 @@ package crypto import ( - "fmt" "os" "testing" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" ) var ( - key1Pub = []byte{230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - key1 = []byte{102, 109, 71, 239, 130, 229, 128, 189, 37, 96, 223, 5, 189, 91, 210, 47, 89, 4, 165, 6, 188, 53, 49, 250, 109, 151, 234, 139, 57, 205, 231, 253, 230, 49, 10, 12, 200, 149, 43, 184, 145, 87, 163, 252, 114, 31, 91, 163, 24, 237, 36, 51, 165, 8, 34, 104, 97, 49, 114, 85, 255, 15, 195, 199} - id1 = []byte{1, 1, 1, 1, 1, 1} - signature = []byte{0x4e, 0x3d, 0x90, 0x5f, 0x25, 0xc7, 0x90, 0x63, 0x7e, 0x6c, 0xd0, 0xe6, 0xc7, 0xbd, 0xe6, 0x81, 0x3b, 0xd0, 0x5b, 0x94, 0x76, 0x86, 0x4e, 0xcb, 0xb9, 0x36, 0x48, 0x44, 0x4b, 0x98, 0xd2, 0x4b, 0x6a, 0x65, 0x22, 0x92, 0x1c, 0x8a, 0xdb, 0xfe, 0xb7, 0x6f, 0xfe, 0x34, 0x52, 0xa3, 0x49, 0xe4, 0xda, 0xdc, 0x5d, 0x1b, 0x0, 0x79, 0x54, 0x60, 0x29, 0x22, 0x94, 0xb, 0x3c, 0x90, 0x3c, 0x3} + key1 = []byte{0xbc, 0xa4, 0xe3, 0x6a, 0x57, 0x9a, 0xc1, 0xfd, 0xc1, 0xf6, 0x5b, 0xbf, 0xbc, 0x3f, 0x72, 0x16, 0xe9, 0x93, 0x74, 0x83, 0xbf, 0x9a, 0x5d, 0xd9, 0x20, 0xf4, 0x8a, 0xf7, 0xc9, 0xe3, 0x9f, 0xcd} + key1Pub = []byte{0x04, 0x8f, 0x06, 0x87, 0x01, 0xfa, 0xbb, 0x2f, 0xb6, 0x67, 0xa4, 0x96, 0xfc, 0xb2, 0x64, 0x41, 0x1c, 0xd8, 0x58, 0x5c, 0x3b, 0x5b, 0xd3, 0xe1, 0xab, 0xfc, 0x47, 0x64, 0x2f, 0x98, 0xd8, 0xbb, 0x8f, 0x28, 0x77, 0xbb, 0xa1, 0x1b, 0xfc, 0xa3, 0x5b, 0xf8, 0xf1, 0xf2, 0x10, 0x52, 0x39, 0x45, 0x7c, 0x24, 0x41, 0xaf, 0xb9, 0x2a, 0xf1, 0x9f, 0xe4, 0x99, 0xf4, 0xb4, 0x91, 0xcf, 0x3a, 0xb5, 0x96} + signature = []byte{0x13, 0xa6, 0xb7, 0xff, 0x47, 0x10, 0x9f, 0x2b, 0x51, 0x3, 0x7c, 0xeb, 0x42, 0xfa, 0xc3, 0x52, 0x85, 0x2b, 0xa8, 0xea, 0xe, 0x34, 0x4f, 0xc0, 0xf7, 0x4a, 0xe9, 0x20, 0x57, 0xbd, 0x0, 0xb9, 0x7e, 0x87, 0x53, 0xa0, 0x34, 0xa8, 0xe1, 0xa, 0x80, 0xda, 0xb8, 0x82, 0x4, 0x11, 0xd3, 0x19, 0x1c, 0xbc, 0x8, 0x16, 0xd6, 0xfa, 0xae, 0x15, 0xcd, 0xb3, 0xc1, 0x97, 0x7d, 0x41, 0xd2, 0x52, 0x1} ) func TestSign(t *testing.T) { - sig := Sign(id1, key1, key1Pub, key1Pub) - assert.NotNil(t, sig) - assert.Equal(t, sig.PublicKey, []byte(key1Pub)) - assert.Equal(t, sig.EntityId, id1) - assert.NotEmpty(t, sig.Signature) - assert.Len(t, sig.Signature, 64) - assert.Equal(t, sig.Signature, signature) - assert.NotNil(t, sig.Timestamp, "must be non nil") + sig, err := SignMessage(key1, key1Pub, CurveSecp256K1) + assert.NoError(t, err) + assert.NotEmpty(t, sig) + assert.Len(t, sig, 65) + assert.Equal(t, signature, sig) } func TestValidateSignature_invalid_sig(t *testing.T) { pubKey := key1Pub message := key1Pub signature := utils.RandomSlice(32) - err := VerifySignature(pubKey, message, signature) - assert.NotNil(t, err, "must be not nil") - assert.Contains(t, err.Error(), "invalid signature") + pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pubKey))) + valid := VerifyMessage(pk32[:], message, signature, CurveSecp256K1) + assert.False(t, valid, "must be false") } -func TestValidateSignature_success(t *testing.T) { - pubKey := key1Pub - message := key1Pub - err := VerifySignature(pubKey, message, signature) - assert.Nil(t, err, "must be nil") +func TestSignMessageUnsupportedType(t *testing.T) { + sig, err := SignMessage(key1, key1Pub, "rsa") + assert.Error(t, err) + assert.Empty(t, sig) } -func TestSignMessage(t *testing.T) { +func TestSignMessageSecp256k1(t *testing.T) { publicKeyFile := "publicKey" privateKeyFile := "privateKey" @@ -58,9 +52,10 @@ func TestSignMessage(t *testing.T) { assert.Nil(t, err) publicKey, err := utils.ReadKeyFromPemFile(publicKeyFile, utils.PublicKey) assert.Nil(t, err) - signature, err := SignMessage(privateKey, testMsg, CurveSecp256K1, false) + signature, err := SignMessage(privateKey, testMsg, CurveSecp256K1) assert.Nil(t, err) - correct := VerifyMessage(publicKey, testMsg, signature, CurveSecp256K1, false) + pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(publicKey))) + correct := VerifyMessage(pk32[:], testMsg, signature, CurveSecp256K1) os.Remove(publicKeyFile) os.Remove(privateKeyFile) @@ -68,31 +63,20 @@ func TestSignMessage(t *testing.T) { assert.True(t, correct, "signature or verification didn't work correctly") } -func TestSignAndVerifyMessageEthereum(t *testing.T) { +func TestSignMessageEd25519(t *testing.T) { publicKeyFile := "publicKey" privateKeyFile := "privateKey" - testMsg := []byte("Centrifuge likes Ethereum") + testMsg := []byte("test") - GenerateSigningKeyPair(publicKeyFile, privateKeyFile, CurveSecp256K1) + GenerateSigningKeyPair(publicKeyFile, privateKeyFile, CurveEd25519) privateKey, err := utils.ReadKeyFromPemFile(privateKeyFile, utils.PrivateKey) assert.Nil(t, err) - signature, err := SignMessage(privateKey, testMsg, CurveSecp256K1, true) + publicKey, err := utils.ReadKeyFromPemFile(publicKeyFile, utils.PublicKey) assert.Nil(t, err) - - publicKey, _ := utils.ReadKeyFromPemFile(publicKeyFile, utils.PublicKey) - address := secp256k1.GetAddress(publicKey) - - fmt.Println("privateKey: ", hexutil.Encode(privateKey)) - fmt.Println("publicKey: ", hexutil.Encode(publicKey)) - fmt.Println("address:", address) - fmt.Println("msg:", string(testMsg[:])) - fmt.Println("msg in hex:", hexutil.Encode(testMsg)) - fmt.Println("hash of msg: ", hexutil.Encode(secp256k1.HashWithEthPrefix(testMsg))) - fmt.Println("signature:", hexutil.Encode(signature)) - fmt.Println("Generated Signature can also be verified at https://etherscan.io/verifySig") - - correct := VerifyMessage(publicKey, testMsg, signature, CurveSecp256K1, true) + signature, err := SignMessage(privateKey, testMsg, CurveEd25519) + assert.Nil(t, err) + correct := VerifyMessage(publicKey, testMsg, signature, CurveEd25519) os.Remove(publicKeyFile) os.Remove(privateKeyFile) diff --git a/crypto/verify.go b/crypto/verify.go index 820069955..f64d17e9f 100644 --- a/crypto/verify.go +++ b/crypto/verify.go @@ -3,23 +3,17 @@ package crypto import ( "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) // VerifyMessage verifies message using the public key as per the curve type. -// if ethereumVerify is true, ethereum specific verification is done -func VerifyMessage(publicKey, message []byte, signature []byte, curveType string, ethereumVerify bool) bool { - signatureBytes := make([]byte, len(signature)) - copy(signatureBytes, signature) - +// for Secp256K1 curve the verification is done with ethereum prefix +// for Secp256K1, public key should be the address of the original public key, following ethereum standards +func VerifyMessage(publicKey, message []byte, signature []byte, curveType string) bool { switch curveType { case CurveSecp256K1: - if ethereumVerify { - address := secp256k1.GetAddress(publicKey) - return secp256k1.VerifySignatureWithAddress(address, hexutil.Encode(signatureBytes), message) - } - - return secp256k1.VerifySignature(publicKey, message, signatureBytes) + return secp256k1.VerifySignatureWithAddress(common.BytesToAddress(publicKey).String(), hexutil.Encode(signature), message) case CurveEd25519: return ed25519.VerifySignature(publicKey, message, signature) default: diff --git a/crypto/verify_test.go b/crypto/verify_test.go index a5e955048..ec2188998 100644 --- a/crypto/verify_test.go +++ b/crypto/verify_test.go @@ -6,6 +6,9 @@ import ( "os" "testing" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" ) @@ -15,12 +18,38 @@ func TestVerifyMessageED25519(t *testing.T) { privateKeyFile := "privateKey" testMsg := "test" - GenerateSigningKeyPair(publicKeyFile, privateKeyFile, CurveEd25519) + err := GenerateSigningKeyPair(publicKeyFile, privateKeyFile, CurveEd25519) + assert.NoError(t, err) privateKey, err := utils.ReadKeyFromPemFile(privateKeyFile, utils.PrivateKey) assert.Nil(t, err) - signature, err := SignMessage(privateKey, []byte(testMsg), CurveEd25519, false) + signature, err := SignMessage(privateKey, []byte(testMsg), CurveEd25519) assert.NoError(t, err) + assert.Len(t, signature, 64) + publicKey, err := utils.ReadKeyFromPemFile(publicKeyFile, utils.PublicKey) + assert.NoError(t, err) + assert.True(t, VerifyMessage(publicKey, []byte(testMsg), signature, CurveEd25519)) + + os.Remove(publicKeyFile) + os.Remove(privateKeyFile) +} + +func TestVerifyMessageSecp256k1(t *testing.T) { + publicKeyFile := "publicKey" + privateKeyFile := "privateKey" + testMsg := "test" + + err := GenerateSigningKeyPair(publicKeyFile, privateKeyFile, CurveSecp256K1) + assert.NoError(t, err) + privateKey, err := utils.ReadKeyFromPemFile(privateKeyFile, utils.PrivateKey) + assert.Nil(t, err) + signature, err := SignMessage(privateKey, []byte(testMsg), CurveSecp256K1) + assert.NoError(t, err) + assert.Len(t, signature, 65) + publicKey, err := utils.ReadKeyFromPemFile(publicKeyFile, utils.PublicKey) + assert.NoError(t, err) + pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(publicKey))) + assert.True(t, VerifyMessage(pk32[:], []byte(testMsg), signature, CurveSecp256K1)) + os.Remove(publicKeyFile) os.Remove(privateKeyFile) - assert.Len(t, signature, 64) } diff --git a/documents/documents_test/service_test.go b/documents/documents_test/service_test.go index cd635180a..5075e8e73 100644 --- a/documents/documents_test/service_test.go +++ b/documents/documents_test/service_test.go @@ -12,11 +12,11 @@ import ( "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/invoice" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" @@ -97,8 +97,8 @@ func mockSignatureCheck(t *testing.T, i *invoice.Invoice, idService testingcommo func TestService_CreateProofs(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, _ := createCDWithEmbeddedInvoice(t, false) ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, false) idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) proof, err := service.CreateProofs(ctxh, i.ID(), []string{"invoice.invoice_number"}) assert.Nil(t, err) @@ -109,12 +109,12 @@ func TestService_CreateProofs(t *testing.T) { } func TestService_CreateProofsValidationFails(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, _ := createCDWithEmbeddedInvoice(t, false) + ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, false) idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) i.(*invoice.Invoice).Document.DataRoot = nil i.(*invoice.Invoice).Document.SigningRoot = nil assert.Nil(t, testRepo().Update(tenantID, i.CurrentVersion(), i)) - ctxh := testingconfig.CreateAccountContext(t, cfg) _, err := service.CreateProofs(ctxh, i.ID(), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to get signing root") @@ -122,9 +122,9 @@ func TestService_CreateProofsValidationFails(t *testing.T) { func TestService_CreateProofsInvalidField(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, _ := createCDWithEmbeddedInvoice(t, false) - idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, false) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) _, err := service.CreateProofs(ctxh, i.CurrentVersion(), []string{"invalid_field"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentProof, err)) @@ -140,9 +140,9 @@ func TestService_CreateProofsDocumentDoesntExist(t *testing.T) { func TestService_CreateProofsForVersion(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, _ := createCDWithEmbeddedInvoice(t, false) - idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, false) + idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) proof, err := service.CreateProofsForVersion(ctxh, i.ID(), i.CurrentVersion(), []string{"invoice.invoice_number"}) assert.Nil(t, err) assert.Equal(t, i.ID(), proof.DocumentID) @@ -153,11 +153,11 @@ func TestService_CreateProofsForVersion(t *testing.T) { func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { service, idService := getServiceWithMockedLayers() - i, _ := createCDWithEmbeddedInvoice(t, true) + ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, true) idService = mockSignatureCheck(t, i.(*invoice.Invoice), idService) i.(*invoice.Invoice).Document.DataRoot = nil i.(*invoice.Invoice).Document.SigningRoot = nil - ctxh := testingconfig.CreateAccountContext(t, cfg) signature, err := service.RequestDocumentSignature(ctxh, i) assert.NotNil(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentInvalid, err)) @@ -165,9 +165,9 @@ func TestService_RequestDocumentSignature_SigningRootNil(t *testing.T) { } func TestService_CreateProofsForVersionDocumentDoesntExist(t *testing.T) { - i, _ := createCDWithEmbeddedInvoice(t, false) - s, _ := getServiceWithMockedLayers() ctxh := testingconfig.CreateAccountContext(t, cfg) + i, _ := createCDWithEmbeddedInvoice(t, ctxh, false) + s, _ := getServiceWithMockedLayers() _, err := s.CreateProofsForVersion(ctxh, i.ID(), utils.RandomSlice(32), []string{"invoice.invoice_number"}) assert.Error(t, err) assert.True(t, errors.IsOfType(documents.ErrDocumentVersionNotFound, err)) @@ -340,7 +340,7 @@ func TestService_Exists(t *testing.T) { } -func createCDWithEmbeddedInvoice(t *testing.T, skipSave bool) (documents.Model, coredocumentpb.CoreDocument) { +func createCDWithEmbeddedInvoice(t *testing.T, ctx context.Context, skipSave bool) (documents.Model, coredocumentpb.CoreDocument) { i := new(invoice.Invoice) err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), cid.String()) assert.NoError(t, err) @@ -349,18 +349,12 @@ func createCDWithEmbeddedInvoice(t *testing.T, skipSave bool) (documents.Model, sr, err := i.CalculateSigningRoot() assert.NoError(t, err) - signKey := identity.IDKey{ - PublicKey: key1Pub[:], - PrivateKey: key1, - } - idConfig := &identity.IDConfig{ - ID: cid, - Keys: map[int]identity.IDKey{ - identity.KeyPurposeSigning: signKey, - }, - } + acc, err := contextutil.Account(ctx) + assert.NoError(t, err) + + sig, err := acc.SignMsg(sr) + assert.NoError(t, err) - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) i.AppendSignatures(sig) _, err = i.CalculateDocumentRoot() assert.NoError(t, err) diff --git a/documents/processor.go b/documents/processor.go index a863add4a..54e770408 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -65,7 +65,7 @@ func (dp defaultProcessor) Send(ctx context.Context, cd coredocumentpb.CoreDocum // PrepareForSignatureRequests gets the core document from the model, and adds the node's own signature func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, model Model) error { - self, err := contextutil.Self(ctx) + self, err := contextutil.Account(ctx) if err != nil { return err } @@ -81,25 +81,21 @@ func (dp defaultProcessor) PrepareForSignatureRequests(ctx context.Context, mode return errors.New("failed to calculate signing root: %v", err) } - model.AppendSignatures(identity.Sign(self, identity.KeyPurposeSigning, sr)) + sig, err := self.SignMsg(sr) + if err != nil { + return err + } + + model.AppendSignatures(sig) + return nil } // RequestSignatures gets the core document from the model, validates pre signature requirements, // collects signatures, and validates the signatures, func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) error { - self, err := contextutil.Self(ctx) - if err != nil { - return err - } - - idKeys, ok := self.Keys[identity.KeyPurposeSigning] - if !ok { - return errors.New("missing keys for signing") - } - - psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) - err = psv.Validate(nil, model) + psv := SignatureValidator(dp.identityService) + err := psv.Validate(nil, model) if err != nil { return errors.New("failed to validate model for signature request: %v", err) } @@ -115,7 +111,7 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e // PrepareForAnchoring validates the signatures and generates the document root func (dp defaultProcessor) PrepareForAnchoring(model Model) error { - psv := PostSignatureRequestValidator(dp.identityService) + psv := SignatureValidator(dp.identityService) err := psv.Validate(nil, model) if err != nil { return errors.New("failed to validate signatures: %v", err) diff --git a/documents/processor_test.go b/documents/processor_test.go index 195412309..bc03e2ffa 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -19,7 +19,6 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "golang.org/x/crypto/ed25519" ) type mockModel struct { @@ -143,7 +142,7 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.Len(t, model.sigs, 1) sig := model.sigs[0] self, _ := contextutil.Self(ctxh) - assert.True(t, ed25519.Verify(self.Keys[identity.KeyPurposeSigning].PublicKey, sr, sig.Signature)) + assert.True(t, crypto.VerifyMessage(self.Keys[identity.KeyPurposeSigning].PublicKey, sr, sig.Signature, crypto.CurveSecp256K1)) } type p2pClient struct { @@ -168,18 +167,13 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - // failed to get self - err := dp.RequestSignatures(context.Background(), nil) - assert.Error(t, err) - assert.True(t, errors.IsOfType(contextutil.ErrSelfNotFound, err)) - - self, err := contextutil.Self(ctxh) + self, err := contextutil.Account(ctxh) assert.NoError(t, err) sr := utils.RandomSlice(32) - keys := self.Keys[identity.KeyPurposeSigning] - sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + sig, err := self.SignMsg(sr) + assert.NoError(t, err) - // validations failed + // data validations failed model := new(mockModel) model.On("ID").Return([]byte{}) model.On("CurrentVersion").Return([]byte{}) @@ -189,7 +183,7 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model.AssertExpectations(t) assert.Error(t, err) - // failed signature collection + // key validation failed model = new(mockModel) id := utils.RandomSlice(32) next := utils.RandomSlice(32) @@ -200,6 +194,23 @@ func TestDefaultProcessor_RequestSignatures(t *testing.T) { model.On("Signatures").Return() model.sigs = append(model.sigs, sig) c := new(p2pClient) + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("cannot validate key")).Once() + err = dp.RequestSignatures(ctxh, model) + model.AssertExpectations(t) + c.AssertExpectations(t) + assert.Error(t, err) + assert.Contains(t, err.Error(), "cannot validate key") + + // failed signature collection + model = new(mockModel) + model.On("ID").Return(id) + model.On("CurrentVersion").Return(id) + model.On("NextVersion").Return(next) + model.On("CalculateSigningRoot").Return(sr, nil) + model.On("Signatures").Return() + model.sigs = append(model.sigs, sig) + c = new(p2pClient) + srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) c.On("GetSignaturesForDocument", ctxh, model).Return(nil, errors.New("failed to get signatures")).Once() dp.p2pClient = c err = dp.RequestSignatures(ctxh, model) @@ -231,11 +242,11 @@ func TestDefaultProcessor_PrepareForAnchoring(t *testing.T) { dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - self, err := contextutil.Self(ctxh) + self, err := contextutil.Account(ctxh) assert.NoError(t, err) sr := utils.RandomSlice(32) - keys := self.Keys[identity.KeyPurposeSigning] - sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + sig, err := self.SignMsg(sr) + assert.NoError(t, err) // validation failed model := new(mockModel) @@ -293,11 +304,11 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { srv := &testingcommons.MockIdentityService{} dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - self, err := contextutil.Self(ctxh) + self, err := contextutil.Account(ctxh) assert.NoError(t, err) sr := utils.RandomSlice(32) - keys := self.Keys[identity.KeyPurposeSigning] - sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + sig, err := self.SignMsg(sr) + assert.NoError(t, err) // validations failed id := utils.RandomSlice(32) @@ -348,11 +359,11 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { srv.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() dp := DefaultProcessor(srv, nil, nil, cfg).(defaultProcessor) ctxh := testingconfig.CreateAccountContext(t, cfg) - self, err := contextutil.Self(ctxh) + self, err := contextutil.Account(ctxh) assert.NoError(t, err) sr := utils.RandomSlice(32) - keys := self.Keys[identity.KeyPurposeSigning] - sig := crypto.Sign(self.ID[:], keys.PrivateKey, keys.PublicKey, sr) + sig, err := self.SignMsg(sr) + assert.NoError(t, err) // validations failed id := utils.RandomSlice(32) diff --git a/documents/read_acls.go b/documents/read_acls.go index 16ad1408f..ca59d76d8 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -354,7 +354,7 @@ func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID if err != nil { return err } - validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1, true) + validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1) if !validated { return errors.New("access token is invalid") } diff --git a/documents/service.go b/documents/service.go index c6bbc73d0..cb80165f6 100644 --- a/documents/service.go +++ b/documents/service.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" @@ -153,7 +152,7 @@ func (s service) CreateProofsForVersion(ctx context.Context, documentID, version } func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*coredocumentpb.Signature, error) { - idConf, err := contextutil.Self(ctx) + acc, err := contextutil.Account(ctx) if err != nil { return nil, ErrDocumentConfigAccountID } @@ -168,15 +167,18 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co } srvLog.Infof("document received %x with signing root %x", model.ID(), sr) - idKeys, ok := idConf.Keys[identity.KeyPurposeSigning] - if !ok { - return nil, errors.NewTypedError(ErrDocumentSigning, errors.New("missing signing key")) + + tenantID, err := acc.GetIdentityID() + if err != nil { + return nil, err } - sig := crypto.Sign(idConf.ID[:], idKeys.PrivateKey, idKeys.PublicKey, sr) + sig, err := acc.SignMsg(sr) + if err != nil { + return nil, err + } model.AppendSignatures(sig) - tenantID := idConf.ID[:] // Logic for receiving version n (n > 1) of the document for the first time // TODO(ved): we should not save the new model with old identifier. We should sync from the peer. if !s.repo.Exists(tenantID, model.ID()) && !utils.IsSameByteSlice(model.ID(), model.CurrentVersion()) { @@ -196,16 +198,25 @@ func (s service) RequestDocumentSignature(ctx context.Context, model Model) (*co } func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, senderID []byte) error { - idConf, err := contextutil.Self(ctx) + acc, err := contextutil.Account(ctx) if err != nil { return ErrDocumentConfigAccountID } + idBytes, err := acc.GetIdentityID() + if err != nil { + return err + } + did := identity.NewDIDFromBytes(idBytes) + if model == nil { + return errors.New("no model given") + } + if err := PostAnchoredValidator(s.idService, s.anchorRepository).Validate(nil, model); err != nil { return errors.NewTypedError(ErrDocumentInvalid, err) } - err = s.repo.Update(idConf.ID[:], model.CurrentVersion(), model) + err = s.repo.Update(did[:], model.CurrentVersion(), model) if err != nil { return errors.NewTypedError(ErrDocumentPersistence, err) } @@ -213,9 +224,9 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende ts, _ := ptypes.TimestampProto(time.Now().UTC()) notificationMsg := ¬ificationpb.NotificationMessage{ EventType: uint32(notification.ReceivedPayload), - AccountId: idConf.ID.String(), + AccountId: did.String(), FromId: hexutil.Encode(senderID), - ToId: idConf.ID.String(), + ToId: did.String(), Recorded: ts, DocumentType: model.DocumentType(), DocumentId: hexutil.Encode(model.ID()), @@ -228,19 +239,27 @@ func (s service) ReceiveAnchoredDocument(ctx context.Context, model Model, sende } func (s service) Exists(ctx context.Context, documentID []byte) bool { - idConf, err := contextutil.Self(ctx) + acc, err := contextutil.Account(ctx) + if err != nil { + return false + } + idBytes, err := acc.GetIdentityID() if err != nil { return false } - return s.repo.Exists(idConf.ID[:], documentID) + return s.repo.Exists(idBytes, documentID) } func (s service) getVersion(ctx context.Context, documentID, version []byte) (Model, error) { - idConf, err := contextutil.Self(ctx) + acc, err := contextutil.Account(ctx) if err != nil { return nil, ErrDocumentConfigAccountID } - model, err := s.repo.Get(idConf.ID[:], version) + idBytes, err := acc.GetIdentityID() + if err != nil { + return nil, err + } + model, err := s.repo.Get(idBytes, version) if err != nil { return nil, errors.NewTypedError(ErrDocumentVersionNotFound, err) } diff --git a/documents/validator.go b/documents/validator.go index 38c69a04e..d9afccd5c 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -2,7 +2,6 @@ package documents import ( "github.com/centrifuge/go-centrifuge/anchors" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" @@ -163,40 +162,6 @@ func documentRootValidator() Validator { }) } -// readyForSignaturesValidator validates self signature -// re-calculates the signature and compares with existing one -// assumes signing_root is already generated and verified -// Note: this needs to used only before document is sent for signatures from the collaborators -func readyForSignaturesValidator(id, priv, pub []byte) Validator { - return ValidatorFunc(func(_, model Model) error { - sr, err := model.CalculateSigningRoot() - if err != nil { - return errors.New("failed to generate signing root: %v", err) - } - - signatures := model.Signatures() - if len(signatures) != 1 { - return errors.New("expecting only one signature") - } - - s := crypto.Sign(id, priv, pub, sr) - sh := signatures[0] - if !utils.IsSameByteSlice(s.EntityId, sh.EntityId) { - err = errors.AppendError(err, errors.New("entity ID mismatch")) - } - - if !utils.IsSameByteSlice(s.PublicKey, sh.PublicKey) { - err = errors.AppendError(err, errors.New("public key mismatch")) - } - - if !utils.IsSameByteSlice(s.Signature, sh.Signature) { - err = errors.AppendError(err, errors.New("signature mismatch")) - } - - return err - }) -} - // signaturesValidator validates all the signatures in the core document // assumes signing root is verified // Note: can be used when during the signature request on collaborator side and post signature collection on sender side @@ -262,7 +227,7 @@ func anchoredValidator(repo anchors.AnchorRepository) Validator { // signatures validator // should be used when node receives a document requesting for signature func SignatureRequestValidator(idService identity.ServiceDID) ValidatorGroup { - return PostSignatureRequestValidator(idService) + return SignatureValidator(idService) } // PreAnchorValidator is a validator group with following validators @@ -273,7 +238,7 @@ func SignatureRequestValidator(idService identity.ServiceDID) ValidatorGroup { // should be called before pre anchoring func PreAnchorValidator(idService identity.ServiceDID) ValidatorGroup { return ValidatorGroup{ - PostSignatureRequestValidator(idService), + SignatureValidator(idService), documentRootValidator(), } } @@ -289,25 +254,12 @@ func PostAnchoredValidator(idService identity.ServiceDID, repo anchors.AnchorRep } } -// PreSignatureRequestValidator is a validator group with following validators -// baseValidator -// signingRootValidator -// readyForSignaturesValidator -// should be called after sender signing the document and before requesting the document -func PreSignatureRequestValidator(id, priv, pub []byte) ValidatorGroup { - return ValidatorGroup{ - baseValidator(), - signingRootValidator(), - readyForSignaturesValidator(id, priv, pub), - } -} - -// PostSignatureRequestValidator is a validator group with following validators +// SignatureValidator is a validator group with following validators // baseValidator // signingRootValidator // signaturesValidator -// should be called after the signature collection/before preparing for anchoring -func PostSignatureRequestValidator(idService identity.ServiceDID) ValidatorGroup { +// should be called after sender signing the document, before requesting the document and after signature collection +func SignatureValidator(idService identity.ServiceDID) ValidatorGroup { return ValidatorGroup{ baseValidator(), signingRootValidator(), diff --git a/documents/validator_test.go b/documents/validator_test.go index 7bfdfc3a1..bc8509e71 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -5,11 +5,12 @@ package documents import ( "testing" + "github.com/stretchr/testify/mock" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" @@ -241,30 +242,35 @@ func TestValidator_documentRootValidator(t *testing.T) { model.AssertExpectations(t) } -func TestValidator_selfSignatureValidator(t *testing.T) { - account, _ := contextutil.Account(testingconfig.CreateAccountContext(t, cfg)) - keys, err := account.GetKeys() - assert.Nil(t, err) - accID, err := account.GetIdentityID() +func TestValidator_SignatureValidator(t *testing.T) { + account, err := contextutil.Account(testingconfig.CreateAccountContext(t, cfg)) assert.NoError(t, err) - rfsv := readyForSignaturesValidator(accID, keys[identity.KeyPurposeSigning].PrivateKey, keys[identity.KeyPurposeSigning].PublicKey) + idService := new(testingcommons.MockIdentityService) + sv := SignatureValidator(idService) // fail to get signing root model := new(mockModel) - model.On("CalculateSigningRoot").Return(nil, errors.New("error")).Once() - err = rfsv.Validate(nil, model) + model.On("ID").Return(utils.RandomSlice(32)) + model.On("CurrentVersion").Return(utils.RandomSlice(32)) + model.On("NextVersion").Return(utils.RandomSlice(32)) + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil) + model.On("CalculateSigningRoot").Return(nil, errors.New("error")) + err = sv.Validate(nil, model) assert.Error(t, err) model.AssertExpectations(t) // signature length mismatch sr := utils.RandomSlice(32) model = new(mockModel) - model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("ID").Return(utils.RandomSlice(32)) + model.On("CurrentVersion").Return(utils.RandomSlice(32)) + model.On("NextVersion").Return(utils.RandomSlice(32)) + model.On("CalculateSigningRoot").Return(sr, nil) model.On("Signatures").Return().Once() - err = rfsv.Validate(nil, model) + err = sv.Validate(nil, model) assert.Error(t, err) model.AssertExpectations(t) - assert.Contains(t, err.Error(), "expecting only one signature") + assert.Contains(t, err.Error(), "atleast one signature expected") // mismatch s := &coredocumentpb.Signature{ @@ -272,24 +278,34 @@ func TestValidator_selfSignatureValidator(t *testing.T) { EntityId: utils.RandomSlice(6), PublicKey: utils.RandomSlice(32), } + + idService = new(testingcommons.MockIdentityService) + sv = SignatureValidator(idService) model = new(mockModel) - model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("ID").Return(utils.RandomSlice(32)) + model.On("CurrentVersion").Return(utils.RandomSlice(32)) + model.On("NextVersion").Return(utils.RandomSlice(32)) + model.On("CalculateSigningRoot").Return(sr, nil) + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(errors.New("invalid signature")).Once() model.On("Signatures").Return().Once() model.sigs = append(model.sigs, s) - err = rfsv.Validate(nil, model) + err = sv.Validate(nil, model) model.AssertExpectations(t) assert.Error(t, err) - assert.Equal(t, 3, errors.Len(err)) + assert.Equal(t, 1, errors.Len(err)) // success - c, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - s = identity.Sign(c, identity.KeyPurposeSigning, sr) + s, err = account.SignMsg(sr) + assert.NoError(t, err) model = new(mockModel) - model.On("CalculateSigningRoot").Return(sr, nil).Once() + model.On("ID").Return(utils.RandomSlice(32)) + model.On("CurrentVersion").Return(utils.RandomSlice(32)) + model.On("NextVersion").Return(utils.RandomSlice(32)) + model.On("CalculateSigningRoot").Return(sr, nil) + idService.On("ValidateSignature", mock.Anything, mock.Anything).Return(nil).Once() model.On("Signatures").Return().Once() model.sigs = append(model.sigs, s) - err = rfsv.Validate(nil, model) + err = sv.Validate(nil, model) model.AssertExpectations(t) assert.NoError(t, err) } @@ -429,18 +445,6 @@ func TestPostAnchoredValidator(t *testing.T) { assert.Len(t, pav, 2) } -func TestPreSignatureRequestValidator(t *testing.T) { - self, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) - idKeys := self.Keys[identity.KeyPurposeSigning] - psv := PreSignatureRequestValidator(self.ID[:], idKeys.PrivateKey, idKeys.PublicKey) - assert.Len(t, psv, 3) -} - -func TestPostSignatureRequestValidator(t *testing.T) { - psv := PostSignatureRequestValidator(nil) - assert.Len(t, psv, 3) -} - func TestSignatureRequestValidator(t *testing.T) { srv := SignatureRequestValidator(nil) assert.Len(t, srv, 3) diff --git a/identity/did.go b/identity/did.go index 9fe0fc0f0..646173709 100644 --- a/identity/did.go +++ b/identity/did.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" @@ -284,14 +283,15 @@ func GetIdentityConfig(config Config) (*IDConfig, error) { } keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} - pk, sk, err = ed25519.GetSigningKeyPair(config.GetSigningKeyPair()) + pk, sk, err = secp256k1.GetSigningKeyPair(config.GetSigningKeyPair()) if err != nil { return nil, err } - keys[KeyPurposeSigning] = IDKey{PublicKey: pk, PrivateKey: sk} + pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + keys[KeyPurposeSigning] = IDKey{PublicKey: pk32[:], PrivateKey: sk} //secp256k1 keys - pk, sk, err = secp256k1.GetEthAuthKey(config.GetEthAuthKeyPair()) + pk, sk, err = secp256k1.GetSigningKeyPair(config.GetEthAuthKeyPair()) if err != nil { return nil, err } @@ -303,10 +303,3 @@ func GetIdentityConfig(config Config) (*IDConfig, error) { return &IDConfig{ID: centID, Keys: keys}, nil } - -// Sign the document with the private key and return the signature along with the public key for the verification -// assumes that signing root for the document is generated -// Deprecated -func Sign(idConfig *IDConfig, purpose int, payload []byte) *coredocumentpb.Signature { - return crypto.Sign(idConfig.ID[:], idConfig.Keys[purpose].PrivateKey, idConfig.Keys[purpose].PublicKey, payload) -} diff --git a/identity/ideth/service.go b/identity/ideth/service.go index fdbac96ea..668d839c3 100644 --- a/identity/ideth/service.go +++ b/identity/ideth/service.go @@ -397,25 +397,22 @@ func getKeyPairsFromAccount(acc config.Account) (map[int]id.KeyDID, error) { } keys[id.KeyPurposeP2P] = id.NewKey(pk32, big.NewInt(id.KeyPurposeP2P), big.NewInt(id.KeyTypeECDSA)) + // secp256k1 keys // KeyPurposeSigning - pk, _, err = ed25519.GetSigningKeyPair(acc.GetSigningKeyPair()) + pk, _, err = secp256k1.GetSigningKeyPair(acc.GetSigningKeyPair()) if err != nil { return nil, err } - pk32, err = utils.SliceToByte32(pk) - if err != nil { - return nil, err - } - keys[id.KeyPurposeSigning] = id.NewKey(pk32, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + keys[id.KeyPurposeSigning] = id.NewKey(address32Bytes, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) - // secp256k1 keys // KeyPurposeEthMsgAuth - pk, _, err = secp256k1.GetEthAuthKey(acc.GetEthAuthKeyPair()) + pk, _, err = secp256k1.GetSigningKeyPair(acc.GetEthAuthKeyPair()) if err != nil { return nil, err } - address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + address32Bytes = utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) keys[id.KeyPurposeEthMsgAuth] = id.NewKey(address32Bytes, big.NewInt(id.KeyPurposeEthMsgAuth), big.NewInt(id.KeyTypeECDSA)) return keys, nil @@ -458,7 +455,11 @@ func (i service) ValidateSignature(signature *coredocumentpb.Signature, message return err } - return crypto.VerifySignature(signature.PublicKey, message, signature.Signature) + if !crypto.VerifyMessage(signature.PublicKey, message, signature.Signature, crypto.CurveSecp256K1) { + return errors.New("error when validating signature") + } + + return nil } // ValidateCentrifugeIDBytes validates a centrifuge ID given as bytes diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 6878fbf3a..43b8928c3 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -7,6 +7,10 @@ import ( "flag" "os" "testing" + "time" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -134,7 +138,14 @@ func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) document assert.NoError(t, err) sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) + s, err := crypto.SignMessage(idConfig.Keys[identity.KeyPurposeSigning].PrivateKey, sr, crypto.CurveSecp256K1) + assert.NoError(t, err) + sig := &coredocumentpb.Signature{ + EntityId: idConfig.ID[:], + PublicKey: idConfig.Keys[identity.KeyPurposeSigning].PublicKey, + Signature: s, + Timestamp: utils.ToTimestamp(time.Now().UTC()), + } po.AppendSignatures(sig) _, err = po.CalculateDocumentRoot() assert.NoError(t, err) diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index f03173788..90ad0bbfe 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -8,10 +8,17 @@ import ( "math/big" "os" "testing" + "time" - "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/crypto/secp256k1" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" + + "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/ethereum/go-ethereum/common" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" @@ -31,7 +38,6 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" - "golang.org/x/crypto/ed25519" ) var ( @@ -97,7 +103,7 @@ func TestHandler_HandleInterceptorReqSignature(t *testing.T) { resp := resolveSignatureResponse(t, p2pResp) assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, secp256k1.VerifySignatureWithAddress(common.BytesToAddress(sig.PublicKey).String(), hexutil.Encode(sig.Signature), cd.SigningRoot), "signature must be valid") } func TestHandler_RequestDocumentSignature_AlreadyExists(t *testing.T) { @@ -120,8 +126,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") - + assert.True(t, secp256k1.VerifySignatureWithAddress(common.BytesToAddress(sig.PublicKey).String(), hexutil.Encode(sig.Signature), cd.SigningRoot), "signature must be valid") //Update document po, cd = updateDocumentForP2Phandler(t, po) resp, err = handler.RequestDocumentSignature(ctxh, &p2ppb.SignatureRequest{Document: &cd}) @@ -129,7 +134,7 @@ func TestHandler_RequestDocumentSignature_UpdateSucceeds(t *testing.T) { assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig = resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, secp256k1.VerifySignatureWithAddress(common.BytesToAddress(sig.PublicKey).String(), hexutil.Encode(sig.Signature), cd.SigningRoot), "signature must be valid") } func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T) { @@ -142,7 +147,7 @@ func TestHandler_RequestDocumentSignatureFirstTimeOnUpdatedDocument(t *testing.T assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, secp256k1.VerifySignatureWithAddress(common.BytesToAddress(sig.PublicKey).String(), hexutil.Encode(sig.Signature), cd.SigningRoot), "signature must be valid") } func TestHandler_RequestDocumentSignature(t *testing.T) { @@ -153,7 +158,7 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { assert.NotNil(t, resp, "must be non nil") assert.NotNil(t, resp.Signature.Signature, "must be non nil") sig := resp.Signature - assert.True(t, ed25519.Verify(sig.PublicKey, cd.SigningRoot, sig.Signature), "signature must be valid") + assert.True(t, secp256k1.VerifySignatureWithAddress(common.BytesToAddress(sig.PublicKey).String(), hexutil.Encode(sig.Signature), cd.SigningRoot), "signature must be valid") } func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { @@ -275,7 +280,14 @@ func prepareDocumentForP2PHandler(t *testing.T, po *purchaseorder.PurchaseOrder) assert.NoError(t, err) sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - sig := identity.Sign(idConfig, identity.KeyPurposeSigning, sr) + s, err := crypto.SignMessage(idConfig.Keys[identity.KeyPurposeSigning].PrivateKey, sr, crypto.CurveSecp256K1) + assert.NoError(t, err) + sig := &coredocumentpb.Signature{ + EntityId: idConfig.ID[:], + PublicKey: idConfig.Keys[identity.KeyPurposeSigning].PublicKey, + Signature: s, + Timestamp: utils.ToTimestamp(time.Now().UTC()), + } po.AppendSignatures(sig) _, err = po.CalculateDocumentRoot() assert.NoError(t, err) diff --git a/resources/data.go b/resources/data.go index 8b5531a3c..a2581ff81 100644 --- a/resources/data.go +++ b/resources/data.go @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1551090705, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1551103801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1165, mode: os.FileMode(420), modTime: time.Unix(1551084552, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1165, mode: os.FileMode(420), modTime: time.Unix(1551103801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From 5d8ca0620d05d98ad0345c81a2f77482c2a40075 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Thu, 28 Feb 2019 12:25:29 +0100 Subject: [PATCH 206/220] remove collaborators from core doc (#785) This removes collaborators for the core document Changes: - Added `GetSignCollaborators` which should be used to get collaborators with sign permission. Ex: while requesting for signatures - `GetCollaborators` will return collaborators with Read and Read_sign. Fixes #679 and Fixes #680 --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- anchors/service_test.go | 2 +- documents/coredocument.go | 98 ++++++++------- documents/coredocument_test.go | 171 ++++++++++++++++++++------ documents/invoice/model_test.go | 16 ++- documents/model.go | 4 + documents/processor.go | 2 +- documents/processor_test.go | 14 ++- documents/purchaseorder/model_test.go | 17 ++- documents/read_acls.go | 29 ++--- documents/read_acls_test.go | 2 +- identity/did.go | 5 - p2p/client.go | 2 +- 14 files changed, 239 insertions(+), 129 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 4764a9e9a..d0e3b58f3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" [[projects]] - digest = "1:3dfab93e13cbc54458ddd94ac88c0f01eb724b28a7dd3eef5923903d1fe71cef" + digest = "1:94366a6a33e0dbcfa2bdf4cffe474e66b517e7863662e2fb87f28e3cd6289409" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "3e3292cf89ce246d64863fa28ac1f4cb4e57dd3e" + revision = "1bc057399d5d3658f8cd357b0ce22663de7c1ce8" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 6b3c9812d..b3a3d0ee8 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "3e3292cf89ce246d64863fa28ac1f4cb4e57dd3e" + revision = "1bc057399d5d3658f8cd357b0ce22663de7c1ce8" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/anchors/service_test.go b/anchors/service_test.go index 484403a03..bcb11758b 100644 --- a/anchors/service_test.go +++ b/anchors/service_test.go @@ -45,7 +45,7 @@ func TestCorrectCommitSignatureGen(t *testing.T) { correctCommitSignature := "0x4a73286521114f528967674bae4ecdc6cc94789255495429a7f58ca3ef0158ae257dd02a0ccb71d817e480d06f60f640ec021ade2ff90fe601bb7a5f4ddc569700" testPrivateKey, _ := hexutil.Decode("0x17e063fa17dd8274b09c14b253697d9a20afff74ace3c04fdb1b9c814ce0ada5") anchorIDTyped, _ := ToAnchorID(anchorID) - centIdTyped := identity.NewDIDFromByte(address) + centIdTyped := identity.NewDIDFromBytes(address) docRootTyped, _ := ToDocumentRoot(documentRoot) messageToSign := GenerateCommitHash(anchorIDTyped, centIdTyped, docRootTyped) assert.Equal(t, correctCommitToSign, hexutil.Encode(messageToSign), "messageToSign not calculated correctly") diff --git a/documents/coredocument.go b/documents/coredocument.go index 095c0996f..153f713ff 100644 --- a/documents/coredocument.go +++ b/documents/coredocument.go @@ -14,7 +14,6 @@ import ( "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" - "github.com/ethereum/go-ethereum/common/hexutil" ) const ( @@ -96,10 +95,6 @@ func NewCoreDocumentWithCollaborators(collaborators []string) (*CoreDocument, er return nil, errors.New("failed to decode collaborators: %v", err) } - for i := range ids { - cd.Document.Collaborators = append(cd.Document.Collaborators, ids[i][:]) - } - cd.initReadRules(ids) if err := cd.setSalts(); err != nil { return nil, err @@ -155,30 +150,30 @@ func (cd *CoreDocument) setSalts() error { } // PrepareNewVersion prepares the next version of the CoreDocument -// Note: salts needs to be filled by the caller +// if initSalts is true, salts will be generated for new version. func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool) (*CoreDocument, error) { if len(cd.Document.DocumentRoot) != idSize { return nil, errors.New("Document root is invalid") } - ucs, err := fetchNewUniqueCollaborators(cd.Document.Collaborators, collaborators) + cs, err := identity.NewDIDsFromStrings(collaborators) if err != nil { - return nil, errors.New("failed to fetch new collaborators: %v", err) + return nil, err } - cs := cd.Document.Collaborators - for _, c := range ucs { - c := c - cs = append(cs, c[:]) + // get all the old collaborators + oldCs, err := cd.GetCollaborators() + if err != nil { + return nil, err } + ucs := filterCollaborators(cs, oldCs...) cdp := coredocumentpb.CoreDocument{ DocumentIdentifier: cd.Document.DocumentIdentifier, PreviousVersion: cd.Document.CurrentVersion, CurrentVersion: cd.Document.NextVersion, NextVersion: utils.RandomSlice(32), PreviousRoot: cd.Document.DocumentRoot, - Collaborators: cs, Roles: cd.Document.Roles, ReadRules: cd.Document.ReadRules, Nfts: cd.Document.Nfts, @@ -428,53 +423,68 @@ func (cd *CoreDocument) documentTree(docType string) (tree *proofs.DocumentTree, } -// GetCollaborators returns the collaborators from the role with READ_SIGN ability. -func (cd *CoreDocument) GetCollaborators(filterIDs ...identity.DID) (ids []identity.DID, err error) { - exclude := make(map[string]struct{}) - for _, id := range filterIDs { - exclude[id.String()] = struct{}{} +// GetSignerCollaborators returns the collaborators excluding the filteredIDs +// returns collaborators with Read_Sign permissions. +func (cd *CoreDocument) GetSignerCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) { + cs, err := cd.getCollaborators(coredocumentpb.Action_ACTION_READ_SIGN) + if err != nil { + return nil, err } - for _, c := range cd.Document.Collaborators { - id := identity.NewDIDFromBytes(c) - if _, ok := exclude[id.String()]; ok { - continue - } + return filterCollaborators(cs, filterIDs...), nil +} - ids = append(ids, id) +// GetCollaborators returns the collaborators excluding the filteredIDs +// returns collaborators with Read and Read_Sign permissions. +func (cd *CoreDocument) GetCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) { + cs, err := cd.getCollaborators(coredocumentpb.Action_ACTION_READ_SIGN, coredocumentpb.Action_ACTION_READ) + if err != nil { + return nil, err } - return ids, nil + return filterCollaborators(cs, filterIDs...), nil } -// fetchNewUniqueCollaborators returns the unique collaborators from newCollabs in reference to oldCollabs. -func fetchNewUniqueCollaborators(oldCollabs [][]byte, newCollabs []string) (ids []identity.DID, err error) { - ocsm := make(map[string]struct{}) - for _, c := range oldCollabs { - cs := strings.ToLower(hexutil.Encode(c)) - ocsm[cs] = struct{}{} - } +// getCollaborators returns all the collaborators who belongs to the actions passed. +func (cd *CoreDocument) getCollaborators(actions ...coredocumentpb.Action) (ids []identity.DID, err error) { + findRole(cd.Document, func(_, _ int, role *coredocumentpb.Role) bool { + if len(role.Collaborators) < 1 { + return false + } - var uc []string - for _, c := range newCollabs { - cs := strings.ToLower(c) - if _, ok := ocsm[cs]; ok { - continue + for _, c := range role.Collaborators { + // TODO(ved): we should ideally check the address length of 20 + // we will still keep the error return to the function so that once check is in, we don't have to refactor this function + ids = append(ids, identity.NewDIDFromBytes(c)) } - uc = append(uc, c) + return false + }, actions...) + + if err != nil { + return nil, err } - for _, c := range uc { - id, err := identity.NewDIDFromString(c) - if err != nil { - return nil, err + return ids, nil +} + +// filterCollaborators removes the filterIDs if any from cs and returns the result +func filterCollaborators(cs []identity.DID, filterIDs ...identity.DID) (filteredIDs []identity.DID) { + filter := make(map[string]struct{}) + for _, c := range filterIDs { + cs := strings.ToLower(c.String()) + filter[cs] = struct{}{} + } + + for _, id := range cs { + if _, ok := filter[strings.ToLower(id.String())]; ok { + continue } - ids = append(ids, id) + filteredIDs = append(filteredIDs, id) } - return ids, nil + return filteredIDs } // CalculateDocumentRoot calculates the Document root of the core Document. diff --git a/documents/coredocument_test.go b/documents/coredocument_test.go index d1a2e3d52..068f364bb 100644 --- a/documents/coredocument_test.go +++ b/documents/coredocument_test.go @@ -7,19 +7,20 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testlogging" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" + "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/storage/leveldb" "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions/txv1" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" @@ -68,49 +69,41 @@ func Test_fetchUniqueCollaborators(t *testing.T) { o2 := testingidentity.GenerateRandomDID() n1 := testingidentity.GenerateRandomDID() tests := []struct { - old [][]byte - new []string + old []identity.DID + new []identity.DID result []identity.DID - err bool }{ + // when old cs are nil { - new: []string{n1.String()}, - result: []identity.DID{n1}, + new: []identity.DID{n1}, }, { - old: [][]byte{o1[:]}, - new: []string{n1.String()}, - result: []identity.DID{n1}, + old: []identity.DID{o1, o2}, + result: []identity.DID{o1, o2}, }, { - old: [][]byte{o1[:], n1[:]}, - new: []string{n1.String()}, + old: []identity.DID{o1}, + new: []identity.DID{n1}, + result: []identity.DID{o1}, }, { - old: [][]byte{o1[:], o2[:]}, + old: []identity.DID{o1, n1}, + new: []identity.DID{n1}, + result: []identity.DID{o1}, }, - // new collaborator with wrong format { - old: [][]byte{o1[:], o2[:]}, - new: []string{"0x0102030405"}, - err: true, + old: []identity.DID{o1, n1}, + new: []identity.DID{o2}, + result: []identity.DID{o1, n1}, }, } for _, c := range tests { - uc, err := fetchNewUniqueCollaborators(c.old, c.new) - if err != nil { - if c.err { - continue - } - - t.Fatal(err) - } - + uc := filterCollaborators(c.old, c.new...) assert.Equal(t, c.result, uc) } } @@ -118,32 +111,42 @@ func Test_fetchUniqueCollaborators(t *testing.T) { func TestCoreDocument_PrepareNewVersion(t *testing.T) { cd := newCoreDocument() - //collaborators need to be hex string - collabs := []string{"some ID"} - ncd, err := cd.PrepareNewVersion(collabs, false) - assert.Error(t, err) - assert.Nil(t, ncd) - // missing DocumentRoot c1 := testingidentity.GenerateRandomDID() c2 := testingidentity.GenerateRandomDID() c := []string{c1.String(), c2.String()} - ncd, err = cd.PrepareNewVersion(c, false) + ncd, err := cd.PrepareNewVersion(c, false) assert.Error(t, err) + assert.Contains(t, err.Error(), "Document root is invalid") assert.Nil(t, ncd) - // successful preparation of new version upon addition of DocumentRoot + //collaborators need to be hex string cd.Document.DocumentRoot = utils.RandomSlice(32) + collabs := []string{"some ID"} + ncd, err = cd.PrepareNewVersion(collabs, false) + assert.Error(t, err) + assert.True(t, errors.IsOfType(identity.ErrMalformedAddress, err)) + assert.Nil(t, ncd) + + // successful preparation of new version upon addition of DocumentRoot ncd, err = cd.PrepareNewVersion(c, false) assert.NoError(t, err) assert.NotNil(t, ncd) - assert.Len(t, ncd.Document.Collaborators, 2) + cs, err := ncd.GetCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 2) + assert.Contains(t, cs, c1) + assert.Contains(t, cs, c2) assert.Nil(t, ncd.Document.CoredocumentSalts) ncd, err = cd.PrepareNewVersion(c, true) assert.NoError(t, err) assert.NotNil(t, ncd) - assert.Len(t, ncd.Document.Collaborators, 2) + cs, err = ncd.GetCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 2) + assert.Contains(t, cs, c1) + assert.Contains(t, cs, c2) assert.NotNil(t, ncd.Document.CoredocumentSalts) assert.Equal(t, cd.Document.NextVersion, ncd.Document.CurrentVersion) @@ -236,7 +239,6 @@ func TestCoreDocument_GenerateProofs(t *testing.T) { cd := newCoreDocument() cd.Document.EmbeddedData = docAny - cd.Document.Collaborators = [][]byte{utils.RandomSlice(32), utils.RandomSlice(32)} assert.NoError(t, cd.setSalts()) cd.Document.DataRoot = testTree.RootHash() _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) @@ -267,7 +269,7 @@ func TestCoreDocument_GenerateProofs(t *testing.T) { 3, }, { - CDTreePrefix + ".collaborators[0]", + CDTreePrefix + ".next_version", true, 6, }, @@ -306,3 +308,96 @@ func TestCoreDocument_setSalts(t *testing.T) { assert.Nil(t, cd.setSalts()) assert.Equal(t, salts, cd.Document.CoredocumentSalts) } + +func TestCoreDocument_getCollaborators(t *testing.T) { + id1 := testingidentity.GenerateRandomDID() + id2 := testingidentity.GenerateRandomDID() + ids := []string{id1.String()} + cd, err := NewCoreDocumentWithCollaborators(ids) + assert.NoError(t, err) + cs, err := cd.getCollaborators(coredocumentpb.Action_ACTION_READ_SIGN) + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Equal(t, cs[0], id1) + + cs, err = cd.getCollaborators(coredocumentpb.Action_ACTION_READ) + assert.NoError(t, err) + assert.Len(t, cs, 0) + + role := newRole() + role.Collaborators = append(role.Collaborators, id2[:]) + cd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + + cs, err = cd.getCollaborators(coredocumentpb.Action_ACTION_READ) + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Equal(t, cs[0], id2) + + cs, err = cd.getCollaborators(coredocumentpb.Action_ACTION_READ, coredocumentpb.Action_ACTION_READ_SIGN) + assert.NoError(t, err) + assert.Len(t, cs, 2) + assert.Contains(t, cs, id1) + assert.Contains(t, cs, id2) +} + +func TestCoreDocument_GetCollaborators(t *testing.T) { + id1 := testingidentity.GenerateRandomDID() + id2 := testingidentity.GenerateRandomDID() + ids := []string{id1.String()} + cd, err := NewCoreDocumentWithCollaborators(ids) + assert.NoError(t, err) + cs, err := cd.GetCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Equal(t, cs[0], id1) + + cs, err = cd.GetCollaborators(id1) + assert.NoError(t, err) + assert.Len(t, cs, 0) + + role := newRole() + role.Collaborators = append(role.Collaborators, id2[:]) + cd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + + cs, err = cd.GetCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 2) + assert.Contains(t, cs, id1) + assert.Contains(t, cs, id2) + + cs, err = cd.GetCollaborators(id2) + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Contains(t, cs, id1) +} + +func TestCoreDocument_GetSignCollaborators(t *testing.T) { + id1 := testingidentity.GenerateRandomDID() + id2 := testingidentity.GenerateRandomDID() + ids := []string{id1.String()} + cd, err := NewCoreDocumentWithCollaborators(ids) + assert.NoError(t, err) + cs, err := cd.GetSignerCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Equal(t, cs[0], id1) + + cs, err = cd.GetSignerCollaborators(id1) + assert.NoError(t, err) + assert.Len(t, cs, 0) + + role := newRole() + role.Collaborators = append(role.Collaborators, id2[:]) + cd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + + cs, err = cd.GetSignerCollaborators() + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Contains(t, cs, id1) + assert.NotContains(t, cs, id2) + + cs, err = cd.GetSignerCollaborators(id2) + assert.NoError(t, err) + assert.Len(t, cs, 1) + assert.Contains(t, cs, id1) +} diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index f18f35842..8f10cb173 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -4,6 +4,7 @@ package invoice import ( "encoding/json" + "fmt" "os" "testing" @@ -40,6 +41,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration var configService config.Service +var defaultDID = testingidentity.GenerateRandomDID() func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -228,10 +230,12 @@ func TestInvoiceModel_calculateDataRoot(t *testing.T) { assert.NotNil(t, m.InvoiceSalts, "salts must be created") } -func TestInvoice_GenerateProofs(t *testing.T) { +func TestInvoice_CreateProofs(t *testing.T) { i, err := createInvoice(t) assert.Nil(t, err) - proof, err := i.CreateProofs([]string{"invoice.invoice_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) + rk := i.Document.Roles[0].RoleKey + pf := fmt.Sprintf(documents.CDTreePrefix+".roles[%s].collaborators[0]", hexutil.Encode(rk)) + proof, err := i.CreateProofs([]string{"invoice.invoice_number", pf, documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) tree, err := i.CoreDocument.DocumentRootTree() @@ -242,14 +246,14 @@ func TestInvoice_GenerateProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) - // Validate collaborators[0] + // Validate roles valid, err = tree.ValidateProof(proof[1]) assert.Nil(t, err) assert.True(t, valid) // Validate []byte value - id := identity.NewDIDFromBytes(proof[1].Value) - assert.True(t, i.CoreDocument.AccountCanRead(id)) + acc := identity.NewDIDFromBytes(proof[1].Value) + assert.True(t, i.AccountCanRead(acc)) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -281,7 +285,7 @@ func TestInvoiceModel_getDocumentDataTree(t *testing.T) { func createInvoice(t *testing.T) (*Invoice, error) { i := new(Invoice) - err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), "0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + err := i.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), defaultDID.String()) assert.NoError(t, err) _, err = i.CalculateDataRoot() assert.NoError(t, err) diff --git a/documents/model.go b/documents/model.go index a1137b26c..f3adde943 100644 --- a/documents/model.go +++ b/documents/model.go @@ -73,8 +73,12 @@ type Model interface { // GetCollaborators returns the collaborators of this Document. // filter ids should not be returned + // Note: returns all the collaborators with Read and Read_Sign permission GetCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) + // GetSignerCollaborators works like GetCollaborators except it returns only those with Read_Sign permission. + GetSignerCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) + // AccountCanRead returns true if the account can read the document AccountCanRead(account identity.DID) bool diff --git a/documents/processor.go b/documents/processor.go index 54e770408..a12439b29 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -173,7 +173,7 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error return err } - cs, err := model.GetCollaborators(self.ID) + cs, err := model.GetSignerCollaborators(self.ID) if err != nil { return errors.New("get external collaborators failed: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index bc03e2ffa..799355443 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -95,6 +95,12 @@ func (m *mockModel) GetCollaborators(filterIDs ...identity.DID) ([]identity.DID, return cids, args.Error(1) } +func (m *mockModel) GetSignerCollaborators(filterIDs ...identity.DID) ([]identity.DID, error) { + args := m.Called(filterIDs) + cids, _ := args.Get(0).([]identity.DID) + return cids, args.Error(1) +} + func (m *mockModel) PackCoreDocument() (coredocumentpb.CoreDocument, error) { args := m.Called() cd, _ := args.Get(0).(coredocumentpb.CoreDocument) @@ -401,7 +407,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model.On("CalculateSigningRoot").Return(sr, nil) model.On("Signatures").Return() model.On("CalculateDocumentRoot").Return(dr[:], nil) - model.On("GetCollaborators", mock.Anything).Return(nil, errors.New("error")).Once() + model.On("GetSignerCollaborators", mock.Anything).Return(nil, errors.New("error")).Once() model.sigs = append(model.sigs, sig) srv = &testingcommons.MockIdentityService{} srv.On("ValidateSignature", sig, sr).Return(nil).Once() @@ -423,7 +429,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model.On("CalculateSigningRoot").Return(sr, nil) model.On("Signatures").Return() model.On("CalculateDocumentRoot").Return(dr[:], nil) - model.On("GetCollaborators", mock.Anything).Return([]identity.DID{testingidentity.GenerateRandomDID()}, nil).Once() + model.On("GetSignerCollaborators", mock.Anything).Return([]identity.DID{testingidentity.GenerateRandomDID()}, nil).Once() model.On("PackCoreDocument").Return(nil, errors.New("error")).Once() model.sigs = append(model.sigs, sig) srv = &testingcommons.MockIdentityService{} @@ -448,7 +454,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model.On("CalculateSigningRoot").Return(sr, nil) model.On("Signatures").Return() model.On("CalculateDocumentRoot").Return(dr[:], nil) - model.On("GetCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() + model.On("GetSignerCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() model.On("PackCoreDocument").Return(cd, nil).Once() model.sigs = append(model.sigs, sig) srv = &testingcommons.MockIdentityService{} @@ -475,7 +481,7 @@ func TestDefaultProcessor_SendDocument(t *testing.T) { model.On("CalculateSigningRoot").Return(sr, nil) model.On("Signatures").Return() model.On("CalculateDocumentRoot").Return(dr[:], nil) - model.On("GetCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() + model.On("GetSignerCollaborators", mock.Anything).Return([]identity.DID{did}, nil).Once() model.On("PackCoreDocument").Return(cd, nil).Once() model.sigs = append(model.sigs, sig) srv = &testingcommons.MockIdentityService{} diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index 6b6ad2d4b..dd465935b 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -4,6 +4,7 @@ package purchaseorder import ( "encoding/json" + "fmt" "os" "testing" @@ -27,6 +28,7 @@ import ( "github.com/centrifuge/go-centrifuge/testingutils/commons" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/testingutils/documents" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/testingutils/testingtx" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" @@ -39,6 +41,7 @@ import ( var ctx = map[string]interface{}{} var cfg config.Configuration var configService config.Service +var defaultDID = testingidentity.GenerateRandomDID() func TestMain(m *testing.M) { ethClient := &testingcommons.MockEthClient{} @@ -202,10 +205,12 @@ func TestPOModel_calculateDataRoot(t *testing.T) { assert.NotNil(t, poModel.PurchaseOrderSalts, "salts must be created") } -func TestPOModel_GenerateProofs(t *testing.T) { +func TestPOModel_CreateProofs(t *testing.T) { po := createPurchaseOrder(t) assert.NotNil(t, po) - proof, err := po.CreateProofs([]string{"po.po_number", documents.CDTreePrefix + ".collaborators[0]", documents.CDTreePrefix + ".document_type"}) + rk := po.Document.Roles[0].RoleKey + pf := fmt.Sprintf(documents.CDTreePrefix+".roles[%s].collaborators[0]", hexutil.Encode(rk)) + proof, err := po.CreateProofs([]string{"po.po_number", pf, documents.CDTreePrefix + ".document_type"}) assert.Nil(t, err) assert.NotNil(t, proof) tree, err := po.DocumentRootTree() @@ -216,14 +221,14 @@ func TestPOModel_GenerateProofs(t *testing.T) { assert.Nil(t, err) assert.True(t, valid) - // Validate collaborators[0] + // Validate roles collaborators valid, err = tree.ValidateProof(proof[1]) assert.Nil(t, err) assert.True(t, valid) // Validate []byte value - id := identity.NewDIDFromBytes(proof[1].Value) - assert.True(t, po.CoreDocument.AccountCanRead(id)) + acc := identity.NewDIDFromBytes(proof[1].Value) + assert.True(t, po.AccountCanRead(acc)) // Validate document_type valid, err = tree.ValidateProof(proof[2]) @@ -248,7 +253,7 @@ func TestPOModel_getDocumentDataTree(t *testing.T) { func createPurchaseOrder(t *testing.T) *PurchaseOrder { po := new(PurchaseOrder) - err := po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), "0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + err := po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), defaultDID.String()) assert.NoError(t, err) _, err = po.CalculateDataRoot() assert.NoError(t, err) diff --git a/documents/read_acls.go b/documents/read_acls.go index ca59d76d8..c60534a84 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -63,19 +63,6 @@ func findRole(cd coredocumentpb.CoreDocument, onRole func(rridx, ridx int, role return false } -// GetExternalCollaborators returns collaborators of a Document without the own centID. -func (cd *CoreDocument) GetExternalCollaborators(self identity.DID) ([][]byte, error) { - var cs [][]byte - for _, c := range cd.Document.Collaborators { - id := identity.NewDIDFromBytes(c) - if !self.Equal(id) { - cs = append(cs, c) - } - } - - return cs, nil -} - // NFTOwnerCanRead checks if the nft owner/account can read the Document func (cd *CoreDocument) NFTOwnerCanRead(tokenRegistry TokenRegistry, registry common.Address, tokenID []byte, account identity.DID) error { // check if the account can read the doc @@ -124,7 +111,7 @@ func (cd *CoreDocument) addNFTToReadRules(registry common.Address, tokenID []byt return errors.New("failed to construct NFT: %v", err) } - role := &coredocumentpb.Role{RoleKey: utils.RandomSlice(32)} + role := newRole() role.Nfts = append(role.Nfts, nft) cd.addNewRule(role, coredocumentpb.Action_ACTION_READ) return cd.setSalts() @@ -348,8 +335,8 @@ func isATInRole(role *coredocumentpb.Role, tokenID []byte) (*coredocumentpb.Acce // validateAT validates that given access token against its signature func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID []byte) error { // assemble token message from the token for validation - reqID := identity.NewDIDFromByte(requesterID) - granterID := identity.NewDIDFromByte(token.Granter) + reqID := identity.NewDIDFromBytes(requesterID) + granterID := identity.NewDIDFromBytes(token.Granter) tm, err := assembleTokenMessage(token.Identifier, granterID, reqID, token.RoleIdentifier, token.DocumentIdentifier) if err != nil { return err @@ -394,8 +381,7 @@ func (cd *CoreDocument) AddAccessToken(ctx context.Context, payload documentpb.A return nil, err } - role := new(coredocumentpb.Role) - role.RoleKey = utils.RandomSlice(32) + role := newRole() at, err := assembleAccessToken(ctx, payload, role.RoleKey) if err != nil { return nil, errors.New("failed to construct access token: %v", err) @@ -417,7 +403,7 @@ func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenPara if err != nil { return nil, err } - granterID := identity.NewDIDFromByte(id) + granterID := identity.NewDIDFromBytes(id) roleID := roleKey granteeID, err := identity.NewDIDFromString(payload.Grantee) if err != nil { @@ -475,3 +461,8 @@ func assembleTokenMessage(tokenIdentifier []byte, granterID identity.DID, grante tm = append(tm, docID...) return tm, nil } + +// newRole returns a new role with random role key +func newRole() *coredocumentpb.Role { + return &coredocumentpb.Role{RoleKey: utils.RandomSlice(32)} +} diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go index 181fa13e3..fae73444d 100644 --- a/documents/read_acls_test.go +++ b/documents/read_acls_test.go @@ -333,7 +333,7 @@ func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { cd := newCoreDocument() cd.Document.DocumentRoot = utils.RandomSlice(32) id, err := account.GetIdentityID() - granteeID := identity.NewDIDFromByte(id) + granteeID := identity.NewDIDFromBytes(id) assert.NoError(t, err) payload := documentpb.AccessTokenParams{ Grantee: hexutil.Encode(granteeID[:]), diff --git a/identity/did.go b/identity/did.go index 646173709..6c53d1334 100644 --- a/identity/did.go +++ b/identity/did.go @@ -129,11 +129,6 @@ type Factory interface { CalculateIdentityAddress(ctx context.Context) (*common.Address, error) } -// NewDIDFromByte returns a DID based on a byte slice -func NewDIDFromByte(did []byte) DID { - return DID(common.BytesToAddress(did)) -} - // ServiceDID interface contains the methods to interact with the identity contract type ServiceDID interface { // AddKey adds a key to identity contract diff --git a/p2p/client.go b/p2p/client.go index fe5adb2eb..3cc5db598 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -226,7 +226,7 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Mod return nil, errors.New("failed to get self ID") } - cs, err := model.GetCollaborators(self.ID) + cs, err := model.GetSignerCollaborators(self.ID) if err != nil { return nil, errors.New("failed to get external collaborators") } From 11d0f6cd722ad3068a9c1e8198ea26023df5b3ed Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Thu, 28 Feb 2019 14:33:24 +0100 Subject: [PATCH 207/220] fix build tags --- testingutils/commons/mock_did_identity.go | 2 ++ testingutils/config/config.go | 2 ++ testingutils/documents/documents.go | 2 ++ 3 files changed, 6 insertions(+) diff --git a/testingutils/commons/mock_did_identity.go b/testingutils/commons/mock_did_identity.go index aceb00f38..d53ac7b2c 100644 --- a/testingutils/commons/mock_did_identity.go +++ b/testingutils/commons/mock_did_identity.go @@ -1,3 +1,5 @@ +// +build unit integration + package testingcommons import ( diff --git a/testingutils/config/config.go b/testingutils/config/config.go index fc8aee376..665408c92 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -1,3 +1,5 @@ +// +build unit integration + package testingconfig import ( diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 3abb5914f..3661d28dd 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -1,3 +1,5 @@ +// +build unit integration + package testingdocuments import ( From 76803e31ba67f1b01750e32d5aaef3772b631c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Tuyaerts?= <30529561+Remi-Tuy@users.noreply.github.com> Date: Thu, 28 Feb 2019 20:56:03 +0100 Subject: [PATCH 208/220] Remove vendor folder to make install easier (#677) * Remove vendor folder to make install easier This make the 'make install' process easier :) * Update * Corrected spelling mistake * Added the commands to 'clean' * Added clean to 'install' to make the installation process more straight forward * Removed clean from install This should help with passing the CI --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index d96d836f7..bc7538f69 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,11 @@ help: ## Show this help message. @echo 'targets:' @egrep '^(.+)\:\ ##\ (.+)' ${MAKEFILE_LIST} | column -t -c 2 -s ':#' +clean: ##clean vendor's folder. Should be run before a make install + @echo 'cleaning previous /vendor folder' + @rm -rf vendor/ + @echo 'done cleaning' + install-deps: ## Install Dependencies @command -v dep >/dev/null 2>&1 || go get -u github.com/golang/dep/... @dep ensure From 04d562d1bfdf1abbb86ab06561baf66d3c34213d Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 1 Mar 2019 10:52:36 +0100 Subject: [PATCH 209/220] Enabling all nft tests (#786) * Enabling all nft tests * node version * node version * block gas limit * Fixes * Fixes * NFT minting works * Fix testworld stuff * Minor * New anchor bindings * Fixes * Fixes * Newest id contracts and skipping execute test * Fixes --- .travis.yml | 1 + Gopkg.lock | 4 +- Gopkg.toml | 2 +- anchors/anchor.go | 6 + anchors/anchor_contract.go | 166 ++++------ anchors/service.go | 8 +- .../testingbootstrap/testing_bootstrap.go | 2 +- build/configs/default_config.yaml | 18 +- build/scripts/docker/docker-compose-geth.yml | 3 +- build/scripts/docker/run.sh | 3 +- build/scripts/migrate.sh | 1 + documents/read_acls.go | 2 +- documents/read_acls_test.go | 4 +- documents/validator.go | 2 +- documents/validator_test.go | 2 +- identity/ideth/execute_integration_test.go | 7 +- identity/ideth/factory_contract.go | 25 +- identity/ideth/identity_contract.go | 172 +++++----- nft/ethereum_payment_obligation.go | 115 +++++-- nft/ethereum_payment_obligation_contract.go | 310 +++++++++++------- nft/ethereum_payment_obligation_test.go | 4 +- nft/payment_obligation_integration_test.go | 48 +-- testingutils/setup.go | 40 ++- testworld/nft_test.go | 48 +-- transactions/txv1/base_task.go | 2 +- 25 files changed, 569 insertions(+), 426 deletions(-) diff --git a/.travis.yml b/.travis.yml index c44c398d2..3b2a42a45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ cache: - /tmp/depcache before_install: + - nvm install 10.15.1 - npm install -g truffle@4.1.13 install: diff --git a/Gopkg.lock b/Gopkg.lock index d0e3b58f3..7ac26fd3d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,11 +57,11 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - digest = "1:bedc0b304fccce285e74ebae57d61c4b190b1a420b0c07afb1d4c2da56d164b8" + digest = "1:2c70a1d77e70fac05b6ad9216a8304424ddedae03a1cd9eb7d5c2adb20bbedf8" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" + revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" [[projects]] digest = "1:94366a6a33e0dbcfa2bdf4cffe474e66b517e7863662e2fb87f28e3cd6289409" diff --git a/Gopkg.toml b/Gopkg.toml index b3a3d0ee8..8b8e3f029 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -32,7 +32,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - revision = "33c46d6fffa366e64fc48aff3a8a173a86eaebf6" + revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" [[constraint]] name = "github.com/Masterminds/semver" diff --git a/anchors/anchor.go b/anchors/anchor.go index ea75d1506..e5024bee4 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -7,6 +7,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" ) @@ -49,6 +50,11 @@ func (a *AnchorID) BigInt() *big.Int { return utils.ByteSliceToBigInt(a[:]) } +// String returns anchorID in string form +func (a *AnchorID) String() string { + return hexutil.Encode(a[:]) +} + // DocumentRoot type is byte array of length DocumentRootLength type DocumentRoot [DocumentRootLength]byte diff --git a/anchors/anchor_contract.go b/anchors/anchor_contract.go index 5757e12f5..96771008d 100644 --- a/anchors/anchor_contract.go +++ b/anchors/anchor_contract.go @@ -15,8 +15,20 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // AnchorContractABI is the input ABI used to generate the binding from. -const AnchorContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"commits\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xc7c4a615\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preCommits\",\"outputs\":[{\"name\":\"signingRoot\",\"type\":\"bytes32\"},{\"name\":\"identity\",\"type\":\"address\"},{\"name\":\"expirationBlock\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xd04cc3da\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\",\"signature\":\"0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\",\"signature\":\"0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_signingRoot\",\"type\":\"bytes32\"},{\"name\":\"_expirationBlock\",\"type\":\"uint256\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\",\"signature\":\"0xdb004f37\"},{\"constant\":false,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_documentRoot\",\"type\":\"bytes32\"},{\"name\":\"_documentProofs\",\"type\":\"bytes32[]\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\",\"signature\":\"0x58522947\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x32bf361b\"},{\"constant\":true,\"inputs\":[{\"name\":\"_anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xb5c7d034\"}]" +const AnchorContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"signingRoot\",\"type\":\"bytes32\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"name\":\"documentProofs\",\"type\":\"bytes32[]\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // AnchorContract is an auto generated Go binding around an Ethereum contract. type AnchorContract struct { @@ -160,36 +172,10 @@ func (_AnchorContract *AnchorContractTransactorRaw) Transact(opts *bind.Transact return _AnchorContract.Contract.contract.Transact(opts, method, params...) } -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_AnchorContract *AnchorContractCaller) Commits(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { - var ( - ret0 = new([32]byte) - ) - out := ret0 - err := _AnchorContract.contract.Call(opts, out, "commits", arg0) - return *ret0, err -} - -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_AnchorContract *AnchorContractSession) Commits(arg0 *big.Int) ([32]byte, error) { - return _AnchorContract.Contract.Commits(&_AnchorContract.CallOpts, arg0) -} - -// Commits is a free data retrieval call binding the contract method 0xc7c4a615. -// -// Solidity: function commits( uint256) constant returns(bytes32) -func (_AnchorContract *AnchorContractCallerSession) Commits(arg0 *big.Int) ([32]byte, error) { - return _AnchorContract.Contract.Commits(&_AnchorContract.CallOpts, arg0) -} - // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) -func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, _anchorId *big.Int) (struct { +// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte }, error) { @@ -198,136 +184,96 @@ func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, DocumentRoot [32]byte }) out := ret - err := _AnchorContract.contract.Call(opts, out, "getAnchorById", _anchorId) + err := _AnchorContract.contract.Call(opts, out, "getAnchorById", id) return *ret, err } // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) -func (_AnchorContract *AnchorContractSession) GetAnchorById(_anchorId *big.Int) (struct { +// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +func (_AnchorContract *AnchorContractSession) GetAnchorById(id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte }, error) { - return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, _anchorId) + return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, id) } // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(_anchorId uint256) constant returns(anchorId uint256, documentRoot bytes32) -func (_AnchorContract *AnchorContractCallerSession) GetAnchorById(_anchorId *big.Int) (struct { +// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +func (_AnchorContract *AnchorContractCallerSession) GetAnchorById(id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte }, error) { - return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, _anchorId) + return _AnchorContract.Contract.GetAnchorById(&_AnchorContract.CallOpts, id) } // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_AnchorContract *AnchorContractCaller) HasValidPreCommit(opts *bind.CallOpts, _anchorId *big.Int) (bool, error) { +// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +func (_AnchorContract *AnchorContractCaller) HasValidPreCommit(opts *bind.CallOpts, anchorId *big.Int) (bool, error) { var ( ret0 = new(bool) ) out := ret0 - err := _AnchorContract.contract.Call(opts, out, "hasValidPreCommit", _anchorId) + err := _AnchorContract.contract.Call(opts, out, "hasValidPreCommit", anchorId) return *ret0, err } // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_AnchorContract *AnchorContractSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { - return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, _anchorId) +// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +func (_AnchorContract *AnchorContractSession) HasValidPreCommit(anchorId *big.Int) (bool, error) { + return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, anchorId) } // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(_anchorId uint256) constant returns(bool) -func (_AnchorContract *AnchorContractCallerSession) HasValidPreCommit(_anchorId *big.Int) (bool, error) { - return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, _anchorId) -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) -func (_AnchorContract *AnchorContractCaller) PreCommits(opts *bind.CallOpts, arg0 *big.Int) (struct { - SigningRoot [32]byte - Identity common.Address - ExpirationBlock uint32 -}, error) { - ret := new(struct { - SigningRoot [32]byte - Identity common.Address - ExpirationBlock uint32 - }) - out := ret - err := _AnchorContract.contract.Call(opts, out, "preCommits", arg0) - return *ret, err -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) -func (_AnchorContract *AnchorContractSession) PreCommits(arg0 *big.Int) (struct { - SigningRoot [32]byte - Identity common.Address - ExpirationBlock uint32 -}, error) { - return _AnchorContract.Contract.PreCommits(&_AnchorContract.CallOpts, arg0) -} - -// PreCommits is a free data retrieval call binding the contract method 0xd04cc3da. -// -// Solidity: function preCommits( uint256) constant returns(signingRoot bytes32, identity address, expirationBlock uint32) -func (_AnchorContract *AnchorContractCallerSession) PreCommits(arg0 *big.Int) (struct { - SigningRoot [32]byte - Identity common.Address - ExpirationBlock uint32 -}, error) { - return _AnchorContract.Contract.PreCommits(&_AnchorContract.CallOpts, arg0) +// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +func (_AnchorContract *AnchorContractCallerSession) HasValidPreCommit(anchorId *big.Int) (bool, error) { + return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, anchorId) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() -func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, _anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.contract.Transact(opts, "commit", _anchorId, _documentRoot, _documentProofs) +// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.contract.Transact(opts, "commit", anchorId, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() -func (_AnchorContract *AnchorContractSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, _anchorId, _documentRoot, _documentProofs) +// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractSession) Commit(anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorId, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(_anchorId uint256, _documentRoot bytes32, _documentProofs bytes32[]) returns() -func (_AnchorContract *AnchorContractTransactorSession) Commit(_anchorId *big.Int, _documentRoot [32]byte, _documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, _anchorId, _documentRoot, _documentProofs) +// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractTransactorSession) Commit(anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorId, documentRoot, documentProofs) } -// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() -func (_AnchorContract *AnchorContractTransactor) PreCommit(opts *bind.TransactOpts, _anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _AnchorContract.contract.Transact(opts, "preCommit", _anchorId, _signingRoot, _expirationBlock) +// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +func (_AnchorContract *AnchorContractTransactor) PreCommit(opts *bind.TransactOpts, anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { + return _AnchorContract.contract.Transact(opts, "preCommit", anchorId, signingRoot) } -// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() -func (_AnchorContract *AnchorContractSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, _anchorId, _signingRoot, _expirationBlock) +// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +func (_AnchorContract *AnchorContractSession) PreCommit(anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, anchorId, signingRoot) } -// PreCommit is a paid mutator transaction binding the contract method 0xdb004f37. +// PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(_anchorId uint256, _signingRoot bytes32, _expirationBlock uint256) returns() -func (_AnchorContract *AnchorContractTransactorSession) PreCommit(_anchorId *big.Int, _signingRoot [32]byte, _expirationBlock *big.Int) (*types.Transaction, error) { - return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, _anchorId, _signingRoot, _expirationBlock) +// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +func (_AnchorContract *AnchorContractTransactorSession) PreCommit(anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, anchorId, signingRoot) } // AnchorContractAnchorCommittedIterator is returned from FilterAnchorCommitted and is used to iterate over the raw logs and unpacked data for AnchorCommitted events raised by the AnchorContract contract. @@ -408,7 +354,7 @@ type AnchorContractAnchorCommitted struct { // FilterAnchorCommitted is a free log retrieval operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. // -// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) +// Solidity: event AnchorCommitted(address indexed from, uint256 indexed anchorId, bytes32 documentRoot, uint32 blockHeight) func (_AnchorContract *AnchorContractFilterer) FilterAnchorCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorCommittedIterator, error) { var fromRule []interface{} @@ -429,7 +375,7 @@ func (_AnchorContract *AnchorContractFilterer) FilterAnchorCommitted(opts *bind. // WatchAnchorCommitted is a free log subscription operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. // -// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) +// Solidity: event AnchorCommitted(address indexed from, uint256 indexed anchorId, bytes32 documentRoot, uint32 blockHeight) func (_AnchorContract *AnchorContractFilterer) WatchAnchorCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { var fromRule []interface{} @@ -550,7 +496,7 @@ type AnchorContractAnchorPreCommitted struct { // FilterAnchorPreCommitted is a free log retrieval operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. // -// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) +// Solidity: event AnchorPreCommitted(address indexed from, uint256 indexed anchorId, uint32 blockHeight) func (_AnchorContract *AnchorContractFilterer) FilterAnchorPreCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorPreCommittedIterator, error) { var fromRule []interface{} @@ -571,7 +517,7 @@ func (_AnchorContract *AnchorContractFilterer) FilterAnchorPreCommitted(opts *bi // WatchAnchorPreCommitted is a free log subscription operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. // -// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) +// Solidity: event AnchorPreCommitted(address indexed from, uint256 indexed anchorId, uint32 blockHeight) func (_AnchorContract *AnchorContractFilterer) WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorPreCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { var fromRule []interface{} diff --git a/anchors/service.go b/anchors/service.go index bd13e5705..4cd1cf446 100644 --- a/anchors/service.go +++ b/anchors/service.go @@ -18,9 +18,9 @@ import ( ) type anchorRepositoryContract interface { - PreCommit(opts *bind.TransactOpts, _anchorID *big.Int, signingRoot [32]byte, expirationBlock *big.Int) (*types.Transaction, error) - Commit(opts *bind.TransactOpts, anchorID *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) - GetAnchorById(opts *bind.CallOpts, anchorID *big.Int) (struct { + PreCommit(opts *bind.TransactOpts, anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) + Commit(opts *bind.TransactOpts, anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) + GetAnchorById(opts *bind.CallOpts, id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte }, error) @@ -142,7 +142,7 @@ func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentR cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, documentProofs) - log.Info("Add Anchor to Commit %s from did:%s", anchorID.BigInt().String(), did.ToAddress().String()) + log.Infof("Add Anchor to Commit %s from did:%s", anchorID.String(), did.ToAddress().String()) _, done, err := s.txManager.ExecuteWithinTX(ctx, did, uuid, "Check TX for anchor commit", s.ethereumTX(opts, s.anchorRepositoryContract.Commit, cd.AnchorID.BigInt(), cd.DocumentRoot, cd.DocumentProofs)) if err != nil { diff --git a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go index bbacda0bb..77e9e9be6 100644 --- a/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go +++ b/bootstrap/bootstrappers/testingbootstrap/testing_bootstrap.go @@ -38,9 +38,9 @@ var bootstappers = []bootstrap.TestBootstrapper{ &invoice.Bootstrapper{}, &purchaseorder.Bootstrapper{}, &nft.Bootstrapper{}, - &queue.Starter{}, p2p.Bootstrapper{}, documents.PostBootstrapper{}, + &queue.Starter{}, } func TestFunctionalEthereumBootstrap() map[string]interface{} { diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 0dae3446a..aba88628d 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -27,10 +27,10 @@ networks: ethereumNetworkId: 4 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0xF3d98f3f6866E772305504317519A12Dcf8e8e9A" + identityFactory: "0x5a24967ffd48a2a1c83dd8535db8dbd9da166c36" identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" - anchorRepository: "0x5372Be663ad3FDe0B2F64776081C077C4B5aa457" - paymentObligation: "0x5F029989DE7AA406aD01DD1d25d6f2e021Eee008" + anchorRepository: "0x5e4ad4716863216b93cf32e12d69fcf17725b53d" + paymentObligation: "0x6bd3f53071d9f89fcc5901596b74c3bd1c791074" # Kovan test network bernalheights: @@ -51,10 +51,10 @@ networks: ethereumNetworkId: 42 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0xC33e46E8f78f42CF041aB9009125F38280E80E3C" + identityFactory: "0x2fd5ff89defb25a0a7eb2fe2d1eec02187b56e13" identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" - anchorRepository: "0xcE2a6E242C457Bc7Ecbe0cb9dA8f2FFCA21273c9" - paymentObligation: "0x4922ea1a05c15547eA3f7a3eA9B0fBF2965E466F" + anchorRepository: "0xebfd8e3a60805d402cdb064cb5bb79d242811d2c" + paymentObligation: "0xf9339d9311ba288c7688092fb823f82d31564ffb" # Ropsten test network dogpatch: @@ -68,10 +68,10 @@ networks: ethereumNetworkId: 3 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x47d3194f858d1Fa26C51a93631CEA6eFa570E833" + identityFactory: "0x9f92f00a3d57d7f316e2ca28996df5291850e8ac" identityRegistry: "0x55160B12091c41E7C41f0BA5Ae925a0426c4aAEA" - anchorRepository: "0xE3228070377Be6DD03f29661AD194Ed038f2830f" - paymentObligation: "0x5820c05E8eE7d63720DF8D5e6C5987Ac6D998C42" + anchorRepository: "0xf6d6a3ef92e991ee6b7fa18c2702a5326082aad9" + paymentObligation: "0x437055dbdf45283de4a6e9e09b90e043a48c2db1" # Data Storage storage: diff --git a/build/scripts/docker/docker-compose-geth.yml b/build/scripts/docker/docker-compose-geth.yml index 35ae8736b..cf245a8c2 100644 --- a/build/scripts/docker/docker-compose-geth.yml +++ b/build/scripts/docker/docker-compose-geth.yml @@ -1,7 +1,7 @@ version: '3' services: geth: - image: "centrifugeio/cent-geth:v0.1.0" + image: "centrifugeio/cent-geth:v0.1.1" container_name: geth-node environment: - RINKEBY @@ -14,6 +14,7 @@ services: - WS_PORT - BOOT_NODES - CENT_ETHEREUM_ACCOUNTS_MAIN_ADDRESS + - TARGETGASLIMIT ports: - "9545:9545" - "9546:9546" diff --git a/build/scripts/docker/run.sh b/build/scripts/docker/run.sh index cfb154602..0861ab4d4 100755 --- a/build/scripts/docker/run.sh +++ b/build/scripts/docker/run.sh @@ -28,6 +28,7 @@ DEFAULT_DATADIR=/tmp/centrifuge_data_${API_PORT}.leveldb API_DATADIR=${API_DATADIR:-$DEFAULT_DATADIR} DEFAULT_CONFIGDIR="${HOME}/centrifuge/cent-api-${API_PORT}" API_CONFIGDIR=${API_CONFIGDIR:-$DEFAULT_CONFIGDIR} +TARGETGASLIMIT=${TARGETGASLIMIT:-"9000000"} ADDITIONAL_CMD="${@:2}" @@ -64,7 +65,7 @@ case "$mode" in cp $local_dir/../test-dependencies/test-ethereum/*.json ${ETH_DATADIR}/${NETWORK_ID}/keystore IDENTITY=$IDENTITY NETWORK_ID=$NETWORK_ID ETH_DATADIR=${ETH_DATADIR}/${NETWORK_ID} RPC_PORT=$RPC_PORT API=$API \ WS_PORT=$WS_PORT CENT_ETHEREUM_ACCOUNTS_MAIN_ADDRESS=$CENT_ETHEREUM_ACCOUNTS_MAIN_ADDRESS \ - docker-compose -f $local_dir/docker-compose-geth.yml up > /tmp/geth.log 2>&1 & + TARGETGASLIMIT=$TARGETGASLIMIT docker-compose -f $local_dir/docker-compose-geth.yml up > /tmp/geth.log 2>&1 & ;; centapi) CENT_MODE=$CENT_MODE ADDITIONAL_CMD=$ADDITIONAL_CMD API_DATADIR=$API_DATADIR API_CONFIGDIR=$API_CONFIGDIR \ diff --git a/build/scripts/migrate.sh b/build/scripts/migrate.sh index d93abeb28..997f479c8 100755 --- a/build/scripts/migrate.sh +++ b/build/scripts/migrate.sh @@ -32,6 +32,7 @@ fi if [[ "X${FORCE_MIGRATE}" == "Xtrue" ]]; then echo "Running the Solidity contracts migrations for local geth" + sleep 30 # allow geth block gas limit to increase to more than 7000000 ${CENT_ETHEREUM_CONTRACTS_DIR}/scripts/migrate.sh localgeth else echo "Not migrating the Solidity contracts" diff --git a/documents/read_acls.go b/documents/read_acls.go index c60534a84..dc0fcb74a 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -272,8 +272,8 @@ func getReadAccessProofKeys(cd coredocumentpb.CoreDocument, registry common.Addr return []string{ fmt.Sprintf(CDTreePrefix+".read_rules[%d].roles[%d]", rridx, ridx), // proof that a read rule exists with the nft role - fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists fmt.Sprintf(CDTreePrefix+".read_rules[%d].action", rridx), // proof that this read rule has read access + fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[%d]", hexutil.Encode(rk), nftIdx), // proof that role with nft exists }, nil } diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go index fae73444d..8eb0d3153 100644 --- a/documents/read_acls_test.go +++ b/documents/read_acls_test.go @@ -190,8 +190,8 @@ func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { assert.NoError(t, err) assert.Len(t, pfs, 3) assert.Equal(t, CDTreePrefix+".read_rules[0].roles[0]", pfs[0]) - assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(cd.Document.Roles[0].RoleKey)), pfs[1]) - assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[2]) + assert.Equal(t, CDTreePrefix+".read_rules[0].action", pfs[1]) + assert.Equal(t, fmt.Sprintf(CDTreePrefix+".roles[%s].nfts[0]", hexutil.Encode(cd.Document.Roles[0].RoleKey)), pfs[2]) } func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { diff --git a/documents/validator.go b/documents/validator.go index d9afccd5c..ced68f0ed 100644 --- a/documents/validator.go +++ b/documents/validator.go @@ -210,7 +210,7 @@ func anchoredValidator(repo anchors.AnchorRepository) Validator { gotRoot, err := repo.GetDocumentRootOf(anchorID) if err != nil { - return errors.New("failed to get document root from chain: %v", err) + return errors.New("failed to get document root for anchor %s from chain: %v", anchorID.String(), err) } if !utils.IsSameByteSlice(docRoot[:], gotRoot[:]) { diff --git a/documents/validator_test.go b/documents/validator_test.go index bc8509e71..aaeea78d5 100644 --- a/documents/validator_test.go +++ b/documents/validator_test.go @@ -411,7 +411,7 @@ func TestValidator_anchoredValidator(t *testing.T) { model.AssertExpectations(t) r.AssertExpectations(t) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get document root from chain") + assert.Contains(t, err.Error(), "failed to get document root for anchor") // mismatched doc roots docRoot := anchors.RandomDocumentRoot() diff --git a/identity/ideth/execute_integration_test.go b/identity/ideth/execute_integration_test.go index f19b8f807..23a903e84 100644 --- a/identity/ideth/execute_integration_test.go +++ b/identity/ideth/execute_integration_test.go @@ -19,15 +19,13 @@ import ( "context" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" @@ -44,6 +42,7 @@ func getAnchorAddress(cfg config.Configuration) common.Address { } func TestExecute_successful(t *testing.T) { + t.SkipNow() did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() diff --git a/identity/ideth/factory_contract.go b/identity/ideth/factory_contract.go index ed0a0f042..ee6b62a5b 100644 --- a/identity/ideth/factory_contract.go +++ b/identity/ideth/factory_contract.go @@ -4,6 +4,7 @@ package ideth import ( + "math/big" "strings" ethereum "github.com/ethereum/go-ethereum" @@ -14,8 +15,20 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // FactoryContractABI is the input ABI used to generate the binding from. -const FactoryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\",\"signature\":\"0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0\"},{\"constant\":false,\"inputs\":[],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x59d21ad9\"},{\"constant\":false,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"createIdentityFor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa480f9f7\"}]" +const FactoryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"createIdentityFor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" // FactoryContract is an auto generated Go binding around an Ethereum contract. type FactoryContract struct { @@ -182,21 +195,21 @@ func (_FactoryContract *FactoryContractTransactorSession) CreateIdentity() (*typ // CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. // -// Solidity: function createIdentityFor(owner address) returns() +// Solidity: function createIdentityFor(address owner) returns() func (_FactoryContract *FactoryContractTransactor) CreateIdentityFor(opts *bind.TransactOpts, owner common.Address) (*types.Transaction, error) { return _FactoryContract.contract.Transact(opts, "createIdentityFor", owner) } // CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. // -// Solidity: function createIdentityFor(owner address) returns() +// Solidity: function createIdentityFor(address owner) returns() func (_FactoryContract *FactoryContractSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) } // CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. // -// Solidity: function createIdentityFor(owner address) returns() +// Solidity: function createIdentityFor(address owner) returns() func (_FactoryContract *FactoryContractTransactorSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) } @@ -276,7 +289,7 @@ type FactoryContractIdentityCreated struct { // FilterIdentityCreated is a free log retrieval operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. // -// Solidity: e IdentityCreated(identity indexed address) +// Solidity: event IdentityCreated(address indexed identity) func (_FactoryContract *FactoryContractFilterer) FilterIdentityCreated(opts *bind.FilterOpts, identity []common.Address) (*FactoryContractIdentityCreatedIterator, error) { var identityRule []interface{} @@ -293,7 +306,7 @@ func (_FactoryContract *FactoryContractFilterer) FilterIdentityCreated(opts *bin // WatchIdentityCreated is a free log subscription operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. // -// Solidity: e IdentityCreated(identity indexed address) +// Solidity: event IdentityCreated(address indexed identity) func (_FactoryContract *FactoryContractFilterer) WatchIdentityCreated(opts *bind.WatchOpts, sink chan<- *FactoryContractIdentityCreated, identity []common.Address) (event.Subscription, error) { var identityRule []interface{} diff --git a/identity/ideth/identity_contract.go b/identity/ideth/identity_contract.go index 3280ff467..02a6c5cb3 100644 --- a/identity/ideth/identity_contract.go +++ b/identity/ideth/identity_contract.go @@ -15,8 +15,20 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // IdentityContractABI is the input ABI used to generate the binding from. -const IdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purposes\",\"type\":\"uint256[]\"},{\"name\":\"_keyType\",\"type\":\"uint256\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"},{\"name\":\"_keyType\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressToKey\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_toSign\",\"type\":\"bytes32\"},{\"name\":\"_signature\",\"type\":\"bytes\"},{\"name\":\"_purpose\",\"type\":\"uint256\"}],\"name\":\"isSignedWithPurpose\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const IdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressToKey\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"},{\"name\":\"result\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"message\",\"type\":\"bytes32\"},{\"name\":\"signature\",\"type\":\"bytes\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"isSignedWithPurpose\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // IdentityContract is an auto generated Go binding around an Ethereum contract. type IdentityContract struct { @@ -162,7 +174,7 @@ func (_IdentityContract *IdentityContractTransactorRaw) Transact(opts *bind.Tran // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(addr address) constant returns(bytes32) +// Solidity: function addressToKey(address addr) constant returns(bytes32) func (_IdentityContract *IdentityContractCaller) AddressToKey(opts *bind.CallOpts, addr common.Address) ([32]byte, error) { var ( ret0 = new([32]byte) @@ -174,22 +186,22 @@ func (_IdentityContract *IdentityContractCaller) AddressToKey(opts *bind.CallOpt // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(addr address) constant returns(bytes32) +// Solidity: function addressToKey(address addr) constant returns(bytes32) func (_IdentityContract *IdentityContractSession) AddressToKey(addr common.Address) ([32]byte, error) { return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) } // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(addr address) constant returns(bytes32) +// Solidity: function addressToKey(address addr) constant returns(bytes32) func (_IdentityContract *IdentityContractCallerSession) AddressToKey(addr common.Address) ([32]byte, error) { return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) } // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, _key [32]byte) (struct { +// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int RevokedAt *big.Int @@ -200,192 +212,192 @@ func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, _ke RevokedAt *big.Int }) out := ret - err := _IdentityContract.contract.Call(opts, out, "getKey", _key) + err := _IdentityContract.contract.Call(opts, out, "getKey", keyHash) return *ret, err } // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_IdentityContract *IdentityContractSession) GetKey(_key [32]byte) (struct { +// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +func (_IdentityContract *IdentityContractSession) GetKey(keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int RevokedAt *big.Int }, error) { - return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, _key) + return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, keyHash) } // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(_key bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) -func (_IdentityContract *IdentityContractCallerSession) GetKey(_key [32]byte) (struct { +// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +func (_IdentityContract *IdentityContractCallerSession) GetKey(keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int RevokedAt *big.Int }, error) { - return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, _key) + return _IdentityContract.Contract.GetKey(&_IdentityContract.CallOpts, keyHash) } // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_IdentityContract *IdentityContractCaller) GetKeysByPurpose(opts *bind.CallOpts, _purpose *big.Int) ([][32]byte, error) { +// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractCaller) GetKeysByPurpose(opts *bind.CallOpts, purpose *big.Int) ([][32]byte, error) { var ( ret0 = new([][32]byte) ) out := ret0 - err := _IdentityContract.contract.Call(opts, out, "getKeysByPurpose", _purpose) + err := _IdentityContract.contract.Call(opts, out, "getKeysByPurpose", purpose) return *ret0, err } // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_IdentityContract *IdentityContractSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { - return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, _purpose) +// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractSession) GetKeysByPurpose(purpose *big.Int) ([][32]byte, error) { + return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, purpose) } // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(_purpose uint256) constant returns(bytes32[]) -func (_IdentityContract *IdentityContractCallerSession) GetKeysByPurpose(_purpose *big.Int) ([][32]byte, error) { - return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, _purpose) +// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +func (_IdentityContract *IdentityContractCallerSession) GetKeysByPurpose(purpose *big.Int) ([][32]byte, error) { + return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, purpose) } // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) -func (_IdentityContract *IdentityContractCaller) IsSignedWithPurpose(opts *bind.CallOpts, _toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { +// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +func (_IdentityContract *IdentityContractCaller) IsSignedWithPurpose(opts *bind.CallOpts, message [32]byte, signature []byte, purpose *big.Int) (bool, error) { var ( ret0 = new(bool) ) out := ret0 - err := _IdentityContract.contract.Call(opts, out, "isSignedWithPurpose", _toSign, _signature, _purpose) + err := _IdentityContract.contract.Call(opts, out, "isSignedWithPurpose", message, signature, purpose) return *ret0, err } // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) -func (_IdentityContract *IdentityContractSession) IsSignedWithPurpose(_toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { - return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, _toSign, _signature, _purpose) +// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +func (_IdentityContract *IdentityContractSession) IsSignedWithPurpose(message [32]byte, signature []byte, purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, message, signature, purpose) } // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(_toSign bytes32, _signature bytes, _purpose uint256) constant returns(valid bool) -func (_IdentityContract *IdentityContractCallerSession) IsSignedWithPurpose(_toSign [32]byte, _signature []byte, _purpose *big.Int) (bool, error) { - return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, _toSign, _signature, _purpose) +// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +func (_IdentityContract *IdentityContractCallerSession) IsSignedWithPurpose(message [32]byte, signature []byte, purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, message, signature, purpose) } // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_IdentityContract *IdentityContractCaller) KeyHasPurpose(opts *bind.CallOpts, _key [32]byte, _purpose *big.Int) (bool, error) { +// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +func (_IdentityContract *IdentityContractCaller) KeyHasPurpose(opts *bind.CallOpts, key [32]byte, purpose *big.Int) (bool, error) { var ( ret0 = new(bool) ) out := ret0 - err := _IdentityContract.contract.Call(opts, out, "keyHasPurpose", _key, _purpose) + err := _IdentityContract.contract.Call(opts, out, "keyHasPurpose", key, purpose) return *ret0, err } // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_IdentityContract *IdentityContractSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { - return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, _key, _purpose) +// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +func (_IdentityContract *IdentityContractSession) KeyHasPurpose(key [32]byte, purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, key, purpose) } // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(_key bytes32, _purpose uint256) constant returns(found bool) -func (_IdentityContract *IdentityContractCallerSession) KeyHasPurpose(_key [32]byte, _purpose *big.Int) (bool, error) { - return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, _key, _purpose) +// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +func (_IdentityContract *IdentityContractCallerSession) KeyHasPurpose(key [32]byte, purpose *big.Int) (bool, error) { + return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, key, purpose) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() -func (_IdentityContract *IdentityContractTransactor) AddKey(opts *bind.TransactOpts, _key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.contract.Transact(opts, "addKey", _key, _purpose, _keyType) +// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +func (_IdentityContract *IdentityContractTransactor) AddKey(opts *bind.TransactOpts, key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "addKey", key, purpose, keyType) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() -func (_IdentityContract *IdentityContractSession) AddKey(_key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, _key, _purpose, _keyType) +// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +func (_IdentityContract *IdentityContractSession) AddKey(key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, key, purpose, keyType) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(_key bytes32, _purpose uint256, _keyType uint256) returns() -func (_IdentityContract *IdentityContractTransactorSession) AddKey(_key [32]byte, _purpose *big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, _key, _purpose, _keyType) +// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +func (_IdentityContract *IdentityContractTransactorSession) AddKey(key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, key, purpose, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() -func (_IdentityContract *IdentityContractTransactor) AddMultiPurposeKey(opts *bind.TransactOpts, _key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.contract.Transact(opts, "addMultiPurposeKey", _key, _purposes, _keyType) +// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +func (_IdentityContract *IdentityContractTransactor) AddMultiPurposeKey(opts *bind.TransactOpts, key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "addMultiPurposeKey", key, purposes, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() -func (_IdentityContract *IdentityContractSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, _key, _purposes, _keyType) +// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +func (_IdentityContract *IdentityContractSession) AddMultiPurposeKey(key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, key, purposes, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(_key bytes32, _purposes uint256[], _keyType uint256) returns() -func (_IdentityContract *IdentityContractTransactorSession) AddMultiPurposeKey(_key [32]byte, _purposes []*big.Int, _keyType *big.Int) (*types.Transaction, error) { - return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, _key, _purposes, _keyType) +// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +func (_IdentityContract *IdentityContractTransactorSession) AddMultiPurposeKey(key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { + return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, key, purposes, keyType) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) -func (_IdentityContract *IdentityContractTransactor) Execute(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { - return _IdentityContract.contract.Transact(opts, "execute", _to, _value, _data) +// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +func (_IdentityContract *IdentityContractTransactor) Execute(opts *bind.TransactOpts, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "execute", to, value, data) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) -func (_IdentityContract *IdentityContractSession) Execute(_to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { - return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, _to, _value, _data) +// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +func (_IdentityContract *IdentityContractSession) Execute(to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { + return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, to, value, data) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(_to address, _value uint256, _data bytes) returns(success bool) -func (_IdentityContract *IdentityContractTransactorSession) Execute(_to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) { - return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, _to, _value, _data) +// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +func (_IdentityContract *IdentityContractTransactorSession) Execute(to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { + return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, to, value, data) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(_key bytes32) returns() -func (_IdentityContract *IdentityContractTransactor) RevokeKey(opts *bind.TransactOpts, _key [32]byte) (*types.Transaction, error) { - return _IdentityContract.contract.Transact(opts, "revokeKey", _key) +// Solidity: function revokeKey(bytes32 key) returns() +func (_IdentityContract *IdentityContractTransactor) RevokeKey(opts *bind.TransactOpts, key [32]byte) (*types.Transaction, error) { + return _IdentityContract.contract.Transact(opts, "revokeKey", key) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(_key bytes32) returns() -func (_IdentityContract *IdentityContractSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { - return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, _key) +// Solidity: function revokeKey(bytes32 key) returns() +func (_IdentityContract *IdentityContractSession) RevokeKey(key [32]byte) (*types.Transaction, error) { + return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, key) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(_key bytes32) returns() -func (_IdentityContract *IdentityContractTransactorSession) RevokeKey(_key [32]byte) (*types.Transaction, error) { - return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, _key) +// Solidity: function revokeKey(bytes32 key) returns() +func (_IdentityContract *IdentityContractTransactorSession) RevokeKey(key [32]byte) (*types.Transaction, error) { + return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, key) } // IdentityContractKeyAddedIterator is returned from FilterKeyAdded and is used to iterate over the raw logs and unpacked data for KeyAdded events raised by the IdentityContract contract. @@ -465,7 +477,7 @@ type IdentityContractKeyAdded struct { // FilterKeyAdded is a free log retrieval operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. // -// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) +// Solidity: event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) func (_IdentityContract *IdentityContractFilterer) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (*IdentityContractKeyAddedIterator, error) { var keyRule []interface{} @@ -490,7 +502,7 @@ func (_IdentityContract *IdentityContractFilterer) FilterKeyAdded(opts *bind.Fil // WatchKeyAdded is a free log subscription operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. // -// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) +// Solidity: event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) func (_IdentityContract *IdentityContractFilterer) WatchKeyAdded(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyAdded, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (event.Subscription, error) { var keyRule []interface{} @@ -615,7 +627,7 @@ type IdentityContractKeyRevoked struct { // FilterKeyRevoked is a free log retrieval operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. // -// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) +// Solidity: event KeyRevoked(bytes32 indexed key, uint256 indexed revokedAt, uint256 indexed keyType) func (_IdentityContract *IdentityContractFilterer) FilterKeyRevoked(opts *bind.FilterOpts, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (*IdentityContractKeyRevokedIterator, error) { var keyRule []interface{} @@ -640,7 +652,7 @@ func (_IdentityContract *IdentityContractFilterer) FilterKeyRevoked(opts *bind.F // WatchKeyRevoked is a free log subscription operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. // -// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) +// Solidity: event KeyRevoked(bytes32 indexed key, uint256 indexed revokedAt, uint256 indexed keyType) func (_IdentityContract *IdentityContractFilterer) WatchKeyRevoked(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyRevoked, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (event.Subscription, error) { var keyRule []interface{} diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 0b5f9212f..6f301ec61 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -92,6 +92,11 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return mreq, err } + nextAnchorID, err := anchors.ToAnchorID(model.NextVersion()) + if err != nil { + return mreq, err + } + dr, err := model.CalculateDocumentRoot() if err != nil { return mreq, err @@ -102,7 +107,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return mreq, err } - requestData, err := NewMintRequest(tokenID, req.DepositAddress, anchorID, docProofs.FieldProofs, rootHash) + requestData, err := NewMintRequest(model, tokenID, req.DepositAddress, anchorID, nextAnchorID, docProofs.FieldProofs, rootHash) if err != nil { return mreq, err } @@ -199,17 +204,29 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, requestData.TokenURI, requestData.AnchorID, - requestData.MerkleRoot, requestData.Values, requestData.Salts, requestData.Proofs) + // to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte + ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, + requestData.TokenURI, requestData.AnchorID, requestData.NextAnchorID, requestData.Props, requestData.Values, + requestData.Salts, requestData.Proofs) if err != nil { errOut <- err return } - log.Infof("Sent off ethTX to mint [tokenID: %s, anchor: %x, registry: %s] to payment obligation contract. Ethereum transaction hash [%s] and Nonce [%d] and Check [%v]", - requestData.TokenID, requestData.AnchorID, requestData.To.String(), ethTX.Hash().String(), ethTX.Nonce(), ethTX.CheckNonce()) + log.Infof("Sent off ethTX to mint [tokenID: %s, anchor: %x, nextAnchor: %s, registry: %s] to payment obligation contract. Ethereum transaction hash [%s] and Nonce [%d] and Check [%v]", + requestData.TokenID, requestData.AnchorID, hexutil.Encode(requestData.NextAnchorID.Bytes()), requestData.To.String(), ethTX.Hash().String(), ethTX.Nonce(), ethTX.CheckNonce()) log.Infof("Transfer pending: %s\n", ethTX.Hash().String()) + log.Debugf("To: %s", requestData.To.String()) + log.Debugf("TokenID: %s", hexutil.Encode(requestData.TokenID.Bytes())) + log.Debugf("TokenURI: %s", requestData.TokenURI) + log.Debugf("AnchorID: %s", hexutil.Encode(requestData.AnchorID.Bytes())) + log.Debugf("NextAnchorID: %s", hexutil.Encode(requestData.NextAnchorID.Bytes())) + log.Debugf("Props: %s", byteSlicetoString(requestData.Props)) + log.Debugf("Values: %s", byteSlicetoString(requestData.Values)) + log.Debugf("Salts: %s", byte32SlicetoString(requestData.Salts)) + log.Debugf("Proofs: %s", byteByte32SlicetoString(requestData.Proofs)) + res, err := ethereum.QueueEthTXStatusTask(accountID, txID, ethTX.Hash(), s.queue) if err != nil { errOut <- err @@ -253,8 +270,11 @@ type MintRequest struct { // AnchorID is the ID of the document as identified by the set up anchorRepository. AnchorID *big.Int - // MerkleRoot is the root hash of the merkle proof/doc - MerkleRoot [32]byte + // NextAnchorID is the next ID of the document, when updated + NextAnchorID *big.Int + + // Props contains the compact props for readRole and tokenRole + Props [][]byte // Values are the values of the leafs that is being proved Will be converted to string and concatenated for proof verification as outlined in precise-proofs library. Values [][]byte @@ -267,40 +287,59 @@ type MintRequest struct { } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(tokenID TokenID, to common.Address, anchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { - proofData, err := createProofData(proofs) +func NewMintRequest(model documents.Model, tokenID TokenID, to common.Address, anchorID anchors.AnchorID, nextAnchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { + proofData, err := createProofData(model, proofs) if err != nil { return MintRequest{}, err } return MintRequest{ - To: to, - TokenID: tokenID.BigInt(), - TokenURI: tokenID.URI(), - AnchorID: anchorID.BigInt(), - MerkleRoot: rootHash, - Values: proofData.Values, - Salts: proofData.Salts, - Proofs: proofData.Proofs}, nil + To: to, + TokenID: tokenID.BigInt(), + TokenURI: tokenID.URI(), + AnchorID: anchorID.BigInt(), + NextAnchorID: nextAnchorID.BigInt(), + Props: proofData.Props, + Values: proofData.Values, + Salts: proofData.Salts, + Proofs: proofData.Proofs}, nil } type proofData struct { + Props [][]byte Values [][]byte Salts [][32]byte Proofs [][][32]byte } -func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { - var values = make([][]byte, len(proofspb)) +func createProofData(model documents.Model, proofspb []*proofspb.Proof) (*proofData, error) { + // TODO cleanup hard coded indexes using the model props + readRoleIndex := 5 + tokenRoleIndex := 7 + var props = make([][]byte, 2) // props are only required for readRole.property, tokenRole.property + var values = make([][]byte, 4) // values are only required for readRole.Value var salts = make([][32]byte, len(proofspb)) var proofs = make([][][32]byte, len(proofspb)) // TODO remove later //proof, _ := documents.ConvertDocProofToClientFormat(&documents.DocumentProof{FieldProofs: proofspb}) //log.Info(json.MarshalIndent(proof, "", " ")) - for i, p := range proofspb { - values[i] = p.Value + if i == readRoleIndex { + props[0] = p.GetCompactName() + } + if i == tokenRoleIndex { + props[1] = p.GetCompactName() + } + + if i < 3 { + values[i] = p.Value + } + + if i == readRoleIndex { + values[3] = p.Value + } + salt32, err := utils.SliceToByte32(p.Salt) if err != nil { return nil, err @@ -314,7 +353,7 @@ func createProofData(proofspb []*proofspb.Proof) (*proofData, error) { proofs[i] = property } - return &proofData{Values: values, Salts: salts, Proofs: proofs}, nil + return &proofData{Props: props, Values: values, Salts: salts, Proofs: proofs}, nil } func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { @@ -333,3 +372,35 @@ func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { func bindContract(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return NewEthereumPaymentObligationContract(address, client.GetEthClient()) } + +// Following are utility methods for nft parameter debugging purposes (Don't remove) + +func byteSlicetoString(s [][]byte) string { + str := "[" + + for i := 0; i < len(s); i++ { + str += "\"" + hexutil.Encode(s[i]) + "\",\n" + } + str += "]" + return str +} + +func byte32SlicetoString(s [][32]byte) string { + str := "[" + + for i := 0; i < len(s); i++ { + str += "\"" + hexutil.Encode(s[i][:]) + "\",\n" + } + str += "]" + return str +} + +func byteByte32SlicetoString(s [][][32]byte) string { + str := "[" + + for i := 0; i < len(s); i++ { + str += "\"" + byte32SlicetoString(s[i]) + "\",\n" + } + str += "]" + return str +} diff --git a/nft/ethereum_payment_obligation_contract.go b/nft/ethereum_payment_obligation_contract.go index 9338fbf35..13f505432 100644 --- a/nft/ethereum_payment_obligation_contract.go +++ b/nft/ethereum_payment_obligation_contract.go @@ -15,8 +15,20 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = abi.U256 + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + // EthereumPaymentObligationContractABI is the input ABI used to generate the binding from. -const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mandatoryFields\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_anchorRegistry\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"name\":\"_tokenURI\",\"type\":\"string\"},{\"name\":\"_anchorId\",\"type\":\"uint256\"},{\"name\":\"_merkleRoot\",\"type\":\"bytes32\"},{\"name\":\"_values\",\"type\":\"string[]\"},{\"name\":\"_salts\",\"type\":\"bytes32[]\"},{\"name\":\"_proofs\",\"type\":\"bytes32[][]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"string\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"dueDate\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_mandatoryFields\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"bytes\"},{\"name\":\"currency\",\"type\":\"bytes\"},{\"name\":\"dueDate\",\"type\":\"bytes\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"registry\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"},{\"name\":\"registry\",\"type\":\"address\"},{\"name\":\"mandatoryFields\",\"type\":\"bytes[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"tokenURI\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"nextAnchorId\",\"type\":\"uint256\"},{\"name\":\"properties\",\"type\":\"bytes[]\"},{\"name\":\"values\",\"type\":\"bytes[]\"},{\"name\":\"salts\",\"type\":\"bytes32[]\"},{\"name\":\"proofs\",\"type\":\"bytes32[][]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" // EthereumPaymentObligationContract is an auto generated Go binding around an Ethereum contract. type EthereumPaymentObligationContract struct { @@ -160,6 +172,32 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTrans return _EthereumPaymentObligationContract.Contract.contract.Transact(opts, method, params...) } +// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// +// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) MandatoryFields(opts *bind.CallOpts, arg0 *big.Int) ([]byte, error) { + var ( + ret0 = new([]byte) + ) + out := ret0 + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "_mandatoryFields", arg0) + return *ret0, err +} + +// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// +// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) MandatoryFields(arg0 *big.Int) ([]byte, error) { + return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) +} + +// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// +// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) MandatoryFields(arg0 *big.Int) ([]byte, error) { + return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) +} + // AnchorRegistry is a free data retrieval call binding the contract method 0x5a180c0a. // // Solidity: function anchorRegistry() constant returns(address) @@ -188,7 +226,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(owner address) constant returns(uint256) +// Solidity: function balanceOf(address owner) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { var ( ret0 = new(*big.Int) @@ -200,21 +238,21 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(owner address) constant returns(uint256) +// Solidity: function balanceOf(address owner) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) BalanceOf(owner common.Address) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(owner address) constant returns(uint256) +// Solidity: function balanceOf(address owner) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) BalanceOf(owner common.Address) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(tokenId uint256) constant returns(address) +// Solidity: function getApproved(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( ret0 = new(common.Address) @@ -226,69 +264,69 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(tokenId uint256) constant returns(address) +// Solidity: function getApproved(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetApproved(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function getApproved(tokenId uint256) constant returns(address) +// Solidity: function getApproved(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(_tokenId uint256) constant returns(grossAmount string, currency string, dueDate string, anchorId uint256, documentRoot bytes32) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetTokenDetails(opts *bind.CallOpts, _tokenId *big.Int) (struct { - GrossAmount string - Currency string - DueDate string +// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetTokenDetails(opts *bind.CallOpts, tokenId *big.Int) (struct { + GrossAmount []byte + Currency []byte + DueDate []byte AnchorId *big.Int DocumentRoot [32]byte }, error) { ret := new(struct { - GrossAmount string - Currency string - DueDate string + GrossAmount []byte + Currency []byte + DueDate []byte AnchorId *big.Int DocumentRoot [32]byte }) out := ret - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getTokenDetails", _tokenId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getTokenDetails", tokenId) return *ret, err } // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(_tokenId uint256) constant returns(grossAmount string, currency string, dueDate string, anchorId uint256, documentRoot bytes32) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetTokenDetails(_tokenId *big.Int) (struct { - GrossAmount string - Currency string - DueDate string +// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetTokenDetails(tokenId *big.Int) (struct { + GrossAmount []byte + Currency []byte + DueDate []byte AnchorId *big.Int DocumentRoot [32]byte }, error) { - return _EthereumPaymentObligationContract.Contract.GetTokenDetails(&_EthereumPaymentObligationContract.CallOpts, _tokenId) + return _EthereumPaymentObligationContract.Contract.GetTokenDetails(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(_tokenId uint256) constant returns(grossAmount string, currency string, dueDate string, anchorId uint256, documentRoot bytes32) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetTokenDetails(_tokenId *big.Int) (struct { - GrossAmount string - Currency string - DueDate string +// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetTokenDetails(tokenId *big.Int) (struct { + GrossAmount []byte + Currency []byte + DueDate []byte AnchorId *big.Int DocumentRoot [32]byte }, error) { - return _EthereumPaymentObligationContract.Contract.GetTokenDetails(&_EthereumPaymentObligationContract.CallOpts, _tokenId) + return _EthereumPaymentObligationContract.Contract.GetTokenDetails(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { var ( ret0 = new(bool) @@ -300,44 +338,18 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) } // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) +// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) } -// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. -// -// Solidity: function mandatoryFields( uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) MandatoryFields(opts *bind.CallOpts, arg0 *big.Int) (string, error) { - var ( - ret0 = new(string) - ) - out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "mandatoryFields", arg0) - return *ret0, err -} - -// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. -// -// Solidity: function mandatoryFields( uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) MandatoryFields(arg0 *big.Int) (string, error) { - return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) -} - -// MandatoryFields is a free data retrieval call binding the contract method 0xc4ac61f7. -// -// Solidity: function mandatoryFields( uint256) constant returns(string) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) MandatoryFields(arg0 *big.Int) (string, error) { - return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) -} - // Name is a free data retrieval call binding the contract method 0x06fdde03. // // Solidity: function name() constant returns(string) @@ -366,7 +378,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(tokenId uint256) constant returns(address) +// Solidity: function ownerOf(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( ret0 = new(common.Address) @@ -378,21 +390,21 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(tokenId uint256) constant returns(address) +// Solidity: function ownerOf(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) OwnerOf(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(tokenId uint256) constant returns(address) +// Solidity: function ownerOf(uint256 tokenId) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var ( ret0 = new(bool) @@ -404,14 +416,14 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } @@ -442,9 +454,61 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle return _EthereumPaymentObligationContract.Contract.Symbol(&_EthereumPaymentObligationContract.CallOpts) } +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenByIndex(opts *bind.CallOpts, index *big.Int) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenByIndex", index) + return *ret0, err +} + +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenByIndex(index *big.Int) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, index) +} + +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenByIndex(index *big.Int) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, index) +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenOfOwnerByIndex(opts *bind.CallOpts, owner common.Address, index *big.Int) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "tokenOfOwnerByIndex", owner, index) + return *ret0, err +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, owner, index) +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, owner, index) +} + // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(tokenId uint256) constant returns(string) +// Solidity: function tokenURI(uint256 tokenId) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { var ( ret0 = new(string) @@ -456,140 +520,166 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(tokenId uint256) constant returns(string) +// Solidity: function tokenURI(uint256 tokenId) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenURI(tokenId *big.Int) (string, error) { return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(tokenId uint256) constant returns(string) +// Solidity: function tokenURI(uint256 tokenId) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenURI(tokenId *big.Int) (string, error) { return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var ( + ret0 = new(*big.Int) + ) + out := ret0 + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "totalSupply") + return *ret0, err +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TotalSupply() (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TotalSupply(&_EthereumPaymentObligationContract.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TotalSupply() (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.TotalSupply(&_EthereumPaymentObligationContract.CallOpts) +} + // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(to address, tokenId uint256) returns() +// Solidity: function approve(address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "approve", to, tokenId) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(to address, tokenId uint256) returns() +// Solidity: function approve(address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(to address, tokenId uint256) returns() +// Solidity: function approve(address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. // -// Solidity: function initialize() returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Initialize(opts *bind.TransactOpts) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "initialize") +// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Initialize(opts *bind.TransactOpts, name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "initialize", name, symbol, registry, mandatoryFields) } -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. // -// Solidity: function initialize() returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Initialize() (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts) +// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Initialize(name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, registry, mandatoryFields) } -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. // -// Solidity: function initialize() returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Initialize() (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts) +// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Initialize(name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, registry, mandatoryFields) } -// Mint is a paid mutator transaction binding the contract method 0x093b02fe. +// Mint is a paid mutator transaction binding the contract method 0xa237952f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) } -// Mint is a paid mutator transaction binding the contract method 0x093b02fe. +// Mint is a paid mutator transaction binding the contract method 0xa237952f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) } -// Mint is a paid mutator transaction binding the contract method 0x093b02fe. +// Mint is a paid mutator transaction binding the contract method 0xa237952f. // -// Solidity: function mint(_to address, _tokenId uint256, _tokenURI string, _anchorId uint256, _merkleRoot bytes32, _values string[], _salts bytes32[], _proofs bytes32[][]) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(_to common.Address, _tokenId *big.Int, _tokenURI string, _anchorId *big.Int, _merkleRoot [32]byte, _values []string, _salts [][32]byte, _proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, _to, _tokenId, _tokenURI, _anchorId, _merkleRoot, _values, _salts, _proofs) +// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "safeTransferFrom", from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(to address, approved bool) returns() +// Solidity: function setApprovalForAll(address to, bool approved) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "setApprovalForAll", to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(to address, approved bool) returns() +// Solidity: function setApprovalForAll(address to, bool approved) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(to address, approved bool) returns() +// Solidity: function setApprovalForAll(address to, bool approved) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "transferFrom", from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } @@ -671,7 +761,7 @@ type EthereumPaymentObligationContractApproval struct { // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) +// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractApprovalIterator, error) { var ownerRule []interface{} @@ -696,7 +786,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) +// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApproval, owner []common.Address, approved []common.Address, tokenId []*big.Int) (event.Subscription, error) { var ownerRule []interface{} @@ -821,7 +911,7 @@ type EthereumPaymentObligationContractApprovalForAll struct { // FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) +// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*EthereumPaymentObligationContractApprovalForAllIterator, error) { var ownerRule []interface{} @@ -842,7 +932,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) +// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApprovalForAll, owner []common.Address, operator []common.Address) (event.Subscription, error) { var ownerRule []interface{} @@ -963,7 +1053,7 @@ type EthereumPaymentObligationContractPaymentObligationMinted struct { // FilterPaymentObligationMinted is a free log retrieval operation binding the contract event 0xe2e4e975c4de5fbb1416db2c5ff8e2f4108bbfcdfd27a1a1eb03935cbfa3b8f9. // -// Solidity: e PaymentObligationMinted(to address, tokenId uint256, tokenURI string) +// Solidity: event PaymentObligationMinted(address to, uint256 tokenId, string tokenURI) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterPaymentObligationMinted(opts *bind.FilterOpts) (*EthereumPaymentObligationContractPaymentObligationMintedIterator, error) { logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "PaymentObligationMinted") @@ -975,7 +1065,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchPaymentObligationMinted is a free log subscription operation binding the contract event 0xe2e4e975c4de5fbb1416db2c5ff8e2f4108bbfcdfd27a1a1eb03935cbfa3b8f9. // -// Solidity: e PaymentObligationMinted(to address, tokenId uint256, tokenURI string) +// Solidity: event PaymentObligationMinted(address to, uint256 tokenId, string tokenURI) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchPaymentObligationMinted(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractPaymentObligationMinted) (event.Subscription, error) { logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "PaymentObligationMinted") @@ -1087,7 +1177,7 @@ type EthereumPaymentObligationContractTransfer struct { // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) +// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractTransferIterator, error) { var fromRule []interface{} @@ -1112,7 +1202,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) +// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractTransfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) { var fromRule []interface{} diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index e4bb8812b..398f54c39 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -64,7 +64,7 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [][]byte{v1, v2}, + Values: [][]byte{v1, v2, []uint8(nil), []uint8(nil)}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -119,7 +119,7 @@ func TestCreateProofData(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - proofData, err := createProofData(test.proofs) + proofData, err := createProofData(nil, test.proofs) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index 294c54a30..a840e6d06 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -85,10 +85,12 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address DueDate: ×tamp.Timestamp{Seconds: dueDate.Unix()}, }, }) - assert.Nil(t, err, "should not error out when creating invoice model") - modelUpdated, txID, _, err := invSrv.Create(ctx, model) - err = txManager.WaitForTransaction(cid, txID) - assert.Nil(t, err) + assert.NoError(t, err, "should not error out when creating invoice model") + modelUpdated, txID, done, err := invSrv.Create(ctx, model) + assert.NoError(t, err) + d := <-done + assert.True(t, d) + assert.NoError(t, txManager.WaitForTransaction(cid, txID)) // get ID id := modelUpdated.ID() @@ -102,10 +104,10 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address func mintNFT(t *testing.T, ctx context.Context, req nft.MintNFTRequest, cid identity.DID, registry common.Address) nft.TokenID { resp, done, err := payOb.MintNFT(ctx, req) - assert.Nil(t, err, "should not error out when minting an invoice") + assert.NoError(t, err, "should not error out when minting an invoice") assert.NotNil(t, resp.TokenID, "token id should be present") tokenID, err := nft.TokenIDFromString(resp.TokenID) - assert.Nil(t, err, "should not error out when getting tokenID hex") + assert.NoError(t, err, "should not error out when getting tokenID hex") <-done txID, err := transactions.FromString(resp.TransactionID) assert.NoError(t, err) @@ -117,14 +119,17 @@ func mintNFT(t *testing.T, ctx context.Context, req nft.MintNFTRequest, cid iden } func TestPaymentObligationService_mint_grant_read_access(t *testing.T) { - t.SkipNow() ctx, id, registry, depositAddr, invSrv, cid := prepareForNFTMinting(t) + regAddr := registry.String() + log.Info(regAddr) req := nft.MintNFTRequest{ - DocumentID: id, - RegistryAddress: registry, - DepositAddress: common.HexToAddress(depositAddr), - ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date"}, - GrantNFTReadAccess: true, + DocumentID: id, + RegistryAddress: registry, + DepositAddress: common.HexToAddress(depositAddr), + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", documents.CDTreePrefix + ".next_version"}, + GrantNFTReadAccess: true, + SubmitNFTReadAccessProof: true, + SubmitTokenProof: true, } tokenID := mintNFT(t, ctx, req, cid, registry) doc, err := invSrv.GetCurrentVersion(ctx, id) @@ -163,7 +168,6 @@ func failMintNFT(t *testing.T, grantNFT, nftReadAccess bool) { } func TestEthereumPaymentObligation_MintNFT_no_grant_access(t *testing.T) { - t.SkipNow() failMintNFT(t, false, true) } @@ -191,27 +195,9 @@ func mintNFTWithProofs(t *testing.T, grantAccess, tokenProof, readAccessProof bo } func TestEthereumPaymentObligation_MintNFT(t *testing.T) { - t.SkipNow() tests := []struct { grantAccess, tokenProof, readAccessProof bool }{ - { - grantAccess: true, - }, - - { - tokenProof: true, - }, - - { - grantAccess: true, - tokenProof: true, - }, - - { - grantAccess: true, - readAccessProof: true, - }, { grantAccess: true, tokenProof: true, diff --git a/testingutils/setup.go b/testingutils/setup.go index 989217683..8f3aff253 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -39,33 +39,49 @@ func RunSmartContractMigrations() { if isRunningOnCI { return } + + var err error projDir := GetProjectDir() migrationScript := path.Join(projDir, "build", "scripts", "migrate.sh") - _, err := exec.Command(migrationScript, projDir).Output() - if err != nil { - log.Fatal(err) + for i := 0; i < 3; i++ { + log.Infof("Trying to migrate contracts for the %d th time", i) + _, err = exec.Command(migrationScript, projDir).Output() + if err == nil { + return + } } + // trying 3 times to migrate didnt work + log.Fatal(err) } // GetSmartContractAddresses finds migrated smart contract addresses for localgeth func GetSmartContractAddresses() *config.SmartContractAddresses { - dat, err := findContractDeployJSON() + iddat, err := findContractDeployJSON("IdentityFactory.json") + if err != nil { + panic(err) + } + + ancdat, err := findContractDeployJSON("AnchorRepository.json") + if err != nil { + panic(err) + } + + payobdat, err := findContractDeployJSON("PaymentObligation.json") if err != nil { panic(err) } - idFactoryAddrOp := getOpForContract(".contracts.IdentityFactory.address") - anchorRepoAddrOp := getOpForContract(".contracts.AnchorRepository.address") - payObAddrOp := getOpForContract(".contracts.PaymentObligation.address") + + addrOp := getOpForContract(".networks.8383.address") return &config.SmartContractAddresses{ - IdentityFactoryAddr: getOpAddr(idFactoryAddrOp, dat), - AnchorRepositoryAddr: getOpAddr(anchorRepoAddrOp, dat), - PaymentObligationAddr: getOpAddr(payObAddrOp, dat), + IdentityFactoryAddr: getOpAddr(addrOp, iddat), + AnchorRepositoryAddr: getOpAddr(addrOp, ancdat), + PaymentObligationAddr: getOpAddr(addrOp, payobdat), } } -func findContractDeployJSON() ([]byte, error) { +func findContractDeployJSON(file string) ([]byte, error) { projDir := GetProjectDir() - deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "deployments", "localgeth.json") + deployJSONFile := path.Join(projDir, "vendor", "github.com", "centrifuge", "centrifuge-ethereum-contracts", "build", "contracts", file) dat, err := ioutil.ReadFile(deployJSONFile) if err != nil { return nil, err diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 83cc29180..0ae070629 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -6,38 +6,39 @@ import ( "net/http" "testing" + "github.com/centrifuge/go-centrifuge/documents" + "github.com/centrifuge/go-centrifuge/config" "github.com/stretchr/testify/assert" ) func TestPaymentObligationMint_invoice_successful(t *testing.T) { - t.SkipNow() t.Parallel() tests := []struct { name string grantAccess, tokenProof, readAccessProof bool }{ - { - name: "grant access", - grantAccess: true, - }, - - { - name: "token proof", - tokenProof: true, - }, - - { - name: "grant access and token proof", - grantAccess: true, - tokenProof: true, - }, - - { - name: "grant access and read access proof", - grantAccess: true, - readAccessProof: true, - }, + //{ + // name: "grant access", + // grantAccess: true, + //}, + // + //{ + // name: "token proof", + // tokenProof: true, + //}, + // + //{ + // name: "grant access and token proof", + // grantAccess: true, + // tokenProof: true, + //}, + // + //{ + // name: "grant access and read access proof", + // grantAccess: true, + // readAccessProof: true, + //}, { name: "grant access, token proof and read access proof", @@ -100,7 +101,7 @@ func paymentObligationMint(t *testing.T, documentType string, grantNFTAccess, to "identifier": docIdentifier, "registryAddress": doctorFord.getHost("Alice").config.GetContractAddress(config.PaymentObligation).String(), "depositAddress": "0x44a0579754d6c94e7bb2c26bfa7394311cc50ccb", // Centrifuge address - "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", "next_version"}, + "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", documents.CDTreePrefix + ".next_version"}, "submitTokenProof": tokenProof, "submitNftOwnerAccessProof": nftReadAccessProof, "grantNftAccess": grantNFTAccess, @@ -117,7 +118,6 @@ func paymentObligationMint(t *testing.T, documentType string, grantNFTAccess, to } func TestPaymentObligationMint_errors(t *testing.T) { - t.SkipNow() t.Parallel() alice := doctorFord.getHostTestSuite(t, "Alice") tests := []struct { diff --git a/transactions/txv1/base_task.go b/transactions/txv1/base_task.go index bd0a23c5e..3decd99fe 100644 --- a/transactions/txv1/base_task.go +++ b/transactions/txv1/base_task.go @@ -44,7 +44,7 @@ func (b *BaseTask) UpdateTransaction(accountID identity.DID, taskTypeName string // TODO this TaskStatus map update assumes that a single transaction has only one execution of a certain task type, which can be wrong, use the taskID or another unique identifier instead. if err != nil { - log.Errorf("Task %s failed for transaction: %v\n", taskTypeName, b.TxID.String()) + log.Errorf("Task %s failed for transaction: %v with error: %s\n", taskTypeName, b.TxID.String(), err.Error()) return errors.AppendError(err, b.TxManager.UpdateTaskStatus(accountID, b.TxID, transactions.Failed, taskTypeName, err.Error())) } From d0808c7c688b9fe526d16061bee11fcf7c21db69 Mon Sep 17 00:00:00 2001 From: Charly Date: Fri, 1 Mar 2019 20:16:48 +0100 Subject: [PATCH 210/220] Updated ReadACL tests to validate signing keys (#790) --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- documents/coredocument.go | 3 - documents/error.go | 32 +++++++++ documents/model.go | 6 +- documents/read_acls.go | 83 ++++++++++++------------ documents/read_acls_test.go | 66 ++++++++++--------- p2p/bootstrapper.go | 2 +- p2p/receiver/handler.go | 7 +- p2p/receiver/handler_integration_test.go | 2 +- p2p/receiver/handler_test.go | 2 +- p2p/server_test.go | 2 +- 12 files changed, 126 insertions(+), 85 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 7ac26fd3d..7381d405a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" [[projects]] - digest = "1:94366a6a33e0dbcfa2bdf4cffe474e66b517e7863662e2fb87f28e3cd6289409" + digest = "1:ba8eb492e68312a04979d7cf6bd5cd5152c72dafadce8f830f3b932158948c45" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "1bc057399d5d3658f8cd357b0ce22663de7c1ce8" + revision = "81ddb4a6e09ece1b82f541f77075c7996b79dc78" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 8b8e3f029..c0a4d1ea3 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "1bc057399d5d3658f8cd357b0ce22663de7c1ce8" + revision = "81ddb4a6e09ece1b82f541f77075c7996b79dc78" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/coredocument.go b/documents/coredocument.go index 153f713ff..a484b27fe 100644 --- a/documents/coredocument.go +++ b/documents/coredocument.go @@ -35,9 +35,6 @@ const ( // idSize represents the size of identifiers, roots etc.. idSize = 32 - // ErrNFTRoleMissing errors when role to generate proof doesn't exist - ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") - // nftByteCount is the length of combined bytes of registry and tokenID nftByteCount = 52 diff --git a/documents/error.go b/documents/error.go index 48524876d..c011f1a2a 100644 --- a/documents/error.go +++ b/documents/error.go @@ -56,6 +56,9 @@ const ( // ErrDocumentProof must be used when document proof creation fails ErrDocumentProof = errors.Error("document proof error") + // ErrDataRootInvalid must be used when the data root is invalid + ErrDataRootInvalid = errors.Error("data root is invalid") + // Document repository errors // ErrDocumentRepositoryModelNotRegistered must be used when the model hasn't been registered in the database repository @@ -75,6 +78,35 @@ const ( // ErrDocumentRepositoryModelDoesntExist must be used when document repository does not find an existing model for an update ErrDocumentRepositoryModelDoesntExist = errors.Error("document repository did not find an existing model for an update") + + // Read ACL errors + + // ErrNftNotFound must be used when the NFT is not found in the document + ErrNftNotFound = errors.Error("nft not found in the Document") + + // ErrNftByteLength must be used when there is a byte length mismatch + ErrNftByteLength = errors.Error("byte length mismatch") + + // ErrAccessTokenInvalid must be used when the access token is invalid + ErrAccessTokenInvalid = errors.Error("access token is invalid") + + // ErrAccessTokenNotFound must be used when the access token was not found + ErrAccessTokenNotFound = errors.Error("access token not found") + + // ErrRequesterNotGrantee must be used when the document requester is not the grantee of the access token + ErrRequesterNotGrantee = errors.Error("requester is not the same as the access token grantee") + + // ErrGranterNotCollab must be used when the granter of the access token is not a collaborator on the document + ErrGranterNotCollab = errors.Error("access token granter is not a collaborator on this document") + + // ErrReqDocNotMatch must be used when the requested document does not match the access granted by the access token + ErrReqDocNotMatch = errors.Error("the document requested does not match the document to which the access token grants access") + + // ErrNFTRoleMissing errors when role to generate proof doesn't exist + ErrNFTRoleMissing = errors.Error("NFT Role doesn't exist") + + // ErrInvalidIDLength must be used when the identifier bytelength is not 32 + ErrInvalidIDLength = errors.Error("invalid identifier length") ) // Error wraps an error with specific key diff --git a/documents/model.go b/documents/model.go index f3adde943..750efd735 100644 --- a/documents/model.go +++ b/documents/model.go @@ -1,6 +1,8 @@ package documents import ( + "context" + "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/storage" @@ -85,8 +87,8 @@ type Model interface { // NFTOwnerCanRead returns error if the NFT cannot read the document. NFTOwnerCanRead(tokenRegistry TokenRegistry, registry common.Address, tokenID []byte, account identity.DID) error - // ATOwnerCanRead returns error if the NFT cannot read the document. - ATOwnerCanRead(tokenID, docID []byte, account identity.DID) (err error) + // ATGranteeCanRead returns error if the access token grantee cannot read the document. + ATGranteeCanRead(ctx context.Context, idSrv identity.ServiceDID, tokenID, docID []byte, grantee identity.DID) (err error) } // TokenRegistry defines NFT related functions. diff --git a/documents/read_acls.go b/documents/read_acls.go index dc0fcb74a..692c7a757 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -77,7 +77,7 @@ func (cd *CoreDocument) NFTOwnerCanRead(tokenRegistry TokenRegistry, registry co }, coredocumentpb.Action_ACTION_READ) if !found { - return errors.New("nft not found in the Document") + return ErrNftNotFound } // get the owner of the NFT @@ -86,7 +86,6 @@ func (cd *CoreDocument) NFTOwnerCanRead(tokenRegistry TokenRegistry, registry co return errors.New("failed to get NFT owner: %v", err) } - // TODO(ved): this will always fail until we roll out identity v2 with CentID type as common.Address if !bytes.Equal(owner.Bytes(), account[:]) { return errors.New("account (%v) not owner of the NFT", account.String()) } @@ -165,7 +164,7 @@ func (cd *CoreDocument) CreateNFTProofs( nftUniqueProof, readAccessProof bool) (proofs []*proofspb.Proof, err error) { if len(cd.Document.DataRoot) != idSize { - return nil, errors.New("data root is invalid") + return nil, ErrDataRootInvalid } var pfKeys []string @@ -215,7 +214,7 @@ func ConstructNFT(registry common.Address, tokenID []byte) ([]byte, error) { nft = append(nft, tokenID...) if len(nft) != nftByteCount { - return nil, errors.New("byte length mismatch") + return nil, ErrNftByteLength } return nft, nil @@ -280,7 +279,7 @@ func getReadAccessProofKeys(cd coredocumentpb.CoreDocument, registry common.Addr func getNFTUniqueProofKey(nfts []*coredocumentpb.NFT, registry common.Address) (pk string, err error) { nft := getStoredNFT(nfts, registry.Bytes()) if nft == nil { - return pk, errors.New("nft is missing from the Document") + return pk, ErrNftNotFound } key := hexutil.Encode(nft.RegistryId) @@ -322,16 +321,6 @@ func getRole(key []byte, roles []*coredocumentpb.Role) (*coredocumentpb.Role, er return nil, errors.New("role %d not found", key) } -// isATInRole checks if the given access token is part of the core document role. -func isATInRole(role *coredocumentpb.Role, tokenID []byte) (*coredocumentpb.AccessToken, error) { - for _, a := range role.AccessTokens { - if bytes.Equal(tokenID, a.Identifier) { - return a, nil - } - } - return nil, errors.New("access token not found") -} - // validateAT validates that given access token against its signature func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID []byte) error { // assemble token message from the token for validation @@ -343,57 +332,69 @@ func validateAT(publicKey []byte, token *coredocumentpb.AccessToken, requesterID } validated := crypto.VerifyMessage(publicKey, tm, token.Signature, crypto.CurveSecp256K1) if !validated { - return errors.New("access token is invalid") + return ErrAccessTokenInvalid } return nil } -// ATOwnerCanRead checks that the owner AT can read the document requested -func (cd *CoreDocument) ATOwnerCanRead(tokenID, docID []byte, account identity.DID) (err error) { - // check if the access token is present in read rules of the document indicated in the AT request - var at *coredocumentpb.AccessToken - findRole(cd.Document, func(_, _ int, role *coredocumentpb.Role) bool { - at, err = isATInRole(role, tokenID) - if err != nil { - return false +func (cd *CoreDocument) findAT(tokenID []byte) (at *coredocumentpb.AccessToken, err error) { + // check if the access token is present on the document indicated in the AT request + for _, at := range cd.Document.AccessTokens { + if bytes.Equal(tokenID, at.Identifier) { + return at, nil } + } + return at, ErrAccessTokenNotFound +} - return true - }, coredocumentpb.Action_ACTION_READ) - +// ATGranteeCanRead checks that the grantee of the access token can read the document requested +func (cd *CoreDocument) ATGranteeCanRead(ctx context.Context, idService identity.ServiceDID, tokenID, docID []byte, requesterID identity.DID) (err error) { + // find the access token + at, err := cd.findAT(tokenID) if err != nil { return err } - + granterID := identity.NewDIDFromBytes(at.Granter) + granteeID := identity.NewDIDFromBytes(at.Grantee) + // check that the peer requesting access is the same identity as the access token grantee + if !requesterID.Equal(granteeID) { + return ErrRequesterNotGrantee + } + // check that the granter of the access token is a collaborator on the document + verified := cd.AccountCanRead(granterID) + if !verified { + return ErrGranterNotCollab + } // check if the requested document is the document indicated in the access token if !bytes.Equal(at.DocumentIdentifier, docID) { - return errors.New("the document requested does not match the document to which the access token grants access") + return ErrReqDocNotMatch } - // validate the access token - // TODO: fetch public key from Ethereum chain - return validateAT(at.Key, at, account[:]) + // validate that the public key of the granter is the public key that has been used to sign the access token + err = idService.ValidateKey(ctx, granterID, at.Key, identity.KeyPurposeSigning) + if err != nil { + return err + } + return validateAT(at.Key, at, granteeID[:]) } -// AddAccessToken adds the AccessToken to the read rules of the document +// AddAccessToken adds the AccessToken to the document func (cd *CoreDocument) AddAccessToken(ctx context.Context, payload documentpb.AccessTokenParams) (*CoreDocument, error) { ncd, err := cd.PrepareNewVersion(nil, false) if err != nil { return nil, err } - role := newRole() - at, err := assembleAccessToken(ctx, payload, role.RoleKey) + at, err := assembleAccessToken(ctx, payload) if err != nil { return nil, errors.New("failed to construct access token: %v", err) } - role.AccessTokens = append(role.AccessTokens, at) - ncd.addNewRule(role, coredocumentpb.Action_ACTION_READ) + ncd.Document.AccessTokens = append(ncd.Document.AccessTokens, at) return ncd, ncd.setSalts() } // assembleAccessToken assembles a Read Access Token from the payload received -func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenParams, roleKey []byte) (*coredocumentpb.AccessToken, error) { +func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenParams) (*coredocumentpb.AccessToken, error) { account, err := contextutil.Account(ctx) if err != nil { return nil, err @@ -404,7 +405,8 @@ func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenPara return nil, err } granterID := identity.NewDIDFromBytes(id) - roleID := roleKey + // TODO: this roleID will be specified later with field level read access + roleID := utils.RandomSlice(32) granteeID, err := identity.NewDIDFromString(payload.Grantee) if err != nil { return nil, err @@ -421,7 +423,6 @@ func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenPara } // fetch key pair from identity - // TODO: change to signing key pair once secp scheme is available sig, err := account.SignMsg(tm) if err != nil { return nil, err @@ -451,7 +452,7 @@ func assembleTokenMessage(tokenIdentifier []byte, granterID identity.DID, grante ids := [][]byte{tokenIdentifier, roleID, docID} for _, id := range ids { if len(id) != idSize { - return nil, errors.New("invalid identifier length") + return nil, ErrInvalidIDLength } } diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go index 8eb0d3153..ec04b1a22 100644 --- a/documents/read_acls_test.go +++ b/documents/read_acls_test.go @@ -6,18 +6,17 @@ import ( "fmt" "testing" - "github.com/centrifuge/go-centrifuge/testingutils/identity" - - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" - "github.com/centrifuge/go-centrifuge/testingutils/config" - "github.com/centrifuge/centrifuge-protobufs/documenttypes" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" + "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" + "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" "github.com/centrifuge/go-centrifuge/protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/commons" + "github.com/centrifuge/go-centrifuge/testingutils/config" + "github.com/centrifuge/go-centrifuge/testingutils/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -119,7 +118,11 @@ func TestCoreDocument_NFTOwnerCanRead(t *testing.T) { assert.Error(t, cd.NFTOwnerCanRead(tr, registry, tokenID, account)) tr.AssertExpectations(t) - // TODO(ved): add a successful test once identity v2 is complete + // same owner + owner = account.ToAddress() + tr.On("OwnerOf", registry, tokenID).Return(owner, nil).Once() + assert.NoError(t, cd.NFTOwnerCanRead(tr, registry, tokenID, account)) + tr.AssertExpectations(t) } func TestCoreDocumentModel_AddNFT(t *testing.T) { @@ -324,17 +327,20 @@ func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { assert.True(t, valid) } } - } func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { ctx := testingconfig.CreateAccountContext(t, cfg) account, _ := contextutil.Account(ctx) - cd := newCoreDocument() - cd.Document.DocumentRoot = utils.RandomSlice(32) + srv := new(testingcommons.MockIdentityService) id, err := account.GetIdentityID() - granteeID := identity.NewDIDFromBytes(id) + granteeID, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") + assert.NoError(t, err) + granterID := identity.NewDIDFromBytes(id) assert.NoError(t, err) + cd, err := NewCoreDocumentWithCollaborators([]string{granterID.String()}) + assert.NoError(t, err) + cd.Document.DocumentRoot = utils.RandomSlice(32) payload := documentpb.AccessTokenParams{ Grantee: hexutil.Encode(granteeID[:]), DocumentIdentifier: hexutil.Encode(cd.Document.DocumentIdentifier), @@ -342,8 +348,7 @@ func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { ncd, err := cd.AddAccessToken(ctx, payload) assert.NoError(t, err) ncd.Document.DocumentRoot = utils.RandomSlice(32) - docRoles := ncd.Document.GetRoles() - at := docRoles[0].AccessTokens[0] + at := ncd.Document.AccessTokens[0] assert.NotNil(t, at) // wrong token identifier tr := &p2ppb.AccessTokenRequest{ @@ -355,20 +360,24 @@ func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { AccessType: p2ppb.AccessType_ACCESS_TYPE_ACCESS_TOKEN_VERIFICATION, AccessTokenRequest: tr, } - err = ncd.ATOwnerCanRead(dr.AccessTokenRequest.AccessTokenId, dr.DocumentIdentifier, granteeID) + err = ncd.ATGranteeCanRead(ctx, srv, dr.AccessTokenRequest.AccessTokenId, dr.DocumentIdentifier, granteeID) assert.Error(t, err, "access token not found") - // valid access token - // TODO: this will always fail until validation for signatures is secp - //tr = &p2ppb.AccessTokenRequest{ - // DelegatingDocumentIdentifier: dm.Document.DocumentIdentifier, - // AccessTokenId: at.Identifier, - //} - //dr.AccessTokenRequest = tr - //err = dm.accessTokenOwnerCanRead(dr, granteeID[:]) - //assert.NoError(t, err) + // invalid signing key + tr = &p2ppb.AccessTokenRequest{ + DelegatingDocumentIdentifier: ncd.Document.DocumentIdentifier, + AccessTokenId: at.Identifier, + } + dr.AccessTokenRequest = tr + srv.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("key not linked to identity")).Once() + err = ncd.ATGranteeCanRead(ctx, srv, dr.AccessTokenRequest.AccessTokenId, dr.DocumentIdentifier, granteeID) + assert.Error(t, err) + // valid key + srv.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + err = ncd.ATGranteeCanRead(ctx, srv, dr.AccessTokenRequest.AccessTokenId, dr.DocumentIdentifier, granteeID) + assert.NoError(t, err) } -func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { +func TestCoreDocumentModel_AddAccessToken(t *testing.T) { m := newCoreDocument() m.Document.DocumentRoot = utils.RandomSlice(32) ctx := testingconfig.CreateAccountContext(t, cfg) @@ -376,8 +385,7 @@ func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { assert.NoError(t, err) cd := m.Document - assert.Len(t, cd.ReadRules, 0) - assert.Len(t, cd.Roles, 0) + assert.Len(t, cd.AccessTokens, 0) // invalid centID format payload := documentpb.AccessTokenParams{ @@ -416,7 +424,5 @@ func TestCoreDocumentModel_AddAccessTokenToReadRules(t *testing.T) { ncd, err := m.AddAccessToken(ctx, payload) assert.NoError(t, err) - assert.Len(t, ncd.Document.ReadRules, 1) - assert.Equal(t, ncd.Document.ReadRules[0].Action, coredocumentpb.Action_ACTION_READ) - assert.Len(t, ncd.Document.Roles, 1) + assert.Len(t, ncd.Document.AccessTokens, 1) } diff --git a/p2p/bootstrapper.go b/p2p/bootstrapper.go index 54b64bda5..baaf21072 100644 --- a/p2p/bootstrapper.go +++ b/p2p/bootstrapper.go @@ -42,7 +42,7 @@ func (b Bootstrapper) Bootstrap(ctx map[string]interface{}) error { } ctx[bootstrap.BootstrappedPeer] = &peer{config: cfgService, idService: idService, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, tokenRegistry) + return receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, tokenRegistry, idService) }} return nil } diff --git a/p2p/receiver/handler.go b/p2p/receiver/handler.go index 0adb64980..a3ae67486 100644 --- a/p2p/receiver/handler.go +++ b/p2p/receiver/handler.go @@ -25,6 +25,7 @@ type Handler struct { handshakeValidator ValidatorGroup docSrv documents.Service tokenRegistry documents.TokenRegistry + srvDID identity.ServiceDID } // New returns an implementation of P2PServiceServer @@ -32,12 +33,14 @@ func New( config config.Service, handshakeValidator ValidatorGroup, docSrv documents.Service, - tokenRegistry documents.TokenRegistry) *Handler { + tokenRegistry documents.TokenRegistry, + srvDID identity.ServiceDID) *Handler { return &Handler{ config: config, handshakeValidator: handshakeValidator, docSrv: docSrv, tokenRegistry: tokenRegistry, + srvDID: srvDID, } } @@ -248,7 +251,7 @@ func (srv *Handler) validateDocumentAccess(ctx context.Context, docReq *p2ppb.Ge return err } - err = m.ATOwnerCanRead(docReq.AccessTokenRequest.AccessTokenId, docReq.DocumentIdentifier, peer) + err = m.ATGranteeCanRead(ctx, srv.srvDID, docReq.AccessTokenRequest.AccessTokenId, docReq.DocumentIdentifier, peer) if err != nil { return err } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 90ad0bbfe..48679de28 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -60,7 +60,7 @@ func TestMain(m *testing.M) { anchorRepo = ctx[anchors.BootstrappedAnchorRepo].(anchors.AnchorRepository) idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) - handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, new(testingdocuments.MockRegistry)) + handler = receiver.New(cfgService, receiver.HandshakeValidator(cfg.GetNetworkID(), idService), docSrv, new(testingdocuments.MockRegistry), idService) defaultDID = createIdentity(&testing.T{}) result := m.Run() testingbootstrap.TestFunctionalEthereumTearDown() diff --git a/p2p/receiver/handler_test.go b/p2p/receiver/handler_test.go index 6da90b801..f553f2317 100644 --- a/p2p/receiver/handler_test.go +++ b/p2p/receiver/handler_test.go @@ -70,7 +70,7 @@ func TestMain(m *testing.M) { _, pub, _ := crypto.GenerateEd25519Key(rand.Reader) defaultPID, _ = libp2pPeer.IDFromPublicKey(pub) mockIDService.On("ValidateKey", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv, new(testingdocuments.MockRegistry)) + handler = New(cfgService, HandshakeValidator(cfg.GetNetworkID(), mockIDService), docSrv, new(testingdocuments.MockRegistry), mockIDService) result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/p2p/server_test.go b/p2p/server_test.go index 9f5ddcf18..e06b99223 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -68,7 +68,7 @@ func TestCentP2PServer_StartContextCancel(t *testing.T) { cfgMock := mockmockConfigStore(n) assert.NoError(t, err) cp2p := &peer{config: cfgMock, handlerCreator: func() *receiver.Handler { - return receiver.New(cfgMock, receiver.HandshakeValidator(n.NetworkID, idService), nil, new(testingdocuments.MockRegistry)) + return receiver.New(cfgMock, receiver.HandshakeValidator(n.NetworkID, idService), nil, new(testingdocuments.MockRegistry), idService) }} ctx, canc := context.WithCancel(context.Background()) startErr := make(chan error, 1) From 593c8236a306552aa80085de6802b6f524a835a5 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Fri, 1 Mar 2019 21:04:04 +0100 Subject: [PATCH 211/220] Testworld test (#793) * Enabling all nft tests * node version * node version * block gas limit * Fixes * Fixes * NFT minting works * Fix testworld stuff * Minor * New anchor bindings * Fixes * Fixes * Newest id contracts and skipping execute test * Fixes * Try changing parallel execution to make testworld go through * Minor logging stuff --- anchors/service.go | 6 ++---- build/scripts/tests/run_testworld.sh | 2 +- testworld/document_consensus_test.go | 1 - testworld/park.go | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/anchors/service.go b/anchors/service.go index 4cd1cf446..7a576ca50 100644 --- a/anchors/service.go +++ b/anchors/service.go @@ -4,16 +4,14 @@ import ( "context" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) diff --git a/build/scripts/tests/run_testworld.sh b/build/scripts/tests/run_testworld.sh index b6fb8d9c9..0187ebd06 100755 --- a/build/scripts/tests/run_testworld.sh +++ b/build/scripts/tests/run_testworld.sh @@ -8,7 +8,7 @@ eval "$cleanup" status=$? -output="go test -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" +output="go test -v -coverprofile=profile.out -covermode=atomic -tags=testworld github.com/centrifuge/go-centrifuge/testworld 2>&1" eval "$output" | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done if [ ${PIPESTATUS[0]} -ne 0 ]; then status=1 diff --git a/testworld/document_consensus_test.go b/testworld/document_consensus_test.go index 078fd5ee5..cf75aa57b 100644 --- a/testworld/document_consensus_test.go +++ b/testworld/document_consensus_test.go @@ -37,7 +37,6 @@ func TestHost_AddExternalCollaborator(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - t.Parallel() switch test.testType { case multiHost: addExternalCollaborator(t, test.docType) diff --git a/testworld/park.go b/testworld/park.go index 14ce83cad..2d1cee56e 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -375,6 +375,7 @@ func (h *host) createAccounts(e *httpexpect.Expect) error { } // create 3 accounts for i := 0; i < 3; i++ { + log.Infof("creating account %d for host %s", i, h.name) res := generateAccount(e, h.identity.String(), http.StatusOK) res.Value("identity_id").String().NotEmpty() } From 7445cc2d39cc35f03ca6ac03d4eb6601001b1c54 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Mon, 4 Mar 2019 17:02:15 +0100 Subject: [PATCH 212/220] fixed identity execute tests by adding an action key (#792) * fixed identity execute tests by added action key * added verbose flag to testworld tests --- identity/ideth/execute_integration_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/identity/ideth/execute_integration_test.go b/identity/ideth/execute_integration_test.go index 23a903e84..3b8c19785 100644 --- a/identity/ideth/execute_integration_test.go +++ b/identity/ideth/execute_integration_test.go @@ -42,19 +42,32 @@ func getAnchorAddress(cfg config.Configuration) common.Address { } func TestExecute_successful(t *testing.T) { - t.SkipNow() did := deployIdentityContract(t) aCtx := getTestDIDContext(t, *did) idSrv := initIdentity() anchorAddress := getAnchorAddress(cfg) + // add node Ethereum address as a action key + // only an action key can use the execute method + actionPurpose := utils.ByteSliceToBigInt([]byte{2}) + ethAccount, err := cfg.GetEthereumAccount(cfg.GetEthereumDefaultAccountName()) + assert.Nil(t, err) + actionAddress := ethAccount.Address + + //add action key + actionKey := utils.AddressTo32Bytes(common.HexToAddress(actionAddress)) + key := id.NewKey(actionKey, actionPurpose, utils.ByteSliceToBigInt([]byte{123})) + err = idSrv.AddKey(aCtx, key) + assert.Nil(t, err) + // init params testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - err := idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + // call execute + err = idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) assert.Nil(t, err, "Execute method calls should be successful") checkAnchor(t, testAnchorId, rootHash) From a3ef4a2079ad027d67b63a62f6d7044420bcc5c5 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 5 Mar 2019 00:46:00 +0100 Subject: [PATCH 213/220] Expose p2p signature collection errors and ignore at correct level (#810) --- documents/processor.go | 5 +++-- documents/processor_test.go | 4 ++-- p2p/client.go | 16 ++++++++-------- p2p/client_integration_test.go | 7 +++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/documents/processor.go b/documents/processor.go index a12439b29..7cbee8256 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -24,7 +24,7 @@ type Config interface { type Client interface { // GetSignaturesForDocument gets the signatures for document - GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, error) + GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, []error, error) // after all signatures are collected the sender sends the document including the signatures SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) @@ -100,7 +100,8 @@ func (dp defaultProcessor) RequestSignatures(ctx context.Context, model Model) e return errors.New("failed to validate model for signature request: %v", err) } - signs, err := dp.p2pClient.GetSignaturesForDocument(ctx, model) + // we ignore signature collection errors and anchor anyways + signs, _, err := dp.p2pClient.GetSignaturesForDocument(ctx, model) if err != nil { return errors.New("failed to collect signatures from the collaborators: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index 799355443..c88b303f8 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -156,10 +156,10 @@ type p2pClient struct { Client } -func (p *p2pClient) GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, error) { +func (p *p2pClient) GetSignaturesForDocument(ctx context.Context, model Model) ([]*coredocumentpb.Signature, []error, error) { args := p.Called(ctx, model) sigs, _ := args.Get(0).([]*coredocumentpb.Signature) - return sigs, args.Error(1) + return sigs, nil, args.Error(1) } func (p *p2pClient) SendAnchoredDocument(ctx context.Context, receiverID identity.DID, in *p2ppb.AnchorDocumentRequest) (*p2ppb.AnchorDocumentResponse, error) { diff --git a/p2p/client.go b/p2p/client.go index 3cc5db598..263aa8a6c 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -212,28 +212,28 @@ func (s *peer) getSignatureAsync(ctx context.Context, cd coredocumentpb.CoreDocu } // GetSignaturesForDocument requests peer nodes for the signature, verifies them, and returns those signatures. -func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Model) (signatures []*coredocumentpb.Signature, err error) { +func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Model) (signatures []*coredocumentpb.Signature, signatureCollectionErrors []error, err error) { in := make(chan signatureResponseWrap) defer close(in) nc, err := s.config.GetConfig() if err != nil { - return nil, err + return nil, nil, err } self, err := contextutil.Self(ctx) if err != nil { - return nil, errors.New("failed to get self ID") + return nil, nil, errors.New("failed to get self ID") } cs, err := model.GetSignerCollaborators(self.ID) if err != nil { - return nil, errors.New("failed to get external collaborators") + return nil, nil, errors.New("failed to get external collaborators") } cd, err := model.PackCoreDocument() if err != nil { - return nil, errors.New("failed to pack core document: %v", err) + return nil, nil, errors.New("failed to pack core document: %v", err) } var count int @@ -250,15 +250,15 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Mod for _, resp := range responses { if resp.err != nil { - // this error is ignored since we would still anchor the document - log.Error(resp.err) + log.Warning(resp.err) + signatureCollectionErrors = append(signatureCollectionErrors, resp.err) continue } signatures = append(signatures, resp.resp.Signature) } - return signatures, nil + return signatures, signatureCollectionErrors, nil } func convertClientError(recv *p2ppb.Envelope) error { diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index 43b8928c3..dc69f0167 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -10,14 +10,13 @@ import ( "time" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/centrifuge-protobufs/gen/go/p2p" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers/testingbootstrap" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/documents" "github.com/centrifuge/go-centrifuge/documents/purchaseorder" "github.com/centrifuge/go-centrifuge/identity" @@ -69,7 +68,7 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { ctxh, err := contextutil.New(context.Background(), acci) assert.Nil(t, err) dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - signs, err := client.GetSignaturesForDocument(ctxh, dm) + signs, _, err := client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) assert.NotNil(t, signs) } @@ -82,7 +81,7 @@ func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { acci.IdentityID = defaultDID[:] ctxh, err := contextutil.New(context.Background(), acci) dm := prepareDocumentForP2PHandler(t, [][]byte{tc.IdentityID}) - signs, err := client.GetSignaturesForDocument(ctxh, dm) + signs, _, err := client.GetSignaturesForDocument(ctxh, dm) assert.NoError(t, err) // one signature would be missing assert.Equal(t, 0, len(signs)) From 1007c107a26a00b95bef4ca562bb5b6211a754b9 Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Tue, 5 Mar 2019 16:06:31 +0100 Subject: [PATCH 214/220] Adapt purposes + remove ethauth (#787) * Adapt purposes + remove ethauth * comments * wip action key * remove IDConfig * fix unit * fixes * fixes * comments --- build/configs/testing_config.yaml | 3 - cmd/common.go | 4 +- cmd/common_test.go | 23 +-- config/configstore/model.go | 104 ++++++------- config/configstore/model_test.go | 15 -- config/configstore/service.go | 21 +-- .../configstore/service_integration_test.go | 2 - config/configstore/service_test.go | 6 +- config/configuration.go | 17 +-- contextutil/context.go | 22 +-- crypto/secp256k1/secp256k1_test.go | 29 ---- documents/coredocument_test.go | 2 - documents/invoice/model_test.go | 33 +++-- documents/invoice/service.go | 16 +- documents/processor.go | 4 +- documents/processor_test.go | 7 +- documents/purchaseorder/model_test.go | 31 ++-- documents/purchaseorder/service.go | 16 +- documents/read_acls.go | 4 +- identity/did.go | 138 ++++++++++-------- identity/did_test.go | 75 ++++++++++ identity/ideth/execute_integration_test.go | 3 +- identity/ideth/factory.go | 25 ---- identity/ideth/service.go | 66 +++------ identity/ideth/service_integration_test.go | 10 +- nft/ethereum_payment_obligation_test.go | 1 - nft/payment_obligation_integration_test.go | 2 +- notification/notification_test.go | 4 +- p2p/client.go | 4 +- p2p/client_integration_test.go | 27 ++-- p2p/client_test.go | 2 +- p2p/common/protocol_test.go | 4 - p2p/messenger/messenger_test.go | 2 - p2p/receiver/handler_integration_test.go | 47 +++--- p2p/receiver/validator.go | 2 +- p2p/server_test.go | 4 +- protobufs/account/service.proto | 1 - protobufs/gen/go/account/service.pb.go | 119 +++++++-------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/account/service.swagger.json | 3 - .../gen/swagger/config/service.swagger.json | 3 - resources/data.go | 4 +- testingutils/commons/mock_did_identity.go | 2 +- testingutils/config/config.go | 7 +- testingutils/identity/identity.go | 21 +-- testingutils/setup.go | 2 - transactions/txv1/manager_test.go | 4 +- utils/tools.go | 13 +- 48 files changed, 439 insertions(+), 517 deletions(-) create mode 100644 identity/did_test.go diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index 97b2bab30..055aeb2b5 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -23,6 +23,3 @@ keys: signing: publicKey: ../../build/resources/signingKey.pub.pem privateKey: ../../build/resources/signingKey.key.pem - ethauth: - publicKey: ../../build/resources/ethauth.pub.pem - privateKey: ../../build/resources/ethauth.key.pem diff --git a/cmd/common.go b/cmd/common.go index 807d9875d..b57da38cc 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -25,10 +25,8 @@ var log = logging.Logger("centrifuge-cmd") func generateKeys(config config.Configuration) { p2pPub, p2pPvt := config.GetP2PKeyPair() signPub, signPvt := config.GetSigningKeyPair() - ethAuthPub, ethAuthPvt := config.GetEthAuthKeyPair() crypto.GenerateSigningKeyPair(p2pPub, p2pPvt, crypto.CurveEd25519) crypto.GenerateSigningKeyPair(signPub, signPvt, crypto.CurveSecp256K1) - crypto.GenerateSigningKeyPair(ethAuthPub, ethAuthPvt, crypto.CurveSecp256K1) } // CreateConfig creates a config file using provide parameters and the default config @@ -76,7 +74,7 @@ func CreateConfig( // create keys locally generateKeys(cfg) - acc, err := configstore.TempAccount("", cfg) + acc, err := configstore.TempAccount("main", cfg) if err != nil { return err } diff --git a/cmd/common_test.go b/cmd/common_test.go index 0afc4aa6d..5341779a1 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -4,7 +4,6 @@ package cmd import ( "context" - "math/big" "os" "os/exec" "path" @@ -76,34 +75,24 @@ func TestCreateConfig(t *testing.T) { assert.Equal(t, true, len(contractCode) > 3000, "current contract code should be around 3378 bytes") // Keys exists - // type KeyPurposeEthMsgAuth - idSrv := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) - pk, _, err := secp256k1.GetSigningKeyPair(cfg.GetEthAuthKeyPair()) - assert.Nil(t, err) - address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - assert.Nil(t, err) - response, err := idSrv.GetKey(accountId, address32Bytes) - assert.Nil(t, err) - assert.NotNil(t, response) - assert.Equal(t, big.NewInt(identity.KeyPurposeEthMsgAuth), response.Purposes[0], "purpose should be ETHMsgAuth") - // type KeyPurposeP2P - pk, _, err = ed25519.GetSigningKeyPair(cfg.GetP2PKeyPair()) + idSrv := ctx[identity.BootstrappedDIDService].(identity.ServiceDID) + pk, _, err := ed25519.GetSigningKeyPair(cfg.GetP2PKeyPair()) assert.Nil(t, err) pk32, err := utils.SliceToByte32(pk) assert.Nil(t, err) - response, _ = idSrv.GetKey(accountId, pk32) + response, _ := idSrv.GetKey(accountId, pk32) assert.NotNil(t, response) - assert.Equal(t, big.NewInt(identity.KeyPurposeP2P), response.Purposes[0], "purpose should be P2P") + assert.Equal(t, &(identity.KeyPurposeP2PDiscovery.Value), response.Purposes[0], "purpose should be P2P") // type KeyPurposeSigning pk, _, err = secp256k1.GetSigningKeyPair(cfg.GetSigningKeyPair()) assert.Nil(t, err) - address32Bytes = utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) + address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) assert.Nil(t, err) response, _ = idSrv.GetKey(accountId, address32Bytes) assert.NotNil(t, response) - assert.Equal(t, big.NewInt(identity.KeyPurposeSigning), response.Purposes[0], "purpose should be Signing") + assert.Equal(t, &(identity.KeyPurposeSigning.Value), response.Purposes[0], "purpose should be Signing") err = exec.Command("rm", "-rf", dataDir).Run() assert.Nil(t, err, "removing testconfig folder should be successful") diff --git a/config/configstore/model.go b/config/configstore/model.go index 414fc16c3..5251e184b 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -1,6 +1,7 @@ package configstore import ( + "encoding/hex" "encoding/json" "math/big" "reflect" @@ -264,11 +265,6 @@ func (nc *NodeConfig) GetSigningKeyPair() (pub, priv string) { return nc.MainIdentity.SigningKeyPair.Pub, nc.MainIdentity.SigningKeyPair.Priv } -// GetEthAuthKeyPair refer the interface -func (nc *NodeConfig) GetEthAuthKeyPair() (pub, priv string) { - return nc.MainIdentity.EthAuthKeyPair.Pub, nc.MainIdentity.EthAuthKeyPair.Priv -} - // IsPProfEnabled refer the interface func (nc *NodeConfig) IsPProfEnabled() bool { return nc.PprofEnabled @@ -306,10 +302,6 @@ func (nc *NodeConfig) CreateProtobuf() *configpb.ConfigData { EthDefaultAccountName: nc.MainIdentity.EthereumDefaultAccountName, IdentityId: common.BytesToAddress(nc.MainIdentity.IdentityID).Hex(), ReceiveEventNotificationEndpoint: nc.MainIdentity.ReceiveEventNotificationEndpoint, - EthauthKeyPair: &accountpb.KeyPair{ - Pub: nc.MainIdentity.EthAuthKeyPair.Pub, - Pvt: nc.MainIdentity.EthAuthKeyPair.Priv, - }, SigningKeyPair: &accountpb.KeyPair{ Pub: nc.MainIdentity.SigningKeyPair.Pub, Pvt: nc.MainIdentity.SigningKeyPair.Priv, @@ -369,10 +361,6 @@ func (nc *NodeConfig) loadFromProtobuf(data *configpb.ConfigData) error { Pub: data.MainIdentity.SigningKeyPair.Pub, Priv: data.MainIdentity.SigningKeyPair.Pvt, }, - EthAuthKeyPair: KeyPair{ - Pub: data.MainIdentity.EthauthKeyPair.Pub, - Priv: data.MainIdentity.EthauthKeyPair.Pvt, - }, } nc.StoragePath = data.StoragePath nc.P2PPort = int(data.P2PPort) @@ -432,7 +420,6 @@ func NewNodeConfig(c config.Configuration) config.Configuration { mainIdentity, _ := c.GetIdentityID() p2pPub, p2pPriv := c.GetP2PKeyPair() signPub, signPriv := c.GetSigningKeyPair() - ethAuthPub, ethAuthPriv := c.GetEthAuthKeyPair() return &NodeConfig{ MainIdentity: Account{ @@ -452,10 +439,6 @@ func NewNodeConfig(c config.Configuration) config.Configuration { Pub: signPub, Priv: signPriv, }, - EthAuthKeyPair: KeyPair{ - Pub: ethAuthPub, - Priv: ethAuthPriv, - }, }, StoragePath: c.GetStoragePath(), AccountsKeystore: c.GetAccountsKeystore(), @@ -499,9 +482,8 @@ type Account struct { ReceiveEventNotificationEndpoint string IdentityID []byte SigningKeyPair KeyPair - EthAuthKeyPair KeyPair P2PKeyPair KeyPair - keys map[int]config.IDKey + keys map[string]config.IDKey } // GetEthereumAccount gets EthereumAccount @@ -534,11 +516,6 @@ func (acc *Account) GetSigningKeyPair() (pub, priv string) { return acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv } -// GetEthAuthKeyPair gets EthAuthKeyPair -func (acc *Account) GetEthAuthKeyPair() (pub, priv string) { - return acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv -} - // GetEthereumContextWaitTimeout gets EthereumContextWaitTimeout func (acc *Account) GetEthereumContextWaitTimeout() time.Duration { return acc.EthereumContextWaitTimeout @@ -550,7 +527,7 @@ func (acc *Account) SignMsg(msg []byte) (*coredocumentpb.Signature, error) { if err != nil { return nil, err } - signature, err := crypto.SignMessage(keys[identity.KeyPurposeSigning].PrivateKey, msg, crypto.CurveSecp256K1) + signature, err := crypto.SignMessage(keys[identity.KeyPurposeSigning.Name].PrivateKey, msg, crypto.CurveSecp256K1) if err != nil { return nil, err } @@ -562,51 +539,66 @@ func (acc *Account) SignMsg(msg []byte) (*coredocumentpb.Signature, error) { return &coredocumentpb.Signature{ EntityId: did, - PublicKey: keys[identity.KeyPurposeSigning].PublicKey, + PublicKey: keys[identity.KeyPurposeSigning.Name].PublicKey, Signature: signature, Timestamp: utils.ToTimestamp(time.Now().UTC()), }, nil } +func (acc *Account) getEthereumAccountAddress() ([]byte, error) { + var ethAddr struct { + Address string `json:"address"` + } + err := json.Unmarshal([]byte(acc.GetEthereumAccount().Key), ðAddr) + if err != nil { + return nil, err + } + return hex.DecodeString(ethAddr.Address) +} + // GetKeys returns the keys of an account // TODO remove GetKeys and add signing methods to account -func (acc *Account) GetKeys() (idKeys map[int]config.IDKey, err error) { +func (acc *Account) GetKeys() (idKeys map[string]config.IDKey, err error) { if acc.keys == nil { - acc.keys = map[int]config.IDKey{} + acc.keys = map[string]config.IDKey{} } - if _, ok := acc.keys[identity.KeyPurposeP2P]; !ok { - pk, sk, err := ed25519.GetSigningKeyPair(acc.GetP2PKeyPair()) + // KeyPurposeAction + if _, ok := acc.keys[identity.KeyPurposeAction.Name]; !ok { + pk, err := acc.getEthereumAccountAddress() if err != nil { return idKeys, err } - - acc.keys[identity.KeyPurposeP2P] = config.IDKey{ - PublicKey: pk, - PrivateKey: sk} + address32Bytes, err := utils.ByteArrayTo32BytesLeftPadded(pk) + if err != nil { + return idKeys, err + } + acc.keys[identity.KeyPurposeAction.Name] = config.IDKey{ + PublicKey: address32Bytes[:], + } } - //secp256k1 keys - if _, ok := acc.keys[identity.KeyPurposeSigning]; !ok { - pk, sk, err := secp256k1.GetSigningKeyPair(acc.GetSigningKeyPair()) + // KeyPurposeP2PDiscovery + if _, ok := acc.keys[identity.KeyPurposeP2PDiscovery.Name]; !ok { + pk, sk, err := ed25519.GetSigningKeyPair(acc.GetP2PKeyPair()) if err != nil { return idKeys, err } - address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - acc.keys[identity.KeyPurposeSigning] = config.IDKey{ - PublicKey: address32Bytes[:], + acc.keys[identity.KeyPurposeP2PDiscovery.Name] = config.IDKey{ + PublicKey: pk, PrivateKey: sk} } - if _, ok := acc.keys[identity.KeyPurposeEthMsgAuth]; !ok { - pk, sk, err := secp256k1.GetSigningKeyPair(acc.GetEthAuthKeyPair()) + // KeyPurposeSigning + if _, ok := acc.keys[identity.KeyPurposeSigning.Name]; !ok { + pk, sk, err := secp256k1.GetSigningKeyPair(acc.GetSigningKeyPair()) if err != nil { return idKeys, err } address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - acc.keys[identity.KeyPurposeEthMsgAuth] = config.IDKey{ + acc.keys[identity.KeyPurposeSigning.Name] = config.IDKey{ PublicKey: address32Bytes[:], PrivateKey: sk} } @@ -663,10 +655,6 @@ func (acc *Account) CreateProtobuf() (*accountpb.AccountData, error) { Pub: acc.SigningKeyPair.Pub, Pvt: acc.SigningKeyPair.Priv, }, - EthauthKeyPair: &accountpb.KeyPair{ - Pub: acc.EthAuthKeyPair.Pub, - Pvt: acc.EthAuthKeyPair.Priv, - }, }, nil } @@ -683,9 +671,6 @@ func (acc *Account) loadFromProtobuf(data *accountpb.AccountData) error { if data.SigningKeyPair == nil { return errors.NewTypedError(ErrNilParameter, errors.New("nil SigningKeyPair field")) } - if data.EthauthKeyPair == nil { - return errors.NewTypedError(ErrNilParameter, errors.New("nil EthauthKeyPair field")) - } acc.EthereumAccount = &config.AccountConfig{ Address: data.EthAccount.Address, Key: data.EthAccount.Key, @@ -702,21 +687,21 @@ func (acc *Account) loadFromProtobuf(data *accountpb.AccountData) error { Pub: data.SigningKeyPair.Pub, Priv: data.SigningKeyPair.Pvt, } - acc.EthAuthKeyPair = KeyPair{ - Pub: data.EthauthKeyPair.Pub, - Priv: data.EthauthKeyPair.Pvt, - } + return nil } // NewAccount creates a new Account instance with configs func NewAccount(ethAccountName string, c config.Configuration) (config.Account, error) { + if ethAccountName == "" { + return nil, errors.New("ethAccountName not provided") + } id, err := c.GetIdentityID() if err != nil { return nil, err } acc, err := c.GetEthereumAccount(ethAccountName) - if err != nil && ethAccountName != "" { + if err != nil { return nil, err } return &Account{ @@ -727,14 +712,16 @@ func NewAccount(ethAccountName string, c config.Configuration) (config.Account, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), - EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil } // TempAccount creates a new Account without id validation, Must only be used for account creation. func TempAccount(ethAccountName string, c config.Configuration) (config.Account, error) { + if ethAccountName == "" { + return nil, errors.New("ethAccountName not provided") + } acc, err := c.GetEthereumAccount(ethAccountName) - if err != nil && ethAccountName != "" { + if err != nil { return nil, err } return &Account{ @@ -744,6 +731,5 @@ func TempAccount(ethAccountName string, c config.Configuration) (config.Account, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), - EthAuthKeyPair: NewKeyPair(c.GetEthAuthKeyPair()), }, nil } diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 6dc0c01f9..5b2c41af5 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -247,11 +247,6 @@ func (m *mockConfig) GetSigningKeyPair() (pub, priv string) { return args.Get(0).(string), args.Get(1).(string) } -func (m *mockConfig) GetEthAuthKeyPair() (pub, priv string) { - args := m.Called() - return args.Get(0).(string), args.Get(1).(string) -} - func TestNewNodeConfig(t *testing.T) { c := createMockConfig() NewNodeConfig(c) @@ -267,7 +262,6 @@ func TestNewAccountConfig(t *testing.T) { c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() - c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() _, err := NewAccount("name", c) assert.NoError(t, err) @@ -302,7 +296,6 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil) c.On("GetP2PKeyPair").Return("pub", "priv") c.On("GetSigningKeyPair").Return("pub", "priv") - c.On("GetEthAuthKeyPair").Return("pub", "priv") c.On("GetEthereumContextWaitTimeout").Return(time.Second) tc, err := NewAccount("name", c) assert.Nil(t, err) @@ -345,12 +338,6 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { assert.Error(t, err) accpb.SigningKeyPair = signKey.(*accountpb.KeyPair) - // Nil EthauthKeyPair - ethAuthKey := proto.Clone(accpb.EthauthKeyPair) - accpb.EthauthKeyPair = nil - err = tco.loadFromProtobuf(accpb) - assert.Error(t, err) - accpb.EthauthKeyPair = ethAuthKey.(*accountpb.KeyPair) } func TestAccountConfigProtobuf(t *testing.T) { @@ -361,7 +348,6 @@ func TestAccountConfigProtobuf(t *testing.T) { c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() - c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() tc, err := NewAccount("name", c) assert.Nil(t, err) @@ -400,7 +386,6 @@ func createMockConfig() *mockConfig { c.On("GetIdentityID").Return(utils.RandomSlice(identity.DIDLength), nil).Once() c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() - c.On("GetEthAuthKeyPair").Return("pub", "priv").Once() c.On("GetReceiveEventNotificationEndpoint").Return("dummyNotifier").Once() c.On("GetEthereumAccount", "dummyAcc").Return(&config.AccountConfig{}, nil).Once() c.On("GetEthereumDefaultAccountName").Return("dummyAcc").Twice() diff --git a/config/configstore/service.go b/config/configstore/service.go index bda26618b..b38020e26 100644 --- a/config/configstore/service.go +++ b/config/configstore/service.go @@ -17,8 +17,6 @@ import ( const ( signingPubKeyName = "signingKey.pub.pem" signingPrivKeyName = "signingKey.key.pem" - ethAuthPubKeyName = "ethauth.pub.pem" - ethAuthPrivKeyName = "ethauth.key.pem" ) // ProtocolSetter sets the protocol on host for the centID @@ -107,7 +105,7 @@ func (s service) GenerateAccount() (config.Account, error) { return acc, nil } -// generateAccountKeys generates signing and ethauth keys +// generateAccountKeys generates signing keys func generateAccountKeys(keystore string, acc *Account, DID *identity.DID) (*Account, error) { acc.IdentityID = DID[:] sPub, err := createKeyPath(keystore, DID, signingPubKeyName) @@ -122,26 +120,11 @@ func generateAccountKeys(keystore string, acc *Account, DID *identity.DID) (*Acc Pub: sPub, Priv: sPriv, } - ePub, err := createKeyPath(keystore, DID, ethAuthPubKeyName) - if err != nil { - return nil, err - } - ePriv, err := createKeyPath(keystore, DID, ethAuthPrivKeyName) - if err != nil { - return nil, err - } - acc.EthAuthKeyPair = KeyPair{ - Pub: ePub, - Priv: ePriv, - } err = crypto.GenerateSigningKeyPair(acc.SigningKeyPair.Pub, acc.SigningKeyPair.Priv, crypto.CurveSecp256K1) if err != nil { return nil, err } - err = crypto.GenerateSigningKeyPair(acc.EthAuthKeyPair.Pub, acc.EthAuthKeyPair.Priv, crypto.CurveSecp256K1) - if err != nil { - return nil, err - } + return acc, nil } diff --git a/config/configstore/service_integration_test.go b/config/configstore/service_integration_test.go index a300e74bb..303335462 100644 --- a/config/configstore/service_integration_test.go +++ b/config/configstore/service_integration_test.go @@ -53,8 +53,6 @@ func TestService_GenerateAccountHappy(t *testing.T) { assert.True(t, tc.GetEthereumDefaultAccountName() != "") pb, pv := tc.GetSigningKeyPair() err = checkKeyPair(t, pb, pv) - pb, pv = tc.GetEthAuthKeyPair() - err = checkKeyPair(t, pb, pv) ctxh := testingconfig.CreateAccountContext(t, cfg) err = identityService.Exists(ctxh, did) assert.NoError(t, err) diff --git a/config/configstore/service_test.go b/config/configstore/service_test.go index 4befa4d87..43277c399 100644 --- a/config/configstore/service_test.go +++ b/config/configstore/service_test.go @@ -159,9 +159,9 @@ func TestGenerateaccountKeys(t *testing.T) { assert.NoError(t, err) tc, err := generateAccountKeys("/tmp/accounts/", &Account{}, &DID) assert.Nil(t, err) - assert.NotNil(t, tc.EthAuthKeyPair) - _, err = os.Stat(tc.EthAuthKeyPair.Pub) + assert.NotNil(t, tc.SigningKeyPair) + _, err = os.Stat(tc.SigningKeyPair.Pub) assert.False(t, os.IsNotExist(err)) - _, err = os.Stat(tc.EthAuthKeyPair.Priv) + _, err = os.Stat(tc.SigningKeyPair.Priv) assert.False(t, os.IsNotExist(err)) } diff --git a/config/configuration.go b/config/configuration.go index 6060408a7..c50bca54a 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -108,7 +108,6 @@ type Configuration interface { GetIdentityID() ([]byte, error) GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) - GetEthAuthKeyPair() (pub, priv string) // debug specific methods IsPProfEnabled() bool @@ -120,7 +119,7 @@ type Configuration interface { // Account exposes account options type Account interface { storage.Model - GetKeys() (map[int]IDKey, error) + GetKeys() (map[string]IDKey, error) SignMsg(msg []byte) (*coredocumentpb.Signature, error) GetEthereumAccount() *AccountConfig GetEthereumDefaultAccountName() string @@ -128,7 +127,6 @@ type Account interface { GetIdentityID() ([]byte, error) GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) - GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration // CreateProtobuf creates protobuf @@ -153,12 +151,6 @@ type IDKey struct { PrivateKey []byte } -// IDKeys holds key of an identity -type IDKeys struct { - ID []byte - Keys map[int]IDKey -} - // configuration holds the configuration details for the node. type configuration struct { mu sync.RWMutex @@ -414,11 +406,6 @@ func (c *configuration) GetSigningKeyPair() (pub, priv string) { return c.GetString("keys.signing.publicKey"), c.GetString("keys.signing.privateKey") } -// GetEthAuthKeyPair returns ethereum key pair. -func (c *configuration) GetEthAuthKeyPair() (pub, priv string) { - return c.GetString("keys.ethauth.publicKey"), c.GetString("keys.ethauth.privateKey") -} - // IsPProfEnabled returns true if the pprof is enabled func (c *configuration) IsPProfEnabled() bool { return c.GetBool("debug.pprof") @@ -537,8 +524,6 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("ethereum.accounts.main.password", accountPassword) v.Set("keys.p2p.privateKey", targetDataDir+"/p2p.key.pem") v.Set("keys.p2p.publicKey", targetDataDir+"/p2p.pub.pem") - v.Set("keys.ethauth.privateKey", targetDataDir+"/ethauth.key.pem") - v.Set("keys.ethauth.publicKey", targetDataDir+"/ethauth.pub.pem") v.Set("keys.signing.privateKey", targetDataDir+"/signing.key.pem") v.Set("keys.signing.publicKey", targetDataDir+"/signing.pub.pem") diff --git a/contextutil/context.go b/contextutil/context.go index f7afca823..0c87f0e6e 100644 --- a/contextutil/context.go +++ b/contextutil/context.go @@ -34,15 +34,6 @@ func WithTX(ctx context.Context, txID transactions.TxID) context.Context { return context.WithValue(ctx, tx, txID) } -// Self returns Self CentID. -func Self(ctx context.Context) (*identity.IDConfig, error) { - tc, ok := ctx.Value(self).(config.Account) - if !ok { - return nil, ErrSelfNotFound - } - return identity.GetIdentityConfig(tc) -} - // TX returns current txID func TX(ctx context.Context) transactions.TxID { tid, ok := ctx.Value(tx).(transactions.TxID) @@ -52,6 +43,19 @@ func TX(ctx context.Context) transactions.TxID { return tid } +// AccountDID extracts the AccountConfig DID from the given context value +func AccountDID(ctx context.Context) (identity.DID, error) { + acc, err := Account(ctx) + if err != nil { + return identity.DID{}, err + } + didBytes, err := acc.GetIdentityID() + if err != nil { + return identity.DID{}, err + } + return identity.NewDIDFromBytes(didBytes), nil +} + // Account extracts the TenanConfig from the given context value func Account(ctx context.Context) (config.Account, error) { tc, ok := ctx.Value(self).(config.Account) diff --git a/crypto/secp256k1/secp256k1_test.go b/crypto/secp256k1/secp256k1_test.go index ba4326417..3f479b466 100644 --- a/crypto/secp256k1/secp256k1_test.go +++ b/crypto/secp256k1/secp256k1_test.go @@ -143,32 +143,3 @@ func TestGetAddress(t *testing.T) { address := GetAddress(publicKey) assert.Equal(t, address, correctAddress, "address is not correctly calculated from public key") } - -func TestGetEthAuthKeyFromConfig(t *testing.T) { - pub := cfg.Get("keys.ethauth.publicKey") - pri := cfg.Get("keys.ethauth.privateKey") - - // bad public key path - cfg.Set("keys.ethauth.publicKey", "bad path") - pubK, priK, err := GetSigningKeyPair(cfg.GetEthAuthKeyPair()) - assert.Error(t, err) - assert.Nil(t, priK) - assert.Nil(t, pubK) - assert.Contains(t, err.Error(), "failed to read public key") - cfg.Set("keys.ethauth.publicKey", pub) - - // bad private key path - cfg.Set("keys.ethauth.privateKey", "bad path") - pubK, priK, err = GetSigningKeyPair(cfg.GetEthAuthKeyPair()) - assert.Error(t, err) - assert.Nil(t, priK) - assert.Nil(t, pubK) - assert.Contains(t, err.Error(), "failed to read private key") - cfg.Set("keys.ethauth.privateKey", pri) - - // success - pubK, priK, err = GetSigningKeyPair(cfg.GetEthAuthKeyPair()) - assert.Nil(t, err) - assert.NotNil(t, pubK) - assert.NotNil(t, priK) -} diff --git a/documents/coredocument_test.go b/documents/coredocument_test.go index 068f364bb..26243c8cb 100644 --- a/documents/coredocument_test.go +++ b/documents/coredocument_test.go @@ -57,8 +57,6 @@ func TestMain(m *testing.M) { cfg.Set("keys.p2p.privateKey", "../build/resources/p2pKey.key.pem") cfg.Set("keys.signing.publicKey", "../build/resources/signingKey.pub.pem") cfg.Set("keys.signing.privateKey", "../build/resources/signingKey.key.pem") - cfg.Set("keys.ethauth.publicKey", "../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../build/resources/ethauth.key.pem") result := m.Run() bootstrap.RunTestTeardown(ibootstappers) os.Exit(result) diff --git a/documents/invoice/model_test.go b/documents/invoice/model_test.go index 8f10cb173..96a709c18 100644 --- a/documents/invoice/model_test.go +++ b/documents/invoice/model_test.go @@ -76,11 +76,12 @@ func TestMain(m *testing.M) { } func TestInvoice_PackCoreDocument(t *testing.T) { - id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) assert.NoError(t, err) inv := new(Invoice) - assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String())) + assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), did.String())) cd, err := inv.PackCoreDocument() assert.NoError(t, err) @@ -90,9 +91,10 @@ func TestInvoice_PackCoreDocument(t *testing.T) { func TestInvoice_JSON(t *testing.T) { inv := new(Invoice) - id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) assert.NoError(t, err) - assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String())) + assert.NoError(t, inv.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), did.String())) cd, err := inv.PackCoreDocument() assert.NoError(t, err) @@ -154,7 +156,10 @@ func TestInvoiceModel_getClientData(t *testing.T) { } func TestInvoiceModel_InitInvoiceInput(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) + assert.NoError(t, err) + // fail recipient data := &clientinvoicepb.InvoiceData{ Sender: "some number", @@ -163,7 +168,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { ExtraData: "some data", } inv := new(Invoice) - err := inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, did.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, inv.Recipient) @@ -174,7 +179,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { data.ExtraData = "0x010203020301" recipientDID := testingidentity.GenerateRandomDID() data.Recipient = recipientDID.String() - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, did.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -183,7 +188,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { senderDID := testingidentity.GenerateRandomDID() data.Sender = senderDID.String() - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, did.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -192,7 +197,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { payeeDID := testingidentity.GenerateRandomDID() data.Payee = payeeDID.String() - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data}, did.String()) assert.Nil(t, err) assert.NotNil(t, inv.ExtraData) assert.NotNil(t, inv.Recipient) @@ -201,7 +206,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { data.ExtraData = "0x010203020301" collabs := []string{"0x010102040506", "some id"} - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, did.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") collab1, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") @@ -209,7 +214,7 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { collab2, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF3") assert.NoError(t, err) collabs = []string{collab1.String(), collab2.String()} - err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) + err = inv.InitInvoiceInput(&clientinvoicepb.InvoiceCreatePayload{Data: data, Collaborators: collabs}, did.String()) assert.Nil(t, err, "must be nil") assert.Equal(t, inv.Sender[:], senderDID[:]) assert.Equal(t, inv.Payee[:], payeeDID[:]) @@ -218,9 +223,11 @@ func TestInvoiceModel_InitInvoiceInput(t *testing.T) { } func TestInvoiceModel_calculateDataRoot(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) + assert.NoError(t, err) m := new(Invoice) - err := m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), id.ID.String()) + err = m.InitInvoiceInput(testingdocuments.CreateInvoicePayload(), did.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, m.InvoiceSalts, "salts must be nil") diff --git a/documents/invoice/service.go b/documents/invoice/service.go index 711a87a2f..845f29c17 100644 --- a/documents/invoice/service.go +++ b/documents/invoice/service.go @@ -71,13 +71,13 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv return nil, documents.ErrDocumentNil } - id, err := contextutil.Self(ctx) + did, err := contextutil.AccountDID(ctx) if err != nil { return nil, documents.ErrDocumentConfigAccountID } invoiceModel := new(Invoice) - err = invoiceModel.InitInvoiceInput(payload, id.ID.String()) + err = invoiceModel.InitInvoiceInput(payload, did.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } @@ -87,7 +87,7 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientinv // validateAndPersist validates the document, calculates the data root, and persists to DB func (s service) validateAndPersist(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -104,7 +104,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], inv.CurrentVersion(), inv) + err = s.repo.Create(selfDID[:], inv.CurrentVersion(), inv) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -114,7 +114,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode // Create takes and invoice model and does required validation checks, tries to persist to DB func (s service) Create(ctx context.Context, inv documents.Model) (documents.Model, transactions.TxID, chan bool, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -125,7 +125,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, inv.CurrentVersion()) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, selfDID, txID, inv.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -134,7 +134,7 @@ func (s service) Create(ctx context.Context, inv documents.Model) (documents.Mod // Update finds the old document, validates the new version and persists the updated document func (s service) Update(ctx context.Context, new documents.Model) (documents.Model, transactions.TxID, chan bool, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -150,7 +150,7 @@ func (s service) Update(ctx context.Context, new documents.Model) (documents.Mod } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, new.CurrentVersion()) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, selfDID, txID, new.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } diff --git a/documents/processor.go b/documents/processor.go index 7cbee8256..a0fd73467 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -169,12 +169,12 @@ func (dp defaultProcessor) SendDocument(ctx context.Context, model Model) error return errors.New("post anchor validations failed: %v", err) } - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return err } - cs, err := model.GetSignerCollaborators(self.ID) + cs, err := model.GetSignerCollaborators(selfDID) if err != nil { return errors.New("get external collaborators failed: %v", err) } diff --git a/documents/processor_test.go b/documents/processor_test.go index c88b303f8..a84ab0518 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -147,8 +147,11 @@ func TestDefaultProcessor_PrepareForSignatureRequests(t *testing.T) { assert.NotNil(t, model.sigs) assert.Len(t, model.sigs, 1) sig := model.sigs[0] - self, _ := contextutil.Self(ctxh) - assert.True(t, crypto.VerifyMessage(self.Keys[identity.KeyPurposeSigning].PublicKey, sr, sig.Signature, crypto.CurveSecp256K1)) + self, err := contextutil.Account(ctxh) + assert.NoError(t, err) + keys, err := self.GetKeys() + assert.NoError(t, err) + assert.True(t, crypto.VerifyMessage(keys[identity.KeyPurposeSigning.Name].PublicKey, sr, sig.Signature, crypto.CurveSecp256K1)) } type p2pClient struct { diff --git a/documents/purchaseorder/model_test.go b/documents/purchaseorder/model_test.go index dd465935b..5feba9f2a 100644 --- a/documents/purchaseorder/model_test.go +++ b/documents/purchaseorder/model_test.go @@ -76,11 +76,12 @@ func TestMain(m *testing.M) { } func TestPurchaseOrder_PackCoreDocument(t *testing.T) { - id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) assert.NoError(t, err) po := new(PurchaseOrder) - assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String())) + assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), did.String())) cd, err := po.PackCoreDocument() assert.NoError(t, err) @@ -90,9 +91,10 @@ func TestPurchaseOrder_PackCoreDocument(t *testing.T) { func TestPurchaseOrder_JSON(t *testing.T) { po := new(PurchaseOrder) - id, err := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) assert.NoError(t, err) - assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String())) + assert.NoError(t, po.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), did.String())) cd, err := po.PackCoreDocument() assert.NoError(t, err) @@ -152,14 +154,17 @@ func TestPOModel_getClientData(t *testing.T) { } func TestPOOrderModel_InitPOInput(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) + assert.NoError(t, err) + // fail recipient data := &clientpurchaseorderpb.PurchaseOrderData{ Recipient: "some recipient", ExtraData: "some data", } poModel := new(PurchaseOrder) - err := poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, did.String()) assert.Error(t, err, "must return err") assert.Contains(t, err.Error(), "failed to decode extra data") assert.Nil(t, poModel.Recipient) @@ -168,14 +173,14 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { data.ExtraData = "0x010203020301" data.Recipient = "0xed03fa80291ff5ddc284de6b51e716b130b05e20" - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, id.ID.String()) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data}, did.String()) assert.Nil(t, err) assert.NotNil(t, poModel.ExtraData) assert.NotNil(t, poModel.Recipient) data.ExtraData = "0x010203020301" collabs := []string{"0x010102040506", "some id"} - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, did.String()) assert.Contains(t, err.Error(), "failed to decode collaborator") collab1, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF7") @@ -183,19 +188,21 @@ func TestPOOrderModel_InitPOInput(t *testing.T) { collab2, err := identity.NewDIDFromString("0xBAEb33a61f05e6F269f1c4b4CFF91A901B54DaF3") assert.NoError(t, err) collabs = []string{collab1.String(), collab2.String()} - err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, id.ID.String()) + err = poModel.InitPurchaseOrderInput(&clientpurchaseorderpb.PurchaseOrderCreatePayload{Data: data, Collaborators: collabs}, did.String()) assert.Nil(t, err, "must be nil") - did, err := identity.NewDIDFromString("0xed03fa80291ff5ddc284de6b51e716b130b05e20") + did, err = identity.NewDIDFromString("0xed03fa80291ff5ddc284de6b51e716b130b05e20") assert.NoError(t, err) assert.Equal(t, poModel.Recipient[:], did[:]) assert.Equal(t, poModel.ExtraData[:], []byte{1, 2, 3, 2, 3, 1}) } func TestPOModel_calculateDataRoot(t *testing.T) { - id, _ := contextutil.Self(testingconfig.CreateAccountContext(t, cfg)) + ctx := testingconfig.CreateAccountContext(t, cfg) + did, err := contextutil.AccountDID(ctx) + assert.NoError(t, err) poModel := new(PurchaseOrder) - err := poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), id.ID.String()) + err = poModel.InitPurchaseOrderInput(testingdocuments.CreatePOPayload(), did.String()) assert.Nil(t, err, "Init must pass") assert.Nil(t, poModel.PurchaseOrderSalts, "salts must be nil") diff --git a/documents/purchaseorder/service.go b/documents/purchaseorder/service.go index 9af14c391..37981a00e 100644 --- a/documents/purchaseorder/service.go +++ b/documents/purchaseorder/service.go @@ -67,7 +67,7 @@ func (s service) DeriveFromCoreDocument(cd coredocumentpb.CoreDocument) (documen // validateAndPersist validates the document, and persists to DB func (s service) validateAndPersist(ctx context.Context, old, new documents.Model, validator documents.Validator) (documents.Model, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -84,7 +84,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode } // we use CurrentVersion as the id since that will be unique across multiple versions of the same document - err = s.repo.Create(self.ID[:], po.CurrentVersion(), po) + err = s.repo.Create(selfDID[:], po.CurrentVersion(), po) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentPersistence, err) } @@ -94,7 +94,7 @@ func (s service) validateAndPersist(ctx context.Context, old, new documents.Mode // Create validates, persists, and anchors a purchase order func (s service) Create(ctx context.Context, po documents.Model) (documents.Model, transactions.TxID, chan bool, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -105,7 +105,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, po.CurrentVersion()) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, selfDID, txID, po.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, nil } @@ -114,7 +114,7 @@ func (s service) Create(ctx context.Context, po documents.Model) (documents.Mode // Update validates, persists, and anchors a new version of purchase order func (s service) Update(ctx context.Context, new documents.Model) (documents.Model, transactions.TxID, chan bool, error) { - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, transactions.NilTxID(), nil, errors.NewTypedError(documents.ErrDocumentConfigAccountID, err) } @@ -130,7 +130,7 @@ func (s service) Update(ctx context.Context, new documents.Model) (documents.Mod } txID := contextutil.TX(ctx) - txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, self.ID, txID, new.CurrentVersion()) + txID, done, err := documents.CreateAnchorTransaction(s.txManager, s.queueSrv, selfDID, txID, new.CurrentVersion()) if err != nil { return nil, transactions.NilTxID(), nil, err } @@ -143,13 +143,13 @@ func (s service) DeriveFromCreatePayload(ctx context.Context, payload *clientpop return nil, documents.ErrDocumentNil } - idConf, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, documents.ErrDocumentConfigAccountID } po := new(PurchaseOrder) - err = po.InitPurchaseOrderInput(payload, idConf.ID.String()) + err = po.InitPurchaseOrderInput(payload, selfDID.String()) if err != nil { return nil, errors.NewTypedError(documents.ErrDocumentInvalid, err) } diff --git a/documents/read_acls.go b/documents/read_acls.go index 692c7a757..9c49dde32 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -370,7 +370,7 @@ func (cd *CoreDocument) ATGranteeCanRead(ctx context.Context, idService identity return ErrReqDocNotMatch } // validate that the public key of the granter is the public key that has been used to sign the access token - err = idService.ValidateKey(ctx, granterID, at.Key, identity.KeyPurposeSigning) + err = idService.ValidateKey(ctx, granterID, at.Key, &(identity.KeyPurposeSigning.Value)) if err != nil { return err } @@ -441,7 +441,7 @@ func assembleAccessToken(ctx context.Context, payload documentpb.AccessTokenPara RoleIdentifier: roleID[:], DocumentIdentifier: docID, Signature: sig.Signature, - Key: keys[identity.KeyPurposeSigning].PublicKey, + Key: keys[identity.KeyPurposeSigning.Name].PublicKey, } return at, nil diff --git a/identity/did.go b/identity/did.go index 6c53d1334..83ec21c4b 100644 --- a/identity/did.go +++ b/identity/did.go @@ -6,15 +6,11 @@ import ( "math/big" "time" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/utils" - - "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/ethereum/go-ethereum/common" ) @@ -29,21 +25,83 @@ const ( // BootstrappedDIDService stores the id of the service BootstrappedDIDService string = "BootstrappedDIDService" - // CentIDLength is the length in bytes of the DID - CentIDLength = 6 + // KeyTypeECDSA has the value one in the ERC725 identity contract + KeyTypeECDSA = 1 - // KeyPurposeP2P represents a key used for p2p txns - KeyPurposeP2P = 1 + keyPurposeMgmt = "MANAGEMENT" + keyPurposeAction = "ACTION" + keyPurposeP2PDiscovery = "P2P_DISCOVERY" + keyPurposeSigning = "SIGNING" +) - // KeyPurposeSigning represents a key used for signing - KeyPurposeSigning = 2 +var ( + // KeyPurposeManagement purpose stores the management key to interact with the ERC725 identity contract + KeyPurposeManagement Purpose + // KeyPurposeAction purpose stores the action key to interact with the ERC725 identity contract + KeyPurposeAction Purpose + // KeyPurposeP2PDiscovery purpose stores the action key to interact with the ERC725 identity contract + KeyPurposeP2PDiscovery Purpose + // KeyPurposeSigning purpose stores the action key to interact with the ERC725 identity contract + KeyPurposeSigning Purpose +) - // KeyPurposeEthMsgAuth represents a key used for ethereum txns - KeyPurposeEthMsgAuth = 3 +func init() { + KeyPurposeManagement = getKeyPurposeManagement() + KeyPurposeAction = getKeyPurposeAction() + KeyPurposeP2PDiscovery = getKeyPurposeP2PDiscovery() + KeyPurposeSigning = getKeyPurposeSigning() +} - // KeyTypeECDSA has the value one in the ERC725 identity contract - KeyTypeECDSA = 1 -) +// getKeyPurposeManagement is calculated out of Hex(leftPadding(1,32)) +func getKeyPurposeManagement() Purpose { + enc := "0000000000000000000000000000000000000000000000000000000000000001" + v, _ := new(big.Int).SetString(enc, 16) + return Purpose{Name: keyPurposeMgmt, HexValue: enc, Value: *v} +} + +// getKeyPurposeAction is calculated out of Hex(leftPadding(2,32)) +func getKeyPurposeAction() Purpose { + enc := "0000000000000000000000000000000000000000000000000000000000000002" + v, _ := new(big.Int).SetString(enc, 16) + return Purpose{Name: keyPurposeAction, HexValue: enc, Value: *v} +} + +// getKeyPurposeP2PDiscovery is calculated out of Hex(sha256("CENTRIFUGE@P2P_DISCOVERY")) +func getKeyPurposeP2PDiscovery() Purpose { + hashed := "88dbd1f0b244e515ab5aee93b5dee6a2d8e326576a583822635a27e52e5b591e" + v, _ := new(big.Int).SetString(hashed, 16) + return Purpose{Name: keyPurposeP2PDiscovery, HexValue: hashed, Value: *v} +} + +// getKeyPurposeSigning is calculated out of Hex(sha256("CENTRIFUGE@SIGNING")) +func getKeyPurposeSigning() Purpose { + hashed := "774a43710604e3ce8db630136980a6ba5a65b5e6686ee51009ed5f3fded6ea7e" + v, _ := new(big.Int).SetString(hashed, 16) + return Purpose{Name: keyPurposeSigning, HexValue: hashed, Value: *v} +} + +// Purpose contains the different representation of purpose along the code +type Purpose struct { + Name string + HexValue string + Value big.Int +} + +// GetPurposeByName retrieves the Purpose by name +func GetPurposeByName(name string) Purpose { + switch name { + case keyPurposeMgmt: + return getKeyPurposeManagement() + case keyPurposeAction: + return getKeyPurposeAction() + case keyPurposeP2PDiscovery: + return getKeyPurposeP2PDiscovery() + case keyPurposeSigning: + return getKeyPurposeSigning() + default: + return Purpose{} + } +} // DID stores the identity address of the user type DID common.Address @@ -162,7 +220,7 @@ type ServiceDID interface { Exists(ctx context.Context, did DID) error // ValidateKey checks if a given key is valid for the given centrifugeID. - ValidateKey(ctx context.Context, did DID, key []byte, purpose int64) error + ValidateKey(ctx context.Context, did DID, key []byte, purpose *big.Int) error // ValidateSignature checks if signature is valid for given identity ValidateSignature(signature *coredocumentpb.Signature, message []byte) error @@ -250,51 +308,5 @@ type Config interface { GetIdentityID() ([]byte, error) GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) - GetEthAuthKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration } - -// IDConfig holds information about the identity -// Deprecated -type IDConfig struct { - ID DID - Keys map[int]IDKey -} - -// GetIdentityConfig returns the identity and keys associated with the node. -func GetIdentityConfig(config Config) (*IDConfig, error) { - centIDBytes, err := config.GetIdentityID() - if err != nil { - return nil, err - } - centID := NewDIDFromBytes(centIDBytes) - - //ed25519 keys - keys := map[int]IDKey{} - - pk, sk, err := ed25519.GetSigningKeyPair(config.GetP2PKeyPair()) - if err != nil { - return nil, err - } - keys[KeyPurposeP2P] = IDKey{PublicKey: pk, PrivateKey: sk} - - pk, sk, err = secp256k1.GetSigningKeyPair(config.GetSigningKeyPair()) - if err != nil { - return nil, err - } - pk32 := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - keys[KeyPurposeSigning] = IDKey{PublicKey: pk32[:], PrivateKey: sk} - - //secp256k1 keys - pk, sk, err = secp256k1.GetSigningKeyPair(config.GetEthAuthKeyPair()) - if err != nil { - return nil, err - } - pubKey, err := hexutil.Decode(secp256k1.GetAddress(pk)) - if err != nil { - return nil, err - } - keys[KeyPurposeEthMsgAuth] = IDKey{PublicKey: pubKey, PrivateKey: sk} - - return &IDConfig{ID: centID, Keys: keys}, nil -} diff --git a/identity/did_test.go b/identity/did_test.go new file mode 100644 index 000000000..82a4d599f --- /dev/null +++ b/identity/did_test.go @@ -0,0 +1,75 @@ +// +build unit + +package identity + +import ( + "crypto/sha256" + "encoding/hex" + "testing" + + "github.com/centrifuge/go-centrifuge/utils" + + "github.com/stretchr/testify/assert" +) + +func TestManagementPurpose(t *testing.T) { + b32, err := utils.ByteArrayTo32BytesLeftPadded([]byte{1}) + assert.NoError(t, err) + mgmtHex := hex.EncodeToString(b32[:]) + assert.Equal(t, KeyPurposeManagement.HexValue, mgmtHex) +} + +func TestActionPurpose(t *testing.T) { + b32, err := utils.ByteArrayTo32BytesLeftPadded([]byte{2}) + assert.NoError(t, err) + actionHex := hex.EncodeToString(b32[:]) + assert.Equal(t, KeyPurposeAction.HexValue, actionHex) +} + +func TestP2PDiscoveryPurposeHash(t *testing.T) { + h := sha256.New() + _, err := h.Write([]byte("CENTRIFUGE@P2P_DISCOVERY")) + assert.NoError(t, err) + hb := h.Sum(nil) + assert.Len(t, hb, 32) + p2pHex := hex.EncodeToString(hb) + assert.Equal(t, KeyPurposeP2PDiscovery.HexValue, p2pHex) +} + +func TestSigningPurposeHash(t *testing.T) { + h := sha256.New() + _, err := h.Write([]byte("CENTRIFUGE@SIGNING")) + assert.NoError(t, err) + hb := h.Sum(nil) + assert.Len(t, hb, 32) + p2pHex := hex.EncodeToString(hb) + assert.Equal(t, KeyPurposeSigning.HexValue, p2pHex) +} + +func TestKeyPurposeManagement(t *testing.T) { + purpose := KeyPurposeManagement + assert.Equal(t, "MANAGEMENT", purpose.Name) + assert.Equal(t, "0000000000000000000000000000000000000000000000000000000000000001", purpose.HexValue) + assert.Equal(t, "1", purpose.Value.String()) +} + +func TestKeyPurposeAction(t *testing.T) { + purpose := KeyPurposeAction + assert.Equal(t, "ACTION", purpose.Name) + assert.Equal(t, "0000000000000000000000000000000000000000000000000000000000000002", purpose.HexValue) + assert.Equal(t, "2", purpose.Value.String()) +} + +func TestKeyPurposeP2PDiscovery(t *testing.T) { + purpose := KeyPurposeP2PDiscovery + assert.Equal(t, "P2P_DISCOVERY", purpose.Name) + assert.Equal(t, "88dbd1f0b244e515ab5aee93b5dee6a2d8e326576a583822635a27e52e5b591e", purpose.HexValue) + assert.Equal(t, "61902935868658303950246481358903666251099779839440421743915568792957869578526", purpose.Value.String()) +} + +func TestKeyPurposeSigning(t *testing.T) { + purpose := KeyPurposeSigning + assert.Equal(t, "SIGNING", purpose.Name) + assert.Equal(t, "774a43710604e3ce8db630136980a6ba5a65b5e6686ee51009ed5f3fded6ea7e", purpose.HexValue) + assert.Equal(t, "53956441128315394338673222674654929973131976200905067808864911710716608047742", purpose.Value.String()) +} diff --git a/identity/ideth/execute_integration_test.go b/identity/ideth/execute_integration_test.go index 3b8c19785..5f37dc19f 100644 --- a/identity/ideth/execute_integration_test.go +++ b/identity/ideth/execute_integration_test.go @@ -49,14 +49,13 @@ func TestExecute_successful(t *testing.T) { // add node Ethereum address as a action key // only an action key can use the execute method - actionPurpose := utils.ByteSliceToBigInt([]byte{2}) ethAccount, err := cfg.GetEthereumAccount(cfg.GetEthereumDefaultAccountName()) assert.Nil(t, err) actionAddress := ethAccount.Address //add action key actionKey := utils.AddressTo32Bytes(common.HexToAddress(actionAddress)) - key := id.NewKey(actionKey, actionPurpose, utils.ByteSliceToBigInt([]byte{123})) + key := id.NewKey(actionKey, &(id.KeyPurposeAction.Value), utils.ByteSliceToBigInt([]byte{123})) err = idSrv.AddKey(aCtx, key) assert.Nil(t, err) diff --git a/identity/ideth/factory.go b/identity/ideth/factory.go index 8d5f710e3..c13fc2f11 100644 --- a/identity/ideth/factory.go +++ b/identity/ideth/factory.go @@ -3,8 +3,6 @@ package ideth import ( "context" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/config/configstore" "github.com/centrifuge/go-centrifuge/contextutil" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" @@ -135,26 +133,3 @@ func (s *factory) CreateIdentity(ctx context.Context) (did *id.DID, err error) { return &createdDID, nil } - -// CreateIdentity creates an identity contract -func CreateIdentity(ctx map[string]interface{}, cfg config.Configuration) (*id.DID, error) { - tc, err := configstore.TempAccount(cfg.GetEthereumDefaultAccountName(), cfg) - if err != nil { - return nil, err - } - - tctx, err := contextutil.New(context.Background(), tc) - if err != nil { - return nil, err - } - - identityFactory := ctx[id.BootstrappedDIDFactory].(id.Factory) - - did, err := identityFactory.CreateIdentity(tctx) - if err != nil { - return nil, err - } - - return did, nil - -} diff --git a/identity/ideth/service.go b/identity/ideth/service.go index 668d839c3..34bc69bbf 100644 --- a/identity/ideth/service.go +++ b/identity/ideth/service.go @@ -11,7 +11,6 @@ import ( "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/crypto/secp256k1" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/go-centrifuge/contextutil" @@ -300,7 +299,7 @@ func (i service) GetKeysByPurpose(did id.DID, purpose *big.Int) ([][32]byte, err // CurrentP2PKey returns the latest P2P key func (i service) CurrentP2PKey(did id.DID) (ret string, err error) { - keys, err := i.GetKeysByPurpose(did, big.NewInt(id.KeyPurposeP2P)) + keys, err := i.GetKeysByPurpose(did, &(id.KeyPurposeP2PDiscovery.Value)) if err != nil { return ret, err } @@ -339,7 +338,7 @@ func (i service) Exists(ctx context.Context, did id.DID) error { } // ValidateKey checks if a given key is valid for the given centrifugeID. -func (i service) ValidateKey(ctx context.Context, did id.DID, key []byte, purpose int64) error { +func (i service) ValidateKey(ctx context.Context, did id.DID, key []byte, purpose *big.Int) error { contract, opts, _, err := i.prepareCall(did) if err != nil { return err @@ -356,7 +355,7 @@ func (i service) ValidateKey(ctx context.Context, did id.DID, key []byte, purpos } for _, p := range keys.Purposes { - if p.Cmp(big.NewInt(purpose)) == 0 { + if p.Cmp(purpose) == 0 { return nil } } @@ -381,40 +380,16 @@ func (i service) GetClientsP2PURLs(dids []*id.DID) ([]string, error) { return urls, nil } -func getKeyPairsFromAccount(acc config.Account) (map[int]id.KeyDID, error) { - keys := map[int]id.KeyDID{} - var pk []byte - - // ed25519 keys - // KeyPurposeP2P - pk, _, err := ed25519.GetSigningKeyPair(acc.GetP2PKeyPair()) - if err != nil { - return nil, err - } - pk32, err := utils.SliceToByte32(pk) - if err != nil { - return nil, err - } - keys[id.KeyPurposeP2P] = id.NewKey(pk32, big.NewInt(id.KeyPurposeP2P), big.NewInt(id.KeyTypeECDSA)) - - // secp256k1 keys - // KeyPurposeSigning - pk, _, err = secp256k1.GetSigningKeyPair(acc.GetSigningKeyPair()) - if err != nil { - return nil, err - } - address32Bytes := utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - keys[id.KeyPurposeSigning] = id.NewKey(address32Bytes, big.NewInt(id.KeyPurposeSigning), big.NewInt(id.KeyTypeECDSA)) - - // KeyPurposeEthMsgAuth - pk, _, err = secp256k1.GetSigningKeyPair(acc.GetEthAuthKeyPair()) - if err != nil { - return nil, err +func convertAccountKeysToKeyDID(accKeys map[string]config.IDKey) (map[string]id.KeyDID, error) { + keys := map[string]id.KeyDID{} + for k, v := range accKeys { + pk32, err := utils.SliceToByte32(v.PublicKey) + if err != nil { + return nil, err + } + v := id.GetPurposeByName(k).Value + keys[k] = id.NewKey(pk32, &v, big.NewInt(id.KeyTypeECDSA)) } - - address32Bytes = utils.AddressTo32Bytes(common.HexToAddress(secp256k1.GetAddress(pk))) - keys[id.KeyPurposeEthMsgAuth] = id.NewKey(address32Bytes, big.NewInt(id.KeyPurposeEthMsgAuth), big.NewInt(id.KeyTypeECDSA)) - return keys, nil } @@ -425,24 +400,31 @@ func (i service) AddKeysForAccount(acc config.Account) error { return err } - keys, err := getKeyPairsFromAccount(acc) + accKeys, err := acc.GetKeys() if err != nil { return err } - err = i.AddKey(tctx, keys[id.KeyPurposeP2P]) + + keys, err := convertAccountKeysToKeyDID(accKeys) + if err != nil { + return err + } + + err = i.AddKey(tctx, keys[id.KeyPurposeAction.Name]) if err != nil { return err } - err = i.AddKey(tctx, keys[id.KeyPurposeSigning]) + err = i.AddKey(tctx, keys[id.KeyPurposeP2PDiscovery.Name]) if err != nil { return err } - err = i.AddKey(tctx, keys[id.KeyPurposeEthMsgAuth]) + err = i.AddKey(tctx, keys[id.KeyPurposeSigning.Name]) if err != nil { return err } + return nil } @@ -450,7 +432,7 @@ func (i service) AddKeysForAccount(acc config.Account) error { func (i service) ValidateSignature(signature *coredocumentpb.Signature, message []byte) error { centID := id.NewDIDFromBytes(signature.EntityId) - err := i.ValidateKey(context.Background(), centID, signature.PublicKey, id.KeyPurposeSigning) + err := i.ValidateKey(context.Background(), centID, signature.PublicKey, &(id.KeyPurposeSigning.Value)) if err != nil { return err } diff --git a/identity/ideth/service_integration_test.go b/identity/ideth/service_integration_test.go index 883b928a1..9a71bf3c5 100644 --- a/identity/ideth/service_integration_test.go +++ b/identity/ideth/service_integration_test.go @@ -41,8 +41,6 @@ func initIdentity() id.ServiceDID { func getTestDIDContext(t *testing.T, did id.DID) context.Context { cfg.Set("identityId", did.ToAddress().String()) - cfg.Set("keys.ethauth.publicKey", "../../build/resources/ethauth.pub.pem") - cfg.Set("keys.ethauth.privateKey", "../../build/resources/ethauth.key.pem") aCtx := testingconfig.CreateAccountContext(t, cfg) return aCtx @@ -217,13 +215,13 @@ func TestValidateKey(t *testing.T) { key32 := testKey.GetKey() - var purpose int64 - purpose = 123 // test purpose + var purpose *big.Int + purpose = big.NewInt(123) // test purpose err := idSrv.ValidateKey(aCtx, *did, utils.Byte32ToSlice(key32), purpose) assert.Nil(t, err, "key with purpose should exist") - purpose = 1 //false purpose + purpose = big.NewInt(1) //false purpose err = idSrv.ValidateKey(aCtx, *did, utils.Byte32ToSlice(key32), purpose) assert.Error(t, err, "key with purpose should not exist") resetDefaultCentID() @@ -237,7 +235,7 @@ func addP2PKeyTestGetClientP2PURL(t *testing.T) (*id.DID, string) { p2pKey := utils.RandomByte32() - testKey := id.NewKey(p2pKey, utils.ByteSliceToBigInt([]byte{identity.KeyPurposeP2P}), utils.ByteSliceToBigInt([]byte{123})) + testKey := id.NewKey(p2pKey, &(identity.KeyPurposeP2PDiscovery.Value), utils.ByteSliceToBigInt([]byte{123})) addKey(aCtx, t, *did, idSrv, testKey) url, err := idSrv.GetClientP2PURL(*did) diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 398f54c39..32403828e 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -178,7 +178,6 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetReceiveEventNotificationEndpoint").Return("") configMock.On("GetP2PKeyPair").Return("", "") configMock.On("GetSigningKeyPair").Return("", "") - configMock.On("GetEthAuthKeyPair").Return("", "") queueSrv := new(testingutils.MockQueue) txMan := &testingtx.MockTxManager{} txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index a840e6d06..e3d9d80fc 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -59,7 +59,7 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) assert.NoError(t, err) did := identity.NewDID(*didAddr) - tc, err := configstore.TempAccount("", cfg) + tc, err := configstore.TempAccount("main", cfg) assert.NoError(t, err) tcr := tc.(*configstore.Account) tcr.IdentityID = did[:] diff --git a/notification/notification_test.go b/notification/notification_test.go index 6d2db4549..25acd7acf 100644 --- a/notification/notification_test.go +++ b/notification/notification_test.go @@ -52,8 +52,8 @@ func (m mockConfig) GetReceiveEventNotificationEndpoint() string { func TestWebhookSender_Send(t *testing.T) { docID := utils.RandomSlice(32) - accountID := utils.RandomSlice(identity.CentIDLength) - senderID := utils.RandomSlice(identity.CentIDLength) + accountID := utils.RandomSlice(identity.DIDLength) + senderID := utils.RandomSlice(identity.DIDLength) ts, err := ptypes.TimestampProto(time.Now().UTC()) assert.Nil(t, err, "Should not error out") var wg sync.WaitGroup diff --git a/p2p/client.go b/p2p/client.go index 263aa8a6c..9b634ee5a 100644 --- a/p2p/client.go +++ b/p2p/client.go @@ -221,12 +221,12 @@ func (s *peer) GetSignaturesForDocument(ctx context.Context, model documents.Mod return nil, nil, err } - self, err := contextutil.Self(ctx) + selfDID, err := contextutil.AccountDID(ctx) if err != nil { return nil, nil, errors.New("failed to get self ID") } - cs, err := model.GetSignerCollaborators(self.ID) + cs, err := model.GetSignerCollaborators(selfDID) if err != nil { return nil, nil, errors.New("failed to get external collaborators") } diff --git a/p2p/client_integration_test.go b/p2p/client_integration_test.go index dc69f0167..2be3aaec3 100644 --- a/p2p/client_integration_test.go +++ b/p2p/client_integration_test.go @@ -46,7 +46,8 @@ func TestMain(m *testing.M) { idService = ctx[identity.BootstrappedDIDService].(identity.ServiceDID) idFactory = ctx[identity.BootstrappedDIDFactory].(identity.Factory) client = ctx[bootstrap.BootstrappedPeer].(documents.Client) - tc, _ := configstore.TempAccount("", cfg) + tc, err := configstore.TempAccount("main", cfg) + assert.NoError(&testing.T{}, err) didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) assert.NoError(&testing.T{}, err) acc := tc.(*configstore.Account) @@ -61,7 +62,7 @@ func TestMain(m *testing.M) { func TestClient_GetSignaturesForDocument(t *testing.T) { tc, _, err := createLocalCollaborator(t, false) - acc, err := configstore.NewAccount("", cfg) + acc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) acci := acc.(*configstore.Account) acci.IdentityID = defaultDID[:] @@ -75,7 +76,7 @@ func TestClient_GetSignaturesForDocument(t *testing.T) { func TestClient_GetSignaturesForDocumentValidationCheck(t *testing.T) { tc, _, err := createLocalCollaborator(t, true) - acc, err := configstore.NewAccount("", cfg) + acc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) acci := acc.(*configstore.Account) acci.IdentityID = defaultDID[:] @@ -102,7 +103,7 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) assert.NoError(t, err) did := identity.NewDID(*didAddr) - tc, err := configstore.TempAccount("", cfg) + tc, err := configstore.TempAccount("main", cfg) assert.NoError(t, err) tcr := tc.(*configstore.Account) tcr.IdentityID = did[:] @@ -121,9 +122,13 @@ func createLocalCollaborator(t *testing.T, corruptID bool) (*configstore.Account } func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) documents.Model { - idConfig, err := identity.GetIdentityConfig(cfg) - idConfig.ID = defaultDID - assert.Nil(t, err) + ctx := testingconfig.CreateAccountContext(t, cfg) + accCfg, err := contextutil.Account(ctx) + assert.NoError(t, err) + acc := accCfg.(*configstore.Account) + acc.IdentityID = defaultDID[:] + accKeys, err := acc.GetKeys() + assert.NoError(t, err) payalod := testingdocuments.CreatePOPayload() var cs []string for _, c := range collaborators { @@ -131,17 +136,17 @@ func prepareDocumentForP2PHandler(t *testing.T, collaborators [][]byte) document } payalod.Collaborators = cs po := new(purchaseorder.PurchaseOrder) - err = po.InitPurchaseOrderInput(payalod, idConfig.ID.String()) + err = po.InitPurchaseOrderInput(payalod, defaultDID.String()) assert.NoError(t, err) _, err = po.CalculateDataRoot() assert.NoError(t, err) sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - s, err := crypto.SignMessage(idConfig.Keys[identity.KeyPurposeSigning].PrivateKey, sr, crypto.CurveSecp256K1) + s, err := crypto.SignMessage(accKeys[identity.KeyPurposeSigning.Name].PrivateKey, sr, crypto.CurveSecp256K1) assert.NoError(t, err) sig := &coredocumentpb.Signature{ - EntityId: idConfig.ID[:], - PublicKey: idConfig.Keys[identity.KeyPurposeSigning].PublicKey, + EntityId: defaultDID[:], + PublicKey: accKeys[identity.KeyPurposeSigning.Name].PublicKey, Signature: s, Timestamp: utils.ToTimestamp(time.Now().UTC()), } diff --git a/p2p/client_test.go b/p2p/client_test.go index 97779210b..d4b453baa 100644 --- a/p2p/client_test.go +++ b/p2p/client_test.go @@ -101,7 +101,7 @@ func TestGetSignatureForDocument_fail_centrifugeId(t *testing.T) { _, err = p2pcommon.PrepareP2PEnvelope(ctx, c.GetNetworkID(), p2pcommon.MessageTypeRequestSignature, &p2ppb.SignatureRequest{Document: &cd}) assert.NoError(t, err, "signature request could not be created") - randomBytes := utils.RandomSlice(identity.CentIDLength) + randomBytes := utils.RandomSlice(identity.DIDLength) signature := &coredocumentpb.Signature{EntityId: randomBytes, PublicKey: utils.RandomSlice(32)} m.On("SendMessage", ctx, mock.Anything, mock.Anything, p2pcommon.ProtocolForDID(¢rifugeId)).Return(testClient.createSignatureResp(version.GetVersion().String(), signature), nil) diff --git a/p2p/common/protocol_test.go b/p2p/common/protocol_test.go index 934ae17ea..d56fdeebd 100644 --- a/p2p/common/protocol_test.go +++ b/p2p/common/protocol_test.go @@ -101,10 +101,6 @@ func TestPrepareP2PEnvelope(t *testing.T) { Priv: ssk, Pub: spk, }, - EthAuthKeyPair: configstore.KeyPair{ - Priv: ssk, - Pub: spk, - }, } ctx, _ := contextutil.New(context.Background(), acc) assert.NotNil(t, ctx) diff --git a/p2p/messenger/messenger_test.go b/p2p/messenger/messenger_test.go index 4c4ab4b1f..fe0a1ea81 100644 --- a/p2p/messenger/messenger_test.go +++ b/p2p/messenger/messenger_test.go @@ -335,7 +335,5 @@ func updateKeys(c config.Configuration) config.Configuration { n := c.(*configstore.NodeConfig) n.MainIdentity.SigningKeyPair.Pub = "../../build/resources/signingKey.pub.pem" n.MainIdentity.SigningKeyPair.Priv = "../../build/resources/signingKey.key.pem" - n.MainIdentity.EthAuthKeyPair.Pub = "../../build/resources/ethauth.pub.pem" - n.MainIdentity.EthAuthKeyPair.Priv = "../../build/resources/ethauth.key.pem" return c } diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index 48679de28..fb319c2f5 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -78,7 +78,7 @@ func TestHandler_GetDocument_nonexistentIdentifier(t *testing.T) { func TestHandler_HandleInterceptorReqSignature(t *testing.T) { centID := createIdentity(t) - tc, err := configstore.NewAccount("", cfg) + tc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) acc := tc.(*configstore.Account) acc.IdentityID = centID[:] @@ -163,20 +163,21 @@ func TestHandler_RequestDocumentSignature(t *testing.T) { func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { _, cd := prepareDocumentForP2PHandler(t, nil) + ctx := testingconfig.CreateAccountContext(t, cfg) // Anchor document - idConfig, err := identity.GetIdentityConfig(cfg) + accDID, err := contextutil.AccountDID(ctx) + assert.NoError(t, err) anchorIDTyped, _ := anchors.ToAnchorID(cd.CurrentVersion) docRootTyped, _ := anchors.ToDocumentRoot(cd.DocumentRoot) - ctx := testingconfig.CreateAccountContext(t, cfg) anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) watchCommittedAnchor := <-anchorConfirmations assert.True(t, watchCommittedAnchor, "No error should be thrown by context") - anchorResp, err := handler.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: &cd}, idConfig.ID[:]) + anchorResp, err := handler.SendAnchoredDocument(ctx, &p2ppb.AnchorDocumentRequest{Document: &cd}, accDID[:]) assert.Error(t, err) assert.Contains(t, err.Error(), storage.ErrRepositoryModelUpdateKeyNotFound.Error()) assert.Nil(t, anchorResp) @@ -192,7 +193,7 @@ func TestHandler_SendAnchoredDocument_EmptyDocument(t *testing.T) { } func TestHandler_SendAnchoredDocument(t *testing.T) { - tc, err := configstore.NewAccount("", cfg) + tc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) centrifugeId := createIdentity(t) acc := tc.(*configstore.Account) @@ -231,7 +232,7 @@ func createIdentity(t *testing.T) identity.DID { // Create Identity didAddr, err := idFactory.CalculateIdentityAddress(context.Background()) assert.NoError(t, err) - tc, err := configstore.NewAccount("", cfg) + tc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) acc := tc.(*configstore.Account) acc.IdentityID = didAddr.Bytes() @@ -242,24 +243,18 @@ func createIdentity(t *testing.T) identity.DID { assert.Nil(t, err, "should not error out when creating identity") assert.Equal(t, did.String(), didAddr.String(), "Resulting Identity should have the same ID as the input") - idConfig, err := identity.GetIdentityConfig(cfg) - assert.NoError(t, err) // Add Keys - pk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeP2P].PublicKey) + accKeys, err := tc.GetKeys() assert.NoError(t, err) - keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeP2P), big.NewInt(identity.KeyTypeECDSA)) - err = idService.AddKey(ctx, keyDID) - assert.Nil(t, err, "should not error out when adding key to identity") - - sPk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeSigning].PublicKey) + pk, err := utils.SliceToByte32(accKeys[identity.KeyPurposeP2PDiscovery.Name].PublicKey) assert.NoError(t, err) - keyDID = identity.NewKey(sPk, big.NewInt(identity.KeyPurposeSigning), big.NewInt(identity.KeyTypeECDSA)) + keyDID := identity.NewKey(pk, &(identity.KeyPurposeP2PDiscovery.Value), big.NewInt(identity.KeyTypeECDSA)) err = idService.AddKey(ctx, keyDID) assert.Nil(t, err, "should not error out when adding key to identity") - secPk, err := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) + sPk, err := utils.SliceToByte32(accKeys[identity.KeyPurposeSigning.Name].PublicKey) assert.NoError(t, err) - keyDID = identity.NewKey(secPk, big.NewInt(identity.KeyPurposeEthMsgAuth), big.NewInt(identity.KeyTypeECDSA)) + keyDID = identity.NewKey(sPk, &(identity.KeyPurposeSigning.Value), big.NewInt(identity.KeyTypeECDSA)) err = idService.AddKey(ctx, keyDID) assert.Nil(t, err, "should not error out when adding key to identity") @@ -267,24 +262,28 @@ func createIdentity(t *testing.T) identity.DID { } func prepareDocumentForP2PHandler(t *testing.T, po *purchaseorder.PurchaseOrder) (*purchaseorder.PurchaseOrder, coredocumentpb.CoreDocument) { - idConfig, err := identity.GetIdentityConfig(cfg) - assert.Nil(t, err) - idConfig.ID = defaultDID + ctx := testingconfig.CreateAccountContext(t, cfg) + accCfg, err := contextutil.Account(ctx) + assert.NoError(t, err) + acc := accCfg.(*configstore.Account) + acc.IdentityID = defaultDID[:] + accKeys, err := acc.GetKeys() + assert.NoError(t, err) if po == nil { payload := testingdocuments.CreatePOPayload() po = new(purchaseorder.PurchaseOrder) - err = po.InitPurchaseOrderInput(payload, idConfig.ID.String()) + err = po.InitPurchaseOrderInput(payload, defaultDID.String()) assert.NoError(t, err) } _, err = po.CalculateDataRoot() assert.NoError(t, err) sr, err := po.CalculateSigningRoot() assert.NoError(t, err) - s, err := crypto.SignMessage(idConfig.Keys[identity.KeyPurposeSigning].PrivateKey, sr, crypto.CurveSecp256K1) + s, err := crypto.SignMessage(accKeys[identity.KeyPurposeSigning.Name].PrivateKey, sr, crypto.CurveSecp256K1) assert.NoError(t, err) sig := &coredocumentpb.Signature{ - EntityId: idConfig.ID[:], - PublicKey: idConfig.Keys[identity.KeyPurposeSigning].PublicKey, + EntityId: defaultDID[:], + PublicKey: accKeys[identity.KeyPurposeSigning.Name].PublicKey, Signature: s, Timestamp: utils.ToTimestamp(time.Now().UTC()), } diff --git a/p2p/receiver/validator.go b/p2p/receiver/validator.go index 3c7bc04b9..869aa7dcb 100644 --- a/p2p/receiver/validator.go +++ b/p2p/receiver/validator.go @@ -89,7 +89,7 @@ func peerValidator(idService identity.ServiceDID) Validator { if err != nil { return err } - return idService.ValidateKey(context.Background(), *centID, idKey, int64(identity.KeyPurposeP2P)) + return idService.ValidateKey(context.Background(), *centID, idKey, &(identity.KeyPurposeP2PDiscovery.Value)) }) } diff --git a/p2p/server_test.go b/p2p/server_test.go index e06b99223..212048ee4 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -154,14 +154,12 @@ func updateKeys(c config.Configuration) config.Configuration { n.MainIdentity.P2PKeyPair.Priv = "../build/resources/p2pKey.key.pem" n.MainIdentity.SigningKeyPair.Pub = "../build/resources/signingKey.pub.pem" n.MainIdentity.SigningKeyPair.Priv = "../build/resources/signingKey.key.pem" - n.MainIdentity.EthAuthKeyPair.Pub = "../build/resources/ethauth.pub.pem" - n.MainIdentity.EthAuthKeyPair.Priv = "../build/resources/ethauth.key.pem" return c } func mockmockConfigStore(n config.Configuration) *configstore.MockService { mockConfigStore := &configstore.MockService{} mockConfigStore.On("GetConfig").Return(n, nil) - mockConfigStore.On("GetAllAccounts").Return([]config.Account{&configstore.Account{IdentityID: utils.RandomSlice(identity.CentIDLength)}}, nil) + mockConfigStore.On("GetAllAccounts").Return([]config.Account{&configstore.Account{IdentityID: utils.RandomSlice(identity.DIDLength)}}, nil) return mockConfigStore } diff --git a/protobufs/account/service.proto b/protobufs/account/service.proto index 28e4090af..75dc2b601 100644 --- a/protobufs/account/service.proto +++ b/protobufs/account/service.proto @@ -87,6 +87,5 @@ message AccountData { string receive_event_notification_endpoint = 3; string identity_id = 4; KeyPair signing_key_pair = 5; - KeyPair ethauth_key_pair = 6; KeyPair p2p_key_pair = 7; } diff --git a/protobufs/gen/go/account/service.pb.go b/protobufs/gen/go/account/service.pb.go index 31a0417bf..e380f5196 100644 --- a/protobufs/gen/go/account/service.pb.go +++ b/protobufs/gen/go/account/service.pb.go @@ -37,7 +37,7 @@ func (m *GetAccountRequest) Reset() { *m = GetAccountRequest{} } func (m *GetAccountRequest) String() string { return proto.CompactTextString(m) } func (*GetAccountRequest) ProtoMessage() {} func (*GetAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{0} + return fileDescriptor_service_bc5abe13fa112146, []int{0} } func (m *GetAccountRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAccountRequest.Unmarshal(m, b) @@ -75,7 +75,7 @@ func (m *GetAllAccountResponse) Reset() { *m = GetAllAccountResponse{} } func (m *GetAllAccountResponse) String() string { return proto.CompactTextString(m) } func (*GetAllAccountResponse) ProtoMessage() {} func (*GetAllAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{1} + return fileDescriptor_service_bc5abe13fa112146, []int{1} } func (m *GetAllAccountResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetAllAccountResponse.Unmarshal(m, b) @@ -114,7 +114,7 @@ func (m *UpdateAccountRequest) Reset() { *m = UpdateAccountRequest{} } func (m *UpdateAccountRequest) String() string { return proto.CompactTextString(m) } func (*UpdateAccountRequest) ProtoMessage() {} func (*UpdateAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{2} + return fileDescriptor_service_bc5abe13fa112146, []int{2} } func (m *UpdateAccountRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateAccountRequest.Unmarshal(m, b) @@ -161,7 +161,7 @@ func (m *EthereumAccount) Reset() { *m = EthereumAccount{} } func (m *EthereumAccount) String() string { return proto.CompactTextString(m) } func (*EthereumAccount) ProtoMessage() {} func (*EthereumAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{3} + return fileDescriptor_service_bc5abe13fa112146, []int{3} } func (m *EthereumAccount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EthereumAccount.Unmarshal(m, b) @@ -214,7 +214,7 @@ func (m *KeyPair) Reset() { *m = KeyPair{} } func (m *KeyPair) String() string { return proto.CompactTextString(m) } func (*KeyPair) ProtoMessage() {} func (*KeyPair) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{4} + return fileDescriptor_service_bc5abe13fa112146, []int{4} } func (m *KeyPair) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyPair.Unmarshal(m, b) @@ -254,7 +254,6 @@ type AccountData struct { ReceiveEventNotificationEndpoint string `protobuf:"bytes,3,opt,name=receive_event_notification_endpoint,json=receiveEventNotificationEndpoint,proto3" json:"receive_event_notification_endpoint,omitempty"` IdentityId string `protobuf:"bytes,4,opt,name=identity_id,json=identityId,proto3" json:"identity_id,omitempty"` SigningKeyPair *KeyPair `protobuf:"bytes,5,opt,name=signing_key_pair,json=signingKeyPair,proto3" json:"signing_key_pair,omitempty"` - EthauthKeyPair *KeyPair `protobuf:"bytes,6,opt,name=ethauth_key_pair,json=ethauthKeyPair,proto3" json:"ethauth_key_pair,omitempty"` P2PKeyPair *KeyPair `protobuf:"bytes,7,opt,name=p2p_key_pair,json=p2pKeyPair,proto3" json:"p2p_key_pair,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -265,7 +264,7 @@ func (m *AccountData) Reset() { *m = AccountData{} } func (m *AccountData) String() string { return proto.CompactTextString(m) } func (*AccountData) ProtoMessage() {} func (*AccountData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_55a49b82a8becf96, []int{5} + return fileDescriptor_service_bc5abe13fa112146, []int{5} } func (m *AccountData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AccountData.Unmarshal(m, b) @@ -320,13 +319,6 @@ func (m *AccountData) GetSigningKeyPair() *KeyPair { return nil } -func (m *AccountData) GetEthauthKeyPair() *KeyPair { - if m != nil { - return m.EthauthKeyPair - } - return nil -} - func (m *AccountData) GetP2PKeyPair() *KeyPair { if m != nil { return m.P2PKeyPair @@ -547,54 +539,53 @@ var _AccountService_serviceDesc = grpc.ServiceDesc{ Metadata: "account/service.proto", } -func init() { proto.RegisterFile("account/service.proto", fileDescriptor_service_55a49b82a8becf96) } - -var fileDescriptor_service_55a49b82a8becf96 = []byte{ - // 724 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xd1, 0x6a, 0xdb, 0x48, - 0x14, 0x45, 0x71, 0x36, 0x5e, 0x5f, 0x25, 0x8e, 0x77, 0x70, 0x82, 0x50, 0x76, 0xb3, 0x42, 0x0b, - 0x8b, 0xc9, 0x6e, 0x6c, 0x70, 0x1e, 0x76, 0xeb, 0x87, 0x52, 0xa7, 0x31, 0xa1, 0x94, 0x86, 0xe0, - 0xd2, 0x87, 0x16, 0x8a, 0x3b, 0xb6, 0x6e, 0xa4, 0x21, 0xf6, 0x68, 0xaa, 0x19, 0x3b, 0x98, 0xd2, - 0x3e, 0xf4, 0x13, 0xdc, 0xe7, 0xf6, 0xa7, 0xfa, 0x0b, 0xfd, 0x8d, 0x42, 0x91, 0x34, 0x92, 0xed, - 0xda, 0xa6, 0xf4, 0x49, 0x33, 0x73, 0xef, 0xb9, 0xe7, 0x9e, 0x3b, 0x73, 0x04, 0x07, 0x74, 0x30, - 0x08, 0xc7, 0x5c, 0x35, 0x24, 0x46, 0x13, 0x36, 0xc0, 0xba, 0x88, 0x42, 0x15, 0x92, 0xa2, 0x3e, - 0xb6, 0x7f, 0xf7, 0xc3, 0xd0, 0x1f, 0x62, 0x83, 0x0a, 0xd6, 0xa0, 0x9c, 0x87, 0x8a, 0x2a, 0x16, - 0x72, 0x99, 0xa6, 0xd9, 0x47, 0x3a, 0x9a, 0xec, 0xfa, 0xe3, 0x9b, 0x06, 0x8e, 0x84, 0x9a, 0xea, - 0xe0, 0xbf, 0xc9, 0x67, 0x70, 0xea, 0x23, 0x3f, 0x95, 0x77, 0xd4, 0xf7, 0x31, 0x6a, 0x84, 0x22, - 0x81, 0xaf, 0x96, 0x72, 0xcf, 0xe0, 0xb7, 0x4b, 0x54, 0xed, 0x94, 0xb6, 0x8b, 0xaf, 0xc7, 0x28, - 0x15, 0x39, 0x06, 0x60, 0x1e, 0x72, 0xc5, 0x6e, 0x18, 0x46, 0x96, 0xe1, 0x18, 0xb5, 0x52, 0x77, - 0xe1, 0xc4, 0x6d, 0xc3, 0x41, 0x0c, 0x1a, 0x0e, 0x73, 0x9c, 0x14, 0x21, 0x97, 0x48, 0x6a, 0xb0, - 0xed, 0x51, 0x45, 0x2d, 0xc3, 0x29, 0xd4, 0xcc, 0x66, 0xb5, 0xae, 0xe5, 0xd4, 0x75, 0xde, 0x05, - 0x55, 0xb4, 0x9b, 0x64, 0xb8, 0xaf, 0xa0, 0xfa, 0x4c, 0x78, 0x54, 0xe1, 0xcf, 0x51, 0xe7, 0x0c, - 0x5b, 0x8e, 0xf1, 0x03, 0x86, 0xe7, 0xb0, 0xdf, 0x51, 0x01, 0x46, 0x38, 0x1e, 0xe9, 0x20, 0xb1, - 0xa0, 0x48, 0x3d, 0x2f, 0x42, 0x29, 0x75, 0xe5, 0x6c, 0x4b, 0x2a, 0x50, 0xb8, 0xc5, 0x69, 0x52, - 0xb5, 0xd4, 0x8d, 0x97, 0xc4, 0x86, 0x5f, 0x05, 0x95, 0xf2, 0x2e, 0x8c, 0x3c, 0xab, 0x90, 0x1c, - 0xe7, 0x7b, 0xf7, 0x14, 0x8a, 0x8f, 0x71, 0x7a, 0x4d, 0x59, 0x14, 0x03, 0xc5, 0xb8, 0xaf, 0xcb, - 0xc5, 0xcb, 0xe4, 0x64, 0xa2, 0xb2, 0x52, 0x62, 0xa2, 0xdc, 0x8f, 0x05, 0x30, 0x17, 0xfa, 0x23, - 0xf7, 0xc0, 0x44, 0x15, 0xf4, 0x74, 0xeb, 0x09, 0xd6, 0x6c, 0x5a, 0xb9, 0x94, 0xef, 0xba, 0xee, - 0x02, 0xaa, 0x20, 0x53, 0xf0, 0x1f, 0x58, 0x31, 0xd4, 0xc3, 0x1b, 0x3a, 0x1e, 0xaa, 0xac, 0x44, - 0x8f, 0xd3, 0x11, 0x6a, 0xc6, 0x03, 0x54, 0xc1, 0x45, 0x1a, 0xd6, 0xa0, 0x2b, 0x3a, 0x42, 0xf2, - 0x04, 0xfe, 0x8a, 0x70, 0x80, 0x6c, 0x82, 0x3d, 0x9c, 0x60, 0x0c, 0x09, 0xe3, 0x89, 0x0e, 0x92, - 0xc7, 0xd0, 0x43, 0xee, 0x89, 0x90, 0x71, 0xa5, 0x95, 0x3a, 0x3a, 0xb5, 0x13, 0x67, 0x5e, 0x2d, - 0x24, 0x76, 0x74, 0x1e, 0xf9, 0x13, 0xcc, 0xf4, 0x52, 0xd4, 0xb4, 0xc7, 0x3c, 0x6b, 0x7b, 0xf1, - 0x9e, 0xd4, 0xf4, 0x91, 0x47, 0x5a, 0x50, 0x91, 0xcc, 0xe7, 0x8c, 0xfb, 0xbd, 0x5b, 0x9c, 0xf6, - 0x04, 0x65, 0x91, 0xf5, 0x4b, 0x22, 0xb4, 0x92, 0x0b, 0xd5, 0x33, 0xec, 0x96, 0x75, 0x66, 0x36, - 0xd3, 0x16, 0x54, 0x50, 0x05, 0x74, 0xac, 0x82, 0x39, 0x76, 0x67, 0x13, 0x56, 0x67, 0x66, 0xd8, - 0x26, 0xec, 0x8a, 0xa6, 0x98, 0xe3, 0x8a, 0x1b, 0x70, 0x20, 0x9a, 0x42, 0xaf, 0x9b, 0x5f, 0xb7, - 0xa1, 0xac, 0x67, 0xf5, 0x34, 0xb5, 0x23, 0xe1, 0x00, 0x73, 0x5b, 0x10, 0x3b, 0x87, 0xaf, 0x78, - 0xc5, 0x5e, 0xfb, 0x04, 0xdd, 0xfa, 0xac, 0xbd, 0x67, 0x9b, 0x97, 0xa8, 0x1c, 0x7d, 0xfa, 0xfe, - 0xf3, 0x97, 0x0f, 0x5b, 0x16, 0x39, 0x6c, 0xe8, 0x6c, 0xd9, 0x78, 0x33, 0x7f, 0xd5, 0x6f, 0x89, - 0x80, 0xf2, 0x92, 0xa3, 0x24, 0x39, 0xac, 0xa7, 0x26, 0xaf, 0x67, 0x26, 0xaf, 0x77, 0x62, 0x93, - 0xdb, 0xc7, 0x4b, 0xbd, 0xac, 0x58, 0xd0, 0xfd, 0x7b, 0xd6, 0x26, 0x76, 0x25, 0x61, 0x1e, 0x0e, - 0x33, 0x76, 0x99, 0xd0, 0x9b, 0xa4, 0x94, 0xd3, 0x93, 0x00, 0xf6, 0x1e, 0x46, 0x38, 0x37, 0x20, - 0x59, 0x2b, 0x64, 0x83, 0xbc, 0x7f, 0x66, 0xed, 0xaa, 0x4d, 0x52, 0xbc, 0x74, 0x28, 0x5f, 0x52, - 0x59, 0x76, 0xe7, 0x34, 0x2d, 0xe3, 0x84, 0x7c, 0x32, 0x60, 0xff, 0x12, 0x39, 0x46, 0x0b, 0x64, - 0x9b, 0xd4, 0xad, 0xa7, 0x7b, 0x39, 0x6b, 0x3f, 0xb0, 0xef, 0x67, 0x35, 0x16, 0x09, 0x1d, 0x45, - 0x6f, 0x19, 0xf7, 0x1d, 0x6d, 0x08, 0xe9, 0xf4, 0xa9, 0x44, 0xcf, 0x09, 0xb9, 0xa3, 0x02, 0x74, - 0x46, 0x94, 0x71, 0x87, 0x2e, 0xb4, 0x56, 0x75, 0xc9, 0xfc, 0x02, 0x7c, 0x5d, 0x8f, 0xbc, 0x83, - 0xbd, 0xa5, 0x7f, 0x11, 0xf9, 0x23, 0xef, 0x62, 0xdd, 0x3f, 0x6a, 0x43, 0x93, 0xff, 0x27, 0x33, - 0x49, 0x01, 0x2b, 0x33, 0x39, 0xb2, 0x37, 0xdc, 0x7c, 0xcb, 0x38, 0x39, 0xaf, 0x81, 0x39, 0x08, - 0x47, 0x59, 0xd1, 0xf3, 0x5d, 0xfd, 0x08, 0xaf, 0xe3, 0xd1, 0x5c, 0x1b, 0x2f, 0x4a, 0x3a, 0x20, - 0xfa, 0xfd, 0x9d, 0x64, 0x5c, 0x67, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x75, 0xab, 0xa4, - 0x3f, 0x06, 0x00, 0x00, +func init() { proto.RegisterFile("account/service.proto", fileDescriptor_service_bc5abe13fa112146) } + +var fileDescriptor_service_bc5abe13fa112146 = []byte{ + // 706 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x51, 0x6b, 0x13, 0x4f, + 0x10, 0xe7, 0xda, 0xfe, 0xff, 0x31, 0x73, 0x6d, 0x1a, 0x97, 0xb4, 0x1c, 0x57, 0xad, 0xc7, 0x09, + 0x12, 0xaa, 0x4d, 0x20, 0x7d, 0x50, 0xfb, 0x20, 0xa6, 0x36, 0x14, 0x11, 0x4b, 0x89, 0xf8, 0xa0, + 0x20, 0x71, 0x93, 0x9b, 0x5e, 0x96, 0x26, 0x7b, 0xeb, 0xed, 0x26, 0x25, 0x88, 0x3e, 0xf8, 0x11, + 0xe2, 0xbb, 0x5f, 0xca, 0x4f, 0x20, 0xf8, 0x35, 0x04, 0xb9, 0xbb, 0xbd, 0xcb, 0xc5, 0x24, 0x88, + 0x4f, 0xb7, 0x3b, 0x33, 0xbf, 0xf9, 0xcd, 0x6f, 0x76, 0xe6, 0x60, 0x87, 0xf6, 0x7a, 0xc1, 0x88, + 0xab, 0xba, 0xc4, 0x70, 0xcc, 0x7a, 0x58, 0x13, 0x61, 0xa0, 0x02, 0x52, 0xd0, 0x66, 0xfb, 0x96, + 0x1f, 0x04, 0xfe, 0x00, 0xeb, 0x54, 0xb0, 0x3a, 0xe5, 0x3c, 0x50, 0x54, 0xb1, 0x80, 0xcb, 0x24, + 0xcc, 0xde, 0xd3, 0xde, 0xf8, 0xd6, 0x1d, 0x5d, 0xd6, 0x71, 0x28, 0xd4, 0x44, 0x3b, 0x1f, 0xc4, + 0x9f, 0xde, 0xa1, 0x8f, 0xfc, 0x50, 0x5e, 0x53, 0xdf, 0xc7, 0xb0, 0x1e, 0x88, 0x18, 0xbe, 0x98, + 0xca, 0x3d, 0x82, 0x9b, 0x67, 0xa8, 0x9a, 0x09, 0x6d, 0x1b, 0x3f, 0x8c, 0x50, 0x2a, 0xb2, 0x0f, + 0xc0, 0x3c, 0xe4, 0x8a, 0x5d, 0x32, 0x0c, 0x2d, 0xc3, 0x31, 0xaa, 0xc5, 0x76, 0xce, 0xe2, 0x36, + 0x61, 0x27, 0x02, 0x0d, 0x06, 0x19, 0x4e, 0x8a, 0x80, 0x4b, 0x24, 0x55, 0xd8, 0xf0, 0xa8, 0xa2, + 0x96, 0xe1, 0xac, 0x57, 0xcd, 0x46, 0xa5, 0xa6, 0xe5, 0xd4, 0x74, 0xdc, 0x29, 0x55, 0xb4, 0x1d, + 0x47, 0xb8, 0xef, 0xa1, 0xf2, 0x5a, 0x78, 0x54, 0xe1, 0xbf, 0x51, 0x67, 0x0c, 0x6b, 0x8e, 0xf1, + 0x17, 0x86, 0x37, 0xb0, 0xdd, 0x52, 0x7d, 0x0c, 0x71, 0x34, 0xd4, 0x4e, 0x62, 0x41, 0x81, 0x7a, + 0x5e, 0x88, 0x52, 0xea, 0xcc, 0xe9, 0x95, 0x94, 0x61, 0xfd, 0x0a, 0x27, 0x71, 0xd6, 0x62, 0x3b, + 0x3a, 0x12, 0x1b, 0x6e, 0x08, 0x2a, 0xe5, 0x75, 0x10, 0x7a, 0xd6, 0x7a, 0x6c, 0xce, 0xee, 0xee, + 0x21, 0x14, 0x5e, 0xe0, 0xe4, 0x82, 0xb2, 0x30, 0x02, 0x8a, 0x51, 0x57, 0xa7, 0x8b, 0x8e, 0xb1, + 0x65, 0xac, 0xd2, 0x54, 0x62, 0xac, 0xdc, 0x1f, 0x6b, 0x60, 0xe6, 0xea, 0x23, 0x8f, 0xc1, 0x44, + 0xd5, 0xef, 0xe8, 0xd2, 0x63, 0xac, 0xd9, 0xb0, 0x32, 0x29, 0x7f, 0x54, 0xdd, 0x06, 0x54, 0xfd, + 0x54, 0xc1, 0x43, 0xb0, 0x22, 0xa8, 0x87, 0x97, 0x74, 0x34, 0x50, 0x69, 0x8a, 0x0e, 0xa7, 0x43, + 0xd4, 0x8c, 0x3b, 0xa8, 0xfa, 0xa7, 0x89, 0x5b, 0x83, 0xce, 0xe9, 0x10, 0xc9, 0x4b, 0xb8, 0x1b, + 0x62, 0x0f, 0xd9, 0x18, 0x3b, 0x38, 0xc6, 0x08, 0x12, 0x44, 0x1d, 0xed, 0xc5, 0xc3, 0xd0, 0x41, + 0xee, 0x89, 0x80, 0x71, 0xa5, 0x95, 0x3a, 0x3a, 0xb4, 0x15, 0x45, 0x9e, 0xe7, 0x02, 0x5b, 0x3a, + 0x8e, 0xdc, 0x01, 0x33, 0x79, 0x14, 0x35, 0xe9, 0x30, 0xcf, 0xda, 0xc8, 0xbf, 0x93, 0x9a, 0x3c, + 0xf7, 0xc8, 0x31, 0x94, 0x25, 0xf3, 0x39, 0xe3, 0x7e, 0xe7, 0x0a, 0x27, 0x1d, 0x41, 0x59, 0x68, + 0xfd, 0x17, 0x0b, 0x2d, 0x67, 0x42, 0x75, 0x0f, 0xdb, 0x25, 0x1d, 0x99, 0xf6, 0xb4, 0x01, 0x9b, + 0xa2, 0x21, 0x66, 0xb8, 0xc2, 0x0a, 0x1c, 0x88, 0x86, 0xd0, 0xe7, 0xc6, 0xaf, 0x0d, 0x28, 0x69, + 0xbd, 0xaf, 0x92, 0x95, 0x22, 0x1c, 0x60, 0x36, 0xda, 0xc4, 0xce, 0xe0, 0x0b, 0xf3, 0x6e, 0x2f, + 0x1d, 0x23, 0xb7, 0x36, 0x6d, 0x6e, 0xd9, 0xe6, 0x19, 0x2a, 0x47, 0x5b, 0xbf, 0x7c, 0xff, 0xf9, + 0x75, 0xcd, 0x22, 0xbb, 0x75, 0x1d, 0x2d, 0xeb, 0x1f, 0x67, 0x93, 0xf9, 0x89, 0x08, 0x28, 0xcd, + 0x6d, 0x85, 0x24, 0xbb, 0xb5, 0x64, 0x51, 0x6b, 0xe9, 0xa2, 0xd6, 0x5a, 0xd1, 0xa2, 0xda, 0xfb, + 0x73, 0xb5, 0x2c, 0xac, 0x91, 0x7b, 0x6f, 0xda, 0x24, 0x76, 0x39, 0x66, 0x1e, 0x0c, 0x52, 0x76, + 0x19, 0xd3, 0x9b, 0xa4, 0x98, 0xd1, 0x93, 0x3e, 0x6c, 0x3d, 0x0b, 0x71, 0xb6, 0x44, 0x64, 0xa9, + 0x90, 0x15, 0xf2, 0xee, 0x4f, 0x9b, 0x15, 0x9b, 0x24, 0x78, 0xe9, 0x50, 0x3e, 0xa7, 0xb2, 0xe4, + 0xce, 0x68, 0x8e, 0x8d, 0x03, 0xf2, 0xcd, 0x80, 0xed, 0x33, 0xe4, 0x18, 0xe6, 0xc8, 0x56, 0xa9, + 0x5b, 0x4e, 0xf7, 0x6e, 0xda, 0x7c, 0x6a, 0x3f, 0x49, 0x73, 0xe4, 0x09, 0x1d, 0x45, 0xaf, 0x18, + 0xf7, 0x1d, 0x3d, 0xd4, 0xd2, 0xe9, 0x52, 0x89, 0x9e, 0x13, 0x70, 0x47, 0xf5, 0xd1, 0x19, 0x52, + 0xc6, 0x1d, 0x9a, 0x2b, 0xad, 0xe2, 0x92, 0xd9, 0x03, 0xf8, 0x3a, 0x1f, 0xf9, 0x0c, 0x5b, 0x73, + 0xff, 0x13, 0x72, 0x3b, 0xab, 0x62, 0xd9, 0x7f, 0x66, 0x45, 0x91, 0x8f, 0xe2, 0x9e, 0x24, 0x80, + 0x85, 0x9e, 0xec, 0xd9, 0x2b, 0x5e, 0xfe, 0xd8, 0x38, 0x38, 0xa9, 0x82, 0xd9, 0x0b, 0x86, 0x69, + 0xd2, 0x93, 0x4d, 0x3d, 0x84, 0x17, 0x51, 0x6b, 0x2e, 0x8c, 0xb7, 0x45, 0xed, 0x10, 0xdd, 0xee, + 0xff, 0x71, 0xbb, 0x8e, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x78, 0xa6, 0xeb, 0x6c, 0x03, 0x06, + 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index 0e7696baf..d79acae9a 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"ethauth_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"smart_contract_bytecode":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"smart_contract_bytecode":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/account/service.swagger.json b/protobufs/gen/swagger/account/service.swagger.json index 2810765e6..c154174e0 100644 --- a/protobufs/gen/swagger/account/service.swagger.json +++ b/protobufs/gen/swagger/account/service.swagger.json @@ -150,9 +150,6 @@ "signing_key_pair": { "$ref": "#/definitions/accountKeyPair" }, - "ethauth_key_pair": { - "$ref": "#/definitions/accountKeyPair" - }, "p2p_key_pair": { "$ref": "#/definitions/accountKeyPair" } diff --git a/protobufs/gen/swagger/config/service.swagger.json b/protobufs/gen/swagger/config/service.swagger.json index a58c0975a..ba70fb058 100644 --- a/protobufs/gen/swagger/config/service.swagger.json +++ b/protobufs/gen/swagger/config/service.swagger.json @@ -52,9 +52,6 @@ "signing_key_pair": { "$ref": "#/definitions/accountKeyPair" }, - "ethauth_key_pair": { - "$ref": "#/definitions/accountKeyPair" - }, "p2p_key_pair": { "$ref": "#/definitions/accountKeyPair" } diff --git a/resources/data.go b/resources/data.go index a2581ff81..984e595b6 100644 --- a/resources/data.go +++ b/resources/data.go @@ -89,7 +89,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x08\xa6\xb8\x66\x1f\x7c\x8a\x8f\x2e\x65\x60\x24\x4d\x02\xb8\x1e\x92\xc3\x3d\x62\x6f\x25\x85\xa4\xee\xbc\x30\xfc\xdf\x03\xad\xf7\x62\x77\xde\xeb\x66\x46\xdf\x63\x46\xfa\x14\x71\xea\xb5\xe4\xf5\x84\x7f\x61\x7f\x9b\xeb\xd9\x93\x8e\xad\x97\xe9\x34\x60\x7f\xc6\x8a\xeb\xc5\x0f\x84\x40\x8c\xf3\x3a\xf5\xb6\xd5\x84\x5c\xa0\x4c\x9e\xdc\x4a\x42\xce\x78\xf5\xe4\xe9\x2b\x85\x94\x2a\xb6\x46\x3d\xb5\x2e\x30\xb0\xa3\xb6\x32\x2a\xa5\x14\xc4\x9c\x0c\x0f\x6a\x94\xc8\x92\x8c\x5a\x03\x72\xc5\x05\x68\xba\xa3\xb1\x5e\x97\x3e\x53\xff\x95\xc6\xb2\x3c\x63\xa5\x9e\x02\xb6\x3d\x17\x76\x1f\x7b\xdd\x00\xb7\x71\xc7\x2f\x9d\x7a\x1a\x8d\x71\xd9\x4a\xe3\x92\x31\x2c\x39\x11\x73\xe4\x29\x25\x05\x36\x4b\x9e\x34\x30\x48\xd1\x66\x01\x2c\x08\xe0\x8a\x71\x69\x58\x92\xa3\x64\x59\xda\xc8\xa2\x85\xff\xf5\x16\xa8\x70\x69\x9b\x6d\x79\xa5\x9e\xca\x31\xf2\xd1\xa2\x91\x21\x3b\xcb\x32\x1a\x1d\x98\x11\x26\x5b\xc7\xc0\x70\x48\xf4\xdb\x8e\x9e\x53\xa6\x9e\xb6\xdb\xc2\xf4\xd6\xfe\x10\x49\xe7\x17\x9c\xa8\x97\x62\x47\x27\xea\xc5\x28\xb8\x52\x3b\xba\x50\xcf\x77\xb4\x52\x6f\x77\xb4\xc1\xcb\x76\x40\x42\x1e\x90\x8f\x28\xa3\xb3\xdc\x29\x95\x38\x46\x10\xc1\x06\x61\x50\xe1\x88\x2c\xe8\x90\x83\x92\x01\x99\x34\x23\xe8\x64\xad\x75\x19\x46\xe3\x40\x58\x2e\xc4\xb6\xc8\x05\xe2\xf6\x2a\x22\x17\x36\x58\xae\xb5\xd6\x01\x38\x42\x32\x11\xd0\xb1\x91\xa1\xb5\x4a\x40\x8e\x60\xa5\x1e\x13\x1b\x95\xd6\x21\x39\xd0\x46\x8b\x00\x63\x8e\x91\x39\x81\x79\x53\x2a\x89\x7a\xaa\x34\xb2\x91\xc1\xb8\x4f\x02\x70\xaf\x64\xb0\x7b\x27\x44\xde\x2b\x65\x85\x53\xce\x25\x69\x12\xdd\xd1\x57\xac\xad\xcc\xdb\x91\xdf\x9e\xee\x1f\x7e\x81\xd6\xde\xe6\x9a\x3c\x79\x7a\x1f\xdd\x33\xe0\xc9\xa3\x11\x18\x86\x92\x70\xea\xa5\x5f\xff\x48\x9e\x50\xf6\xe5\xe1\xec\x0c\xc3\x6f\xe4\xf7\x7b\x2a\xb7\x0c\x92\xd6\xe7\x0a\x27\x1c\x7e\x8e\xea\x19\xaf\xdb\x18\x3d\x39\xf6\xcb\x72\x7c\x7f\x34\x0c\xff\xae\xb8\xe2\x86\x98\xd6\xcb\xe7\xb9\x9e\xb1\x36\x4f\xc4\x40\xc8\xdb\xad\xf9\x0c\xa5\xff\x53\x2e\xf8\xe7\xdf\x9e\xf0\x61\xd8\x64\x36\xf0\x22\x96\xef\x3f\xc0\xb2\x86\x97\x12\x3f\x6d\xc9\x3f\x1c\x8e\x87\xc3\x31\xac\xe5\x25\x1d\x2b\xb6\x79\xad\x11\xdb\x71\x11\xcb\x27\xbc\x1e\x96\x35\x1c\x16\xbc\x7c\xe7\xd4\xf2\x0a\x1d\x7f\x4d\x3a\x6f\xc4\x1b\xa9\x95\xd3\x54\xa6\xd3\x83\x9e\x77\xf4\xc7\x7d\x7f\x22\xfe\xf0\xc6\xfe\x0c\x6b\x7f\x7e\xd0\xfb\x8e\xfe\xa0\xf1\x3b\xeb\xdd\xf5\xbf\x00\x00\x00\xff\xff\x84\x06\xaa\x14\x8d\x04\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x08\xa6\xb8\x66\x1f\x7c\xbf\xba\x94\x81\x91\x34\x09\xe0\x7a\x48\x0e\xd7\xc4\xde\x6a\x15\x92\xba\xf3\xc2\xf0\x7f\x0f\xb4\xde\x4b\xae\xcb\xb9\x9b\x19\x7d\x8f\x19\xe9\x53\xc2\x79\xb4\x5a\xd6\x13\xfe\x81\xe3\xf5\xda\xce\x81\x0c\xec\xa3\xce\xa7\x09\xc7\x17\x6c\xb8\x5e\xc2\x44\x08\xa4\x74\x5d\xe7\xd1\xb7\x9a\x90\x0b\xd4\x39\x90\x7b\x49\xc8\x19\x6f\x81\x3c\x7d\xa3\x90\x73\xc3\xde\x69\xa0\xce\x47\x06\xce\x68\x27\x93\x52\x4a\x41\x2a\xd9\xf2\xa8\x8c\x44\x96\x65\xd2\x1a\x90\x2b\x2e\x40\xd3\x1d\x4d\xed\xb6\x8c\x2b\x0d\xdf\x68\xaa\xcb\x17\x6c\x34\x50\xc0\xbe\xe7\xc2\xed\xd3\x68\x1b\xe0\x3e\x1e\xf8\x75\xd0\x40\x93\xb5\xbe\x38\x69\x7d\xb6\x96\x65\x2f\x52\x49\x3c\xe7\xac\xc0\x15\xc9\xb3\x06\x06\x39\xb9\x22\x80\x45\x01\x5c\x31\x2e\x2d\xcb\xd2\x48\x56\xa4\x4b\x2c\x39\xf8\x57\x6f\x81\x06\x97\xbe\xd9\xd6\x17\x1a\xa8\x34\x89\x1b\x87\x56\xc6\xe2\x1d\x2b\x68\x75\x64\x56\xd8\xe2\x3c\x03\xcb\x21\xd3\xef\x3b\x7a\xce\x85\x06\xda\xef\x0b\xd3\x7b\xfb\x9f\x48\x3e\x3f\xe3\x4c\x83\x14\x3b\x3a\xd3\x20\x8c\xe0\x4a\xed\xe8\x42\x03\xdf\xd1\x46\x83\xdb\xd1\x0e\xcf\xdb\x01\x19\x79\x44\x6e\x50\x26\xef\xb8\x57\x2a\x73\x4c\x20\xa2\x8b\xc2\xa2\x42\x83\x2c\xea\x58\xa2\x92\x11\x99\xb4\x06\x74\x76\xce\xf9\x02\xc6\x7a\x10\x8e\x0b\xb1\x2d\x72\x81\xb4\xbd\x8a\xc4\x85\x8b\x8e\x6b\xad\x75\x04\x8e\x90\x6d\x02\xf4\xcc\x30\x74\x4e\x09\x28\x09\x9c\xd4\x26\x33\xa3\xb4\x8e\xd9\x83\xb6\x5a\x44\x30\x25\x25\xe6\x05\x96\x4d\xa9\x66\x1a\xa8\xd2\xc8\x0c\x03\xb3\xcf\x02\x70\xaf\x64\x74\x7b\x2f\x44\xd9\x2b\xe5\x84\x57\xde\x67\x69\x33\xdd\xd1\x17\x6c\xbd\x5e\xb7\x23\xbf\x3f\x3d\x3e\xfc\x02\xbd\xbf\x5e\x5b\x0e\xe4\xe9\x6d\xf4\xc8\x40\x20\x1f\x8d\xc0\x34\xd5\x8c\xf3\xa8\xe3\xf6\x5b\x0e\x84\xb2\xaf\x1f\xce\xce\x34\xfd\x42\x7e\x7d\xa4\x72\xcb\x20\xe9\xe3\xda\xe0\x84\xd3\xfb\xa8\x9e\xf1\xb6\x8d\x31\x90\xe3\xb8\x2c\xc7\xb7\x47\xd3\xf4\xf7\x8a\x2b\x6e\x88\x79\xbd\x7c\xbe\xb6\x33\xb6\x1e\x88\x98\x08\x79\xbd\x37\x9f\xa1\x8e\xbf\xea\x05\x7f\xff\x33\x10\x3e\x4d\x9b\xcc\x06\x5e\xc4\xf2\xe3\x07\x58\xd6\xf8\x5c\xd3\xa7\x2d\xf9\x87\xc3\xf1\x70\x38\xc6\xb5\x3e\xe7\x63\xc3\x7e\x5d\x5b\xc2\x7e\x5c\xc4\xf2\x09\x6f\x87\x65\x8d\x87\x05\x2f\x3f\x38\xad\xbe\xc0\xc0\xff\x27\x9d\x37\xe2\x9d\xd4\xeb\x69\xae\xf3\xe9\x83\x9e\x0f\xf4\xcf\xfb\xbe\x23\xbe\x79\xff\x13\x00\x00\xff\xff\x59\xcf\xd7\x6b\x17\x04\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1165, mode: os.FileMode(420), modTime: time.Unix(1551103801, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1047, mode: os.FileMode(420), modTime: time.Unix(1551360206, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/testingutils/commons/mock_did_identity.go b/testingutils/commons/mock_did_identity.go index d53ac7b2c..474e89fc4 100644 --- a/testingutils/commons/mock_did_identity.go +++ b/testingutils/commons/mock_did_identity.go @@ -83,7 +83,7 @@ func (i *MockIdentityService) Exists(ctx context.Context, did identity.DID) erro } // ValidateKey checks if a given key is valid for the given centrifugeID. -func (i *MockIdentityService) ValidateKey(ctx context.Context, did identity.DID, key []byte, purpose int64) error { +func (i *MockIdentityService) ValidateKey(ctx context.Context, did identity.DID, key []byte, purpose *big.Int) error { args := i.Called(ctx, did, key, purpose) return args.Error(0) } diff --git a/testingutils/config/config.go b/testingutils/config/config.go index 665408c92..aa047c373 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -164,17 +164,12 @@ func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { return args.Get(0).(string), args.Get(1).(string) } -func (m *MockConfig) GetEthAuthKeyPair() (pub, priv string) { - args := m.Called() - return args.Get(0).(string), args.Get(1).(string) -} - func CreateAccountContext(t *testing.T, cfg config.Configuration) context.Context { return CreateTenantContextWithContext(t, context.Background(), cfg) } func CreateTenantContextWithContext(t *testing.T, ctx context.Context, cfg config.Configuration) context.Context { - tc, err := configstore.NewAccount("", cfg) + tc, err := configstore.NewAccount("main", cfg) assert.Nil(t, err) contextHeader, err := contextutil.New(ctx, tc) diff --git a/testingutils/identity/identity.go b/testingutils/identity/identity.go index 13957de12..9586b7b14 100644 --- a/testingutils/identity/identity.go +++ b/testingutils/identity/identity.go @@ -16,7 +16,7 @@ import ( func CreateAccountIDWithKeys(contextTimeout time.Duration, acc *configstore.Account, idService identity.ServiceDID, idFactory identity.Factory) (identity.DID, error) { ctxh, _ := contextutil.New(context.Background(), acc) - idConfig, err := identity.GetIdentityConfig(acc) + idKeys, err := acc.GetKeys() if err != nil { return identity.DID{}, err } @@ -38,26 +38,13 @@ func CreateAccountIDWithKeys(contextTimeout time.Duration, acc *configstore.Acco if err != nil { return identity.DID{}, nil } - keys, err := idService.GetKeysByPurpose(*did, big.NewInt(identity.KeyPurposeEthMsgAuth)) - if err != nil { - return identity.DID{}, nil - } - defer cancel() - if err != nil || len(keys) == 0 { - pk, _ := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeEthMsgAuth].PublicKey) - keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeEthMsgAuth), big.NewInt(identity.KeyTypeECDSA)) - err = idService.AddKey(ctxh, keyDID) - if err != nil { - return identity.DID{}, nil - } - } - keys, err = idService.GetKeysByPurpose(*did, big.NewInt(identity.KeyPurposeSigning)) + keys, err := idService.GetKeysByPurpose(*did, &(identity.KeyPurposeSigning.Value)) ctx, cancel = defaultWaitForTransactionMiningContext(contextTimeout) ctxh, _ = contextutil.New(ctx, acc) defer cancel() if err != nil || len(keys) == 0 { - pk, _ := utils.SliceToByte32(idConfig.Keys[identity.KeyPurposeSigning].PublicKey) - keyDID := identity.NewKey(pk, big.NewInt(identity.KeyPurposeSigning), big.NewInt(identity.KeyTypeECDSA)) + pk, _ := utils.SliceToByte32(idKeys[identity.KeyPurposeSigning.Name].PublicKey) + keyDID := identity.NewKey(pk, &(identity.KeyPurposeSigning.Value), big.NewInt(identity.KeyTypeECDSA)) err = idService.AddKey(ctxh, keyDID) if err != nil { return identity.DID{}, nil diff --git a/testingutils/setup.go b/testingutils/setup.go index 8f3aff253..db0225a53 100644 --- a/testingutils/setup.go +++ b/testingutils/setup.go @@ -162,8 +162,6 @@ func BuildIntegrationTestingContext() map[string]interface{} { cfg.Set("keys.p2p.privateKey", fmt.Sprintf("%s/build/resources/p2pKey.key.pem", projDir)) cfg.Set("keys.signing.publicKey", fmt.Sprintf("%s/build/resources/signingKey.pub.pem", projDir)) cfg.Set("keys.signing.privateKey", fmt.Sprintf("%s/build/resources/signingKey.key.pem", projDir)) - cfg.Set("keys.ethauth.publicKey", fmt.Sprintf("%s/build/resources/ethauth.pub.pem", projDir)) - cfg.Set("keys.ethauth.privateKey", fmt.Sprintf("%s/build/resources/ethauth.key.pem", projDir)) SetupSmartContractAddresses(cfg, addresses) cm := make(map[string]interface{}) cm[bootstrap.BootstrappedConfig] = cfg diff --git a/transactions/txv1/manager_test.go b/transactions/txv1/manager_test.go index 00b2587c9..0002dded4 100644 --- a/transactions/txv1/manager_test.go +++ b/transactions/txv1/manager_test.go @@ -72,8 +72,8 @@ func TestService_GetTransaction(t *testing.T) { srv := ctx[transactions.BootstrappedService].(transactions.Manager) cid := testingidentity.GenerateRandomDID() - bytes := utils.RandomSlice(identity.CentIDLength) - assert.Equal(t, identity.CentIDLength, copy(cid[:], bytes)) + bytes := utils.RandomSlice(identity.DIDLength) + assert.Equal(t, identity.DIDLength, copy(cid[:], bytes)) txn := transactions.NewTransaction(cid, "Some transaction") // no transaction diff --git a/utils/tools.go b/utils/tools.go index 8cd682e66..49c9111b7 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -76,13 +76,24 @@ func AddressTo32Bytes(address common.Address) [32]byte { addressBytes := address.Bytes() address32Byte := [32]byte{} for i := 1; i <= common.AddressLength; i++ { - address32Byte[32-i] = addressBytes[common.AddressLength-i] } return address32Byte } +// ByteArrayTo32BytesLeftPadded converts an address to 32 a byte array +// The length of the input has to be less or equals to 32 +func ByteArrayTo32BytesLeftPadded(in []byte) ([32]byte, error) { + byte32 := [32]byte{} + if len(in) > 32 { + return byte32, errors.New("incorrect input length %d should be 32", len(in)) + } + padLength := 32 - len(in) + out := append(make([]byte, padLength, padLength), in...) + return SliceToByte32(out) +} + // RandomSlice returns a randomly filled byte array with length of given size func RandomSlice(size int) (out []byte) { r := make([]byte, size) From 53cb546ebb8c86fe59e373442a22e9431ae09587 Mon Sep 17 00:00:00 2001 From: Charly Date: Tue, 5 Mar 2019 17:06:38 +0100 Subject: [PATCH 215/220] Feat/799 update protos (#814) * updated CD with transition_rules, PrepareNewVersion * lint * update Gopkg.toml with new protos --- Gopkg.lock | 4 ++-- Gopkg.toml | 2 +- documents/coredocument.go | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 7381d405a..d27da9756 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" [[projects]] - digest = "1:ba8eb492e68312a04979d7cf6bd5cd5152c72dafadce8f830f3b932158948c45" + digest = "1:d356ff1419f848de543d6b2f6d95a9a2a38e5f630465c41e043704157aa9cdf3" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "81ddb4a6e09ece1b82f541f77075c7996b79dc78" + revision = "b5992325667104a35db388db0ef0cbf4b0c2bf03" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index c0a4d1ea3..b77589231 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "81ddb4a6e09ece1b82f541f77075c7996b79dc78" + revision = "b5992325667104a35db388db0ef0cbf4b0c2bf03" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/coredocument.go b/documents/coredocument.go index a484b27fe..95db212c1 100644 --- a/documents/coredocument.go +++ b/documents/coredocument.go @@ -173,6 +173,7 @@ func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool PreviousRoot: cd.Document.DocumentRoot, Roles: cd.Document.Roles, ReadRules: cd.Document.ReadRules, + TransitionRules: cd.Document.TransitionRules, Nfts: cd.Document.Nfts, } From 876798caa06166eb45300dd3562dd9152bfa7381 Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Tue, 5 Mar 2019 18:14:20 +0100 Subject: [PATCH 216/220] Enable precommit and hiding anchors (#794) * Enabling all nft tests * node version * node version * block gas limit * Fixes * Fixes * NFT minting works * Fix testworld stuff * Minor * New anchor bindings * Fixes * Fixes * Newest id contracts and skipping execute test * Fixes * Integrating anchor hiding with preimage * minor * Fix failing anchor integration * merge * processor done * Fix tests * Lint * Review comments * Fix tests * Review comments * Review comments * Fix --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- anchors/anchor.go | 20 ++-- anchors/anchor_contract.go | 20 ++-- anchors/anchor_repository.go | 5 +- anchors/anchor_repository_integration_test.go | 99 +++++++++++++++++-- anchors/service.go | 52 ++++++---- build/configs/default_config.yaml | 3 + build/configs/testing_config.yaml | 3 + cmd/centrifuge/create_config.go | 11 +-- cmd/common.go | 9 +- cmd/common_test.go | 2 +- config/configstore/model.go | 13 +++ config/configstore/model_test.go | 8 ++ config/configuration.go | 9 ++ config/configuration_test.go | 1 + crypto/generate.go | 13 +++ crypto/generate_test.go | 11 +++ documents/anchor.go | 10 +- documents/anchor_task.go | 2 +- documents/coredocument.go | 61 +++++++++--- documents/coredocument_test.go | 36 +++++-- documents/documents_test/anchor_test.go | 21 ++-- documents/model.go | 6 ++ documents/processor.go | 42 +++++++- documents/processor_test.go | 14 +++ documents/read_acls.go | 2 +- documents/read_acls_test.go | 36 ++++--- documents/service.go | 3 +- documents/tree_test.go | 3 +- identity/ideth/execute_integration_test.go | 17 +++- identity/ideth/service.go | 8 +- nft/ethereum_payment_obligation.go | 15 +-- nft/ethereum_payment_obligation_test.go | 1 + p2p/receiver/handler_integration_test.go | 4 +- resources/data.go | 10 +- testingutils/config/config.go | 5 + testingutils/documents/documents.go | 6 ++ testworld/nft_test.go | 3 +- testworld/park.go | 10 +- testworld/start_test.go | 3 +- utils/tools.go | 15 ++- 42 files changed, 445 insertions(+), 173 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index d27da9756..5faba6bd7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,11 +57,11 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - digest = "1:2c70a1d77e70fac05b6ad9216a8304424ddedae03a1cd9eb7d5c2adb20bbedf8" + digest = "1:36cbc3e655bd69044d0486115b9e7747db4ae15f0a6e03d851c4bf1408d83ac7" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" + revision = "d269f08e89bd195f158787d2ea59274810abc943" [[projects]] digest = "1:d356ff1419f848de543d6b2f6d95a9a2a38e5f630465c41e043704157aa9cdf3" diff --git a/Gopkg.toml b/Gopkg.toml index b77589231..30944682e 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -32,7 +32,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - revision = "cd4b6655ffbf1c44bb3ddd639a5f46b18bc258d3" + revision = "d269f08e89bd195f158787d2ea59274810abc943" [[constraint]] name = "github.com/Masterminds/semver" diff --git a/anchors/anchor.go b/anchors/anchor.go index e5024bee4..b8689298f 100644 --- a/anchors/anchor.go +++ b/anchors/anchor.go @@ -78,12 +78,9 @@ func RandomDocumentRoot() DocumentRoot { // PreCommitData holds required document details for pre-commit type PreCommitData struct { - AnchorID AnchorID - SigningRoot DocumentRoot - DID identity.DID - Signature []byte - ExpirationBlock *big.Int - SchemaVersion uint + AnchorID AnchorID + SigningRoot DocumentRoot + SchemaVersion uint } // CommitData holds required document details for anchoring @@ -113,14 +110,11 @@ func supportedSchemaVersion() uint { } // newPreCommitData returns a PreCommitData with passed in details -func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot, centrifugeID identity.DID, signature []byte, expirationBlock *big.Int) (preCommitData *PreCommitData) { +func newPreCommitData(anchorID AnchorID, signingRoot DocumentRoot) (preCommitData *PreCommitData) { return &PreCommitData{ - AnchorID: anchorID, - SigningRoot: signingRoot, - DID: centrifugeID, - Signature: signature, - ExpirationBlock: expirationBlock, - SchemaVersion: supportedSchemaVersion(), + AnchorID: anchorID, + SigningRoot: signingRoot, + SchemaVersion: supportedSchemaVersion(), } } diff --git a/anchors/anchor_contract.go b/anchors/anchor_contract.go index 96771008d..138e7a2f8 100644 --- a/anchors/anchor_contract.go +++ b/anchors/anchor_contract.go @@ -28,7 +28,7 @@ var ( ) // AnchorContractABI is the input ABI used to generate the binding from. -const AnchorContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"signingRoot\",\"type\":\"bytes32\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"name\":\"documentProofs\",\"type\":\"bytes32[]\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const AnchorContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorCommitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"anchorId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"blockHeight\",\"type\":\"uint32\"}],\"name\":\"AnchorPreCommitted\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"signingRoot\",\"type\":\"bytes32\"}],\"name\":\"preCommit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorIdPreImage\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"},{\"name\":\"documentProofs\",\"type\":\"bytes32[]\"}],\"name\":\"commit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getAnchorById\",\"outputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"anchorId\",\"type\":\"uint256\"}],\"name\":\"hasValidPreCommit\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // AnchorContract is an auto generated Go binding around an Ethereum contract. type AnchorContract struct { @@ -236,23 +236,23 @@ func (_AnchorContract *AnchorContractCallerSession) HasValidPreCommit(anchorId * // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() -func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.contract.Transact(opts, "commit", anchorId, documentRoot, documentProofs) +// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.contract.Transact(opts, "commit", anchorIdPreImage, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() -func (_AnchorContract *AnchorContractSession) Commit(anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorId, documentRoot, documentProofs) +// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractSession) Commit(anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorIdPreImage, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorId, bytes32 documentRoot, bytes32[] documentProofs) returns() -func (_AnchorContract *AnchorContractTransactorSession) Commit(anchorId *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { - return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorId, documentRoot, documentProofs) +// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +func (_AnchorContract *AnchorContractTransactorSession) Commit(anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { + return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorIdPreImage, documentRoot, documentProofs) } // PreCommit is a paid mutator transaction binding the contract method 0x53b36015. diff --git a/anchors/anchor_repository.go b/anchors/anchor_repository.go index 451977663..9f4472bdb 100644 --- a/anchors/anchor_repository.go +++ b/anchors/anchor_repository.go @@ -2,9 +2,7 @@ package anchors import ( "context" - "math/big" - "github.com/centrifuge/go-centrifuge/identity" logging "github.com/ipfs/go-log" ) @@ -13,7 +11,8 @@ var log = logging.Logger("anchorRepository") // AnchorRepository defines a set of functions that can be // implemented by any type that stores and retrieves the anchoring, and pre anchoring details. type AnchorRepository interface { - PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.DID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) + PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot) (confirmations chan bool, err error) CommitAnchor(ctx context.Context, anchorID AnchorID, documentRoot DocumentRoot, documentProofs [][32]byte) (chan bool, error) GetDocumentRootOf(anchorID AnchorID) (DocumentRoot, error) + HasValidPreCommit(anchorID AnchorID) bool } diff --git a/anchors/anchor_repository_integration_test.go b/anchors/anchor_repository_integration_test.go index d91b98e87..f8fe8d3f8 100644 --- a/anchors/anchor_repository_integration_test.go +++ b/anchors/anchor_repository_integration_test.go @@ -4,6 +4,7 @@ package anchors_test import ( "context" + "crypto/sha256" "os" "testing" @@ -14,6 +15,7 @@ import ( "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/testingutils/config" "github.com/centrifuge/go-centrifuge/utils" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" ) @@ -31,20 +33,79 @@ func TestMain(m *testing.M) { os.Exit(result) } -func TestCommitAnchor_Integration(t *testing.T) { +func TestPreCommitAnchor_Integration(t *testing.T) { anchorID := utils.RandomSlice(32) + signingRoot := utils.RandomSlice(32) + + anchorIDTyped, err := anchors.ToAnchorID(anchorID) + assert.NoError(t, err) + preCommitAnchor(t, anchorID, signingRoot) + valid := anchorRepo.HasValidPreCommit(anchorIDTyped) + assert.True(t, valid) +} + +func TestPreCommit_CommitAnchor_Integration(t *testing.T) { + anchorIDPreImage := utils.RandomSlice(32) + h := sha256.New() + _, err := h.Write(anchorIDPreImage) + assert.NoError(t, err) + var anchorID []byte + anchorID = h.Sum(anchorID) + proofStr := []string{"0x73bb733279cd232d72732afad693f80510e71262738b1205a061a1c34497e49c", "0x408b2caa80ace6ac3a37be957235011c0053f0a561f5a8dcf66d223bfffccecb"} + signingRootStr := "0x6ae9e6cc91cded82896d2439942fd42412b5a2ff5fd45bbed0f5a20de0b962c2" + documentRootStr := "0xf5c8f866f4acf2e2e74a803f86cd2a7ac9285721259b172ef121417e886ca22a" + + signingRoot, err := hexutil.Decode(signingRootStr) + assert.NoError(t, err) + + documentRoot, err := hexutil.Decode(documentRootStr) + assert.NoError(t, err) + + proof1, err := hexutil.Decode(proofStr[0]) + assert.NoError(t, err) + + proof2, err := hexutil.Decode(proofStr[1]) + assert.NoError(t, err) + + var proofB1 [32]byte + copy(proofB1[:], proof1) + var proofB2 [32]byte + copy(proofB2[:], proof2) + + anchorIDTyped, err := anchors.ToAnchorID(anchorID) + assert.NoError(t, err) + preCommitAnchor(t, anchorID, signingRoot) + valid := anchorRepo.HasValidPreCommit(anchorIDTyped) + assert.True(t, valid) + + docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) + commitAnchor(t, anchorIDPreImage, documentRoot, [][anchors.DocumentProofLength]byte{proofB1, proofB2}) + gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorIDTyped) + assert.Nil(t, err) + assert.Equal(t, docRootTyped, gotDocRoot) +} + +func TestCommitAnchor_Integration(t *testing.T) { + anchorIDPreImage := utils.RandomSlice(32) + h := sha256.New() + _, err := h.Write(anchorIDPreImage) + assert.NoError(t, err) + var anchorID []byte + anchorID = h.Sum(anchorID) documentRoot := utils.RandomSlice(32) - anchorIDTyped, _ := anchors.ToAnchorID(anchorID) + anchorIDTyped, err := anchors.ToAnchorID(anchorID) + assert.NoError(t, err) docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) - commitAnchor(t, anchorID, documentRoot, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) + commitAnchor(t, anchorIDPreImage, documentRoot, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) gotDocRoot, err := anchorRepo.GetDocumentRootOf(anchorIDTyped) assert.Nil(t, err) assert.Equal(t, docRootTyped, gotDocRoot) } func commitAnchor(t *testing.T, anchorID, documentRoot []byte, documentProofs [][32]byte) { - anchorIDTyped, _ := anchors.ToAnchorID(anchorID) + anchorIDTyped, err := anchors.ToAnchorID(anchorID) + assert.NoError(t, err) docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) ctx := testingconfig.CreateAccountContext(t, cfg) @@ -55,7 +116,20 @@ func commitAnchor(t *testing.T, anchorID, documentRoot []byte, documentProofs [] assert.True(t, isDone, "isDone should be true") assert.Nil(t, err) +} + +func preCommitAnchor(t *testing.T, anchorID, documentRoot []byte) { + anchorIDTyped, err := anchors.ToAnchorID(anchorID) + assert.NoError(t, err) + docRootTyped, _ := anchors.ToDocumentRoot(documentRoot) + ctx := testingconfig.CreateAccountContext(t, cfg) + done, err := anchorRepo.PreCommitAnchor(ctx, anchorIDTyped, docRootTyped) + + isDone := <-done + + assert.True(t, isDone, "isDone should be true") + assert.Nil(t, err) } func TestCommitAnchor_Integration_Concurrent(t *testing.T) { @@ -63,14 +137,23 @@ func TestCommitAnchor_Integration_Concurrent(t *testing.T) { var doneList [5]chan bool for ix := 0; ix < 5; ix++ { - currentAnchorId := utils.RandomByte32() + anchorIDPreImage := utils.RandomSlice(32) + anchorIDPreImageID, err := anchors.ToAnchorID(anchorIDPreImage) + assert.NoError(t, err) + h := sha256.New() + _, err = h.Write(anchorIDPreImage) + assert.NoError(t, err) + var cAnchorId []byte + cAnchorId = h.Sum(cAnchorId) + currentAnchorId, err := anchors.ToAnchorID(cAnchorId) + assert.NoError(t, err) currentDocumentRoot := utils.RandomByte32() documentProofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} - h, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) + hd, err := ethereum.GetClient().GetEthClient().HeaderByNumber(context.Background(), nil) assert.Nil(t, err, " error must be nil") - commitDataList[ix] = anchors.NewCommitData(h.Number.Uint64(), currentAnchorId, currentDocumentRoot, documentProofs) + commitDataList[ix] = anchors.NewCommitData(hd.Number.Uint64(), currentAnchorId, currentDocumentRoot, documentProofs) ctx := testingconfig.CreateAccountContext(t, cfg) - doneList[ix], err = anchorRepo.CommitAnchor(ctx, currentAnchorId, currentDocumentRoot, documentProofs) + doneList[ix], err = anchorRepo.CommitAnchor(ctx, anchorIDPreImageID, currentDocumentRoot, documentProofs) if err != nil { t.Fatalf("Error commit Anchor %v", err) } diff --git a/anchors/service.go b/anchors/service.go index 7a576ca50..cd9cd5fb3 100644 --- a/anchors/service.go +++ b/anchors/service.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/centrifuge/go-centrifuge/contextutil" - "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -22,6 +21,7 @@ type anchorRepositoryContract interface { AnchorId *big.Int DocumentRoot [32]byte }, error) + HasValidPreCommit(opts *bind.CallOpts, anchorId *big.Int) (bool, error) } type service struct { @@ -36,6 +36,17 @@ func newService(config Config, anchorContract anchorRepositoryContract, queue *q return &service{config: config, anchorRepositoryContract: anchorContract, client: client, queue: queue, txManager: txManager} } +// HasValidPreCommit checks if the given anchorID has a valid pre-commit +func (s *service) HasValidPreCommit(anchorID AnchorID) bool { + // Ignoring cancelFunc as code will block until response or timeout is triggered + opts, _ := s.client.GetGethCallOpts(false) + r, err := s.anchorRepositoryContract.HasValidPreCommit(opts, anchorID.BigInt()) + if err != nil { + return false + } + return r +} + // GetDocumentRootOf takes an anchorID and returns the corresponding documentRoot from the chain. func (s *service) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, err error) { // Ignoring cancelFunc as code will block until response or timeout is triggered @@ -45,32 +56,38 @@ func (s *service) GetDocumentRootOf(anchorID AnchorID) (docRoot DocumentRoot, er } // PreCommitAnchor will call the transaction PreCommit on the smart contract -func (s *service) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot, centID identity.DID, signature []byte, expirationBlock *big.Int) (confirmations <-chan *WatchPreCommit, err error) { +func (s *service) PreCommitAnchor(ctx context.Context, anchorID AnchorID, signingRoot DocumentRoot) (confirmations chan bool, err error) { + did, err := getDID(ctx) + if err != nil { + return nil, err + } + tc, err := contextutil.Account(ctx) if err != nil { return nil, err } - ethRepositoryContract := s.anchorRepositoryContract - opts, err := ethereum.GetClient().GetTxOpts(tc.GetEthereumDefaultAccountName()) + txID := contextutil.TX(ctx) + + conn := s.client + opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) if err != nil { - return confirmations, err + return nil, err } - preCommitData := newPreCommitData(anchorID, signingRoot, centID, signature, expirationBlock) + pc := newPreCommitData(anchorID, signingRoot) if err != nil { return confirmations, err } - err = sendPreCommitTransaction(ethRepositoryContract, opts, preCommitData) + log.Infof("Add Anchor to Pre-commit %s from did:%s", anchorID.String(), did.ToAddress().String()) + _, done, err := s.txManager.ExecuteWithinTX(ctx, did, txID, "Check TX for anchor commit", + s.ethereumTX(opts, s.anchorRepositoryContract.PreCommit, pc.AnchorID.BigInt(), pc.SigningRoot)) if err != nil { - wError := errors.New("%v", err) - log.Errorf("Failed to send Ethereum pre-commit transaction [id: %x, signingRoot: %x, SchemaVersion:%v]: %v", - preCommitData.AnchorID, preCommitData.SigningRoot, preCommitData.SchemaVersion, wError) - return confirmations, err + return nil, err } - return confirmations, err + return done, nil } // ethereumTX is submitting an Ethereum transaction and starts a task to wait for the transaction result @@ -125,7 +142,7 @@ func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentR return nil, err } - uuid := contextutil.TX(ctx) + txID := contextutil.TX(ctx) conn := s.client opts, err := conn.GetTxOpts(tc.GetEthereumDefaultAccountName()) @@ -141,7 +158,7 @@ func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentR cd := NewCommitData(h.Number.Uint64(), anchorID, documentRoot, documentProofs) log.Infof("Add Anchor to Commit %s from did:%s", anchorID.String(), did.ToAddress().String()) - _, done, err := s.txManager.ExecuteWithinTX(ctx, did, uuid, "Check TX for anchor commit", + _, done, err := s.txManager.ExecuteWithinTX(ctx, did, txID, "Check TX for anchor commit", s.ethereumTX(opts, s.anchorRepositoryContract.Commit, cd.AnchorID.BigInt(), cd.DocumentRoot, cd.DocumentProofs)) if err != nil { return nil, err @@ -150,10 +167,3 @@ func (s *service) CommitAnchor(ctx context.Context, anchorID AnchorID, documentR return done, nil } - -// sendPreCommitTransaction sends the actual transaction to the ethereum node. -func sendPreCommitTransaction(contract anchorRepositoryContract, opts *bind.TransactOpts, preCommitData *PreCommitData) error { - - //TODO implement - return nil -} diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index aba88628d..f961e2407 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -135,3 +135,6 @@ ethereum: debug: # pprof for debugging pprof: false + +anchoring: + precommit: true diff --git a/build/configs/testing_config.yaml b/build/configs/testing_config.yaml index 055aeb2b5..b6e393fb9 100644 --- a/build/configs/testing_config.yaml +++ b/build/configs/testing_config.yaml @@ -23,3 +23,6 @@ keys: signing: publicKey: ../../build/resources/signingKey.pub.pem privateKey: ../../build/resources/signingKey.key.pem + +anchoring: + precommit: true \ No newline at end of file diff --git a/cmd/centrifuge/create_config.go b/cmd/centrifuge/create_config.go index e75e28239..1d9ad50c4 100644 --- a/cmd/centrifuge/create_config.go +++ b/cmd/centrifuge/create_config.go @@ -30,16 +30,7 @@ func init() { Short: "Configures Node", Long: ``, Run: func(c *cobra.Command, args []string) { - err := cmd.CreateConfig(targetDataDir, - ethNodeURL, - accountKeyPath, - accountPassword, - network, - apiPort, - p2pPort, - bootstraps, - txPoolAccess, - "", nil) + err := cmd.CreateConfig(targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network, apiPort, p2pPort, bootstraps, txPoolAccess, false, "", nil) if err != nil { log.Info(targetDataDir, accountKeyPath, diff --git a/cmd/common.go b/cmd/common.go index b57da38cc..e60dece3c 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -30,13 +30,7 @@ func generateKeys(config config.Configuration) { } // CreateConfig creates a config file using provide parameters and the default config -func CreateConfig( - targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, - apiPort, p2pPort int64, - bootstraps []string, - txPoolAccess bool, - p2pConnectionTimeout string, - smartContractAddrs *config.SmartContractAddresses) error { +func CreateConfig(targetDataDir, ethNodeURL, accountKeyPath, accountPassword, network string, apiPort, p2pPort int64, bootstraps []string, txPoolAccess bool, preCommitEnabled bool, p2pConnectionTimeout string, smartContractAddrs *config.SmartContractAddresses) error { data := map[string]interface{}{ "targetDataDir": targetDataDir, @@ -49,6 +43,7 @@ func CreateConfig( "p2pPort": p2pPort, "p2pConnectTimeout": p2pConnectionTimeout, "txpoolaccess": txPoolAccess, + "preCommitEnabled": preCommitEnabled, } if smartContractAddrs != nil { data["smartContractAddresses"] = smartContractAddrs diff --git a/cmd/common_test.go b/cmd/common_test.go index 5341779a1..d824ef1a0 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -58,7 +58,7 @@ func TestCreateConfig(t *testing.T) { dataDir := "testconfig" keyPath := path.Join(testingutils.GetProjectDir(), "build/scripts/test-dependencies/test-ethereum/migrateAccount.json") scAddrs := testingutils.GetSmartContractAddresses() - err := CreateConfig(dataDir, "http://127.0.0.1:9545", keyPath, "", "russianhill", 8028, 38202, nil, true, "", scAddrs) + err := CreateConfig(dataDir, "http://127.0.0.1:9545", keyPath, "", "russianhill", 8028, 38202, nil, true, false, "", scAddrs) assert.Nil(t, err, "Create Config should be successful") // config exists diff --git a/config/configstore/model.go b/config/configstore/model.go index 5251e184b..dffae8d0c 100644 --- a/config/configstore/model.go +++ b/config/configstore/model.go @@ -265,6 +265,11 @@ func (nc *NodeConfig) GetSigningKeyPair() (pub, priv string) { return nc.MainIdentity.SigningKeyPair.Pub, nc.MainIdentity.SigningKeyPair.Priv } +// GetPrecommitEnabled refer the interface +func (nc *NodeConfig) GetPrecommitEnabled() bool { + return nc.MainIdentity.PrecommitEnabled +} + // IsPProfEnabled refer the interface func (nc *NodeConfig) IsPProfEnabled() bool { return nc.PprofEnabled @@ -484,6 +489,12 @@ type Account struct { SigningKeyPair KeyPair P2PKeyPair KeyPair keys map[string]config.IDKey + PrecommitEnabled bool +} + +// GetPrecommitEnabled gets the enable pre commit value +func (acc *Account) GetPrecommitEnabled() bool { + return acc.PrecommitEnabled } // GetEthereumAccount gets EthereumAccount @@ -712,6 +723,7 @@ func NewAccount(ethAccountName string, c config.Configuration) (config.Account, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), + PrecommitEnabled: c.GetPrecommitEnabled(), }, nil } @@ -731,5 +743,6 @@ func TempAccount(ethAccountName string, c config.Configuration) (config.Account, ReceiveEventNotificationEndpoint: c.GetReceiveEventNotificationEndpoint(), P2PKeyPair: NewKeyPair(c.GetP2PKeyPair()), SigningKeyPair: NewKeyPair(c.GetSigningKeyPair()), + PrecommitEnabled: c.GetPrecommitEnabled(), }, nil } diff --git a/config/configstore/model_test.go b/config/configstore/model_test.go index 5b2c41af5..dca4e60e1 100644 --- a/config/configstore/model_test.go +++ b/config/configstore/model_test.go @@ -24,6 +24,11 @@ type mockConfig struct { mock.Mock } +func (m *mockConfig) GetPrecommitEnabled() bool { + args := m.Called() + return args.Get(0).(bool) +} + func (m *mockConfig) Type() reflect.Type { args := m.Called() return args.Get(0).(reflect.Type) @@ -263,6 +268,7 @@ func TestNewAccountConfig(t *testing.T) { c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() + c.On("GetPrecommitEnabled").Return(true).Once() _, err := NewAccount("name", c) assert.NoError(t, err) c.AssertExpectations(t) @@ -297,6 +303,7 @@ func TestAccountProtobuf_validationFailures(t *testing.T) { c.On("GetP2PKeyPair").Return("pub", "priv") c.On("GetSigningKeyPair").Return("pub", "priv") c.On("GetEthereumContextWaitTimeout").Return(time.Second) + c.On("GetPrecommitEnabled").Return(true) tc, err := NewAccount("name", c) assert.Nil(t, err) c.AssertExpectations(t) @@ -349,6 +356,7 @@ func TestAccountConfigProtobuf(t *testing.T) { c.On("GetP2PKeyPair").Return("pub", "priv").Once() c.On("GetSigningKeyPair").Return("pub", "priv").Once() c.On("GetEthereumContextWaitTimeout").Return(time.Second).Once() + c.On("GetPrecommitEnabled").Return(true).Once() tc, err := NewAccount("name", c) assert.Nil(t, err) c.AssertExpectations(t) diff --git a/config/configuration.go b/config/configuration.go index c50bca54a..887ef962f 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -108,6 +108,7 @@ type Configuration interface { GetIdentityID() ([]byte, error) GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) + GetPrecommitEnabled() bool // debug specific methods IsPProfEnabled() bool @@ -128,6 +129,7 @@ type Account interface { GetP2PKeyPair() (pub, priv string) GetSigningKeyPair() (pub, priv string) GetEthereumContextWaitTimeout() time.Duration + GetPrecommitEnabled() bool // CreateProtobuf creates protobuf CreateProtobuf() (*accountpb.AccountData, error) @@ -411,6 +413,11 @@ func (c *configuration) IsPProfEnabled() bool { return c.GetBool("debug.pprof") } +// GetPrecommitEnabled returns true if precommit for anchors is enabled +func (c *configuration) GetPrecommitEnabled() bool { + return c.GetBool("anchoring.precommit") +} + // LoadConfiguration loads the configuration from the given file. func LoadConfiguration(configFile string) Configuration { cfg := &configuration{configFile: configFile, mu: sync.RWMutex{}} @@ -481,6 +488,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { p2pPort := args["p2pPort"].(int64) p2pConnectTimeout := args["p2pConnectTimeout"].(string) txPoolAccess := args["txpoolaccess"].(bool) + preCommitEnabled := args["preCommitEnabled"].(bool) if targetDataDir == "" { return nil, errors.New("targetDataDir not provided") @@ -510,6 +518,7 @@ func CreateConfigFile(args map[string]interface{}) (*viper.Viper, error) { v.Set("storage.path", targetDataDir+"/db/centrifuge_data.leveldb") v.Set("configStorage.path", targetDataDir+"/db/centrifuge_config_data.leveldb") v.Set("accounts.keystore", targetDataDir+"/accounts") + v.Set("anchoring.precommit", preCommitEnabled) v.Set("identityId", "") v.Set("centrifugeNetwork", network) v.Set("nodeHostname", "0.0.0.0") diff --git a/config/configuration_test.go b/config/configuration_test.go index dc3967a0c..0266c8c30 100644 --- a/config/configuration_test.go +++ b/config/configuration_test.go @@ -32,6 +32,7 @@ func TestConfiguration_CreateConfigFile(t *testing.T) { "p2pPort": int64(38202), "txpoolaccess": false, "p2pConnectTimeout": "", + "preCommitEnabled": false, } v, err := CreateConfigFile(data) diff --git a/crypto/generate.go b/crypto/generate.go index 247d6f449..93019acb7 100644 --- a/crypto/generate.go +++ b/crypto/generate.go @@ -1,6 +1,7 @@ package crypto import ( + "crypto/sha256" "strings" "github.com/centrifuge/go-centrifuge/crypto/ed25519" @@ -34,3 +35,15 @@ func GenerateSigningKeyPair(publicFileName, privateFileName, curveType string) ( } return nil } + +// GenerateHashPair generates a preimage and hash pair. This is useful in a commit reveal scheme such as what we use for anchor pre-commit > commit flow. +func GenerateHashPair(preimageSize int) (preimage, hash []byte, err error) { + preimage = utils.RandomSlice(preimageSize) + h := sha256.New() + _, err = h.Write(preimage) + if err != nil { + return []byte{}, []byte{}, err + } + hash = h.Sum(hash) + return preimage, hash, nil +} diff --git a/crypto/generate_test.go b/crypto/generate_test.go index 691cd73c5..042aeb2b1 100644 --- a/crypto/generate_test.go +++ b/crypto/generate_test.go @@ -3,6 +3,7 @@ package crypto import ( + "crypto/sha256" "os" "testing" @@ -56,3 +57,13 @@ func TestGenerateSigningKeyPairED25519(t *testing.T) { assert.Equal(t, len(publicKey), PublicKeyED25519Len, "public key length not correct") assert.Equal(t, len(privateKey), PrivateKeyED25519Len, "private key length not correct") } + +func TestGenerateHashPair(t *testing.T) { + pre, hash, err := GenerateHashPair(32) + assert.NoError(t, err) + h := sha256.New() + h.Write(pre) + var expectedHash []byte + expectedHash = h.Sum(expectedHash) + assert.Equal(t, expectedHash, hash) +} diff --git a/documents/anchor.go b/documents/anchor.go index 5d30ee7f4..33071cb94 100644 --- a/documents/anchor.go +++ b/documents/anchor.go @@ -15,6 +15,7 @@ type AnchorProcessor interface { PrepareForSignatureRequests(ctx context.Context, model Model) error RequestSignatures(ctx context.Context, model Model) error PrepareForAnchoring(model Model) error + PreAnchorDocument(ctx context.Context, model Model) error AnchorDocument(ctx context.Context, model Model) error SendDocument(ctx context.Context, model Model) error } @@ -24,7 +25,7 @@ type updaterFunc func(id []byte, model Model) error // AnchorDocument add signature, requests signatures, anchors document, and sends the anchored document // to collaborators -func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, updater updaterFunc) (Model, error) { +func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, updater updaterFunc, preAnchor bool) (Model, error) { id := model.CurrentVersion() err := proc.PrepareForSignatureRequests(ctx, model) if err != nil { @@ -36,6 +37,13 @@ func AnchorDocument(ctx context.Context, model Model, proc AnchorProcessor, upda return nil, err } + if preAnchor { + err = proc.PreAnchorDocument(ctx, model) + if err != nil { + return nil, err + } + } + err = proc.RequestSignatures(ctx, model) if err != nil { return nil, errors.NewTypedError(ErrDocumentAnchoring, errors.New("failed to collect signatures: %v", err)) diff --git a/documents/anchor_task.go b/documents/anchor_task.go index 46a0160d2..f96f2cf5a 100644 --- a/documents/anchor_task.go +++ b/documents/anchor_task.go @@ -112,7 +112,7 @@ func (d *documentAnchorTask) RunTask() (res interface{}, err error) { if _, err = AnchorDocument(ctxh, model, d.processor, func(id []byte, model Model) error { return d.modelSaveFunc(d.accountID[:], id, model) - }); err != nil { + }, tc.GetPrecommitEnabled()); err != nil { return false, errors.New("failed to anchor document: %v", err) } diff --git a/documents/coredocument.go b/documents/coredocument.go index 95db212c1..0dc6f9d91 100644 --- a/documents/coredocument.go +++ b/documents/coredocument.go @@ -6,14 +6,14 @@ import ( "fmt" "strings" - "github.com/golang/protobuf/ptypes/any" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs" "github.com/centrifuge/precise-proofs/proofs/proto" + "github.com/golang/protobuf/ptypes/any" ) const ( @@ -66,15 +66,14 @@ type CoreDocument struct { } // newCoreDocument returns a new CoreDocument. -func newCoreDocument() *CoreDocument { - id := utils.RandomSlice(idSize) - cd := coredocumentpb.CoreDocument{ - DocumentIdentifier: id, - CurrentVersion: id, - NextVersion: utils.RandomSlice(idSize), +func newCoreDocument() (*CoreDocument, error) { + cd := coredocumentpb.CoreDocument{} + err := populateVersions(&cd, nil) + if err != nil { + return nil, err } - return &CoreDocument{cd} + return &CoreDocument{cd}, nil } // NewCoreDocumentFromProtobuf returns CoreDocument from the CoreDocument Protobuf. @@ -86,7 +85,11 @@ func NewCoreDocumentFromProtobuf(cd coredocumentpb.CoreDocument) *CoreDocument { // NewCoreDocumentWithCollaborators generates new core Document, adds collaborators, adds read rules and fills salts func NewCoreDocumentWithCollaborators(collaborators []string) (*CoreDocument, error) { - cd := newCoreDocument() + cd, err := newCoreDocument() + if err != nil { + return nil, errors.New("failed to create coredoc: %v", err) + } + ids, err := identity.NewDIDsFromStrings(collaborators) if err != nil { return nil, errors.New("failed to decode collaborators: %v", err) @@ -110,6 +113,11 @@ func (cd *CoreDocument) CurrentVersion() []byte { return cd.Document.CurrentVersion } +// CurrentVersionPreimage returns the current version preimage of the Document +func (cd *CoreDocument) CurrentVersionPreimage() []byte { + return cd.Document.CurrentPreimage +} + // PreviousVersion returns the previous version of the Document. func (cd *CoreDocument) PreviousVersion() []byte { return cd.Document.PreviousVersion @@ -167,9 +175,6 @@ func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool ucs := filterCollaborators(cs, oldCs...) cdp := coredocumentpb.CoreDocument{ DocumentIdentifier: cd.Document.DocumentIdentifier, - PreviousVersion: cd.Document.CurrentVersion, - CurrentVersion: cd.Document.NextVersion, - NextVersion: utils.RandomSlice(32), PreviousRoot: cd.Document.DocumentRoot, Roles: cd.Document.Roles, ReadRules: cd.Document.ReadRules, @@ -177,6 +182,11 @@ func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool Nfts: cd.Document.Nfts, } + err = populateVersions(&cdp, &cd.Document) + if err != nil { + return nil, err + } + ncd := &CoreDocument{Document: cdp} ncd.addCollaboratorsToReadSignRules(ucs) @@ -224,7 +234,7 @@ func (cd *CoreDocument) addNewRule(role *coredocumentpb.Role, action coredocumen // we will try generating proofs from the dataTree. If failed, we will generate proofs from CoreDocument. // errors out when the proof generation is failed on core Document tree. func (cd *CoreDocument) CreateProofs(docType string, dataTree *proofs.DocumentTree, fields []string) (proofs []*proofspb.Proof, err error) { - srpHashes, err := cd.getSigningRootProofHashes() + srpHashes, err := cd.GetSigningRootProof() if err != nil { return nil, errors.New("failed to generate signing root proofs: %v", err) } @@ -269,9 +279,9 @@ func generateProofs(tree *proofs.DocumentTree, fields []string, appendHashes [][ return proofs, missedProofs } -// getSigningRootProofHashes returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. +// GetSigningRootProof returns the hashes needed to create a proof for fields from SigningRoot to DocumentRoot. // The returned proofs are appended to the proofs generated from the data tree and core Document tree for a successful verification. -func (cd *CoreDocument) getSigningRootProofHashes() (hashes [][]byte, err error) { +func (cd *CoreDocument) GetSigningRootProof() (hashes [][]byte, err error) { tree, err := cd.DocumentRootTree() if err != nil { return @@ -529,3 +539,22 @@ func (cd *CoreDocument) Signatures() (signatures []coredocumentpb.Signature) { return signatures } + +func populateVersions(cd *coredocumentpb.CoreDocument, prevCD *coredocumentpb.CoreDocument) (err error) { + if prevCD != nil { + cd.PreviousVersion = prevCD.CurrentVersion + cd.CurrentVersion = prevCD.NextVersion + cd.CurrentPreimage = prevCD.NextPreimage + } else { + cd.CurrentPreimage, cd.CurrentVersion, err = crypto.GenerateHashPair(idSize) + cd.DocumentIdentifier = cd.CurrentVersion + if err != nil { + return err + } + } + cd.NextPreimage, cd.NextVersion, err = crypto.GenerateHashPair(idSize) + if err != nil { + return err + } + return nil +} diff --git a/documents/coredocument_test.go b/documents/coredocument_test.go index 26243c8cb..4f89eff1d 100644 --- a/documents/coredocument_test.go +++ b/documents/coredocument_test.go @@ -107,7 +107,13 @@ func Test_fetchUniqueCollaborators(t *testing.T) { } func TestCoreDocument_PrepareNewVersion(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) + h := sha256.New() + h.Write(cd.Document.CurrentPreimage) + var expectedCurrentVersion []byte + expectedCurrentVersion = h.Sum(expectedCurrentVersion) + assert.Equal(t, expectedCurrentVersion, cd.Document.CurrentVersion) // missing DocumentRoot c1 := testingidentity.GenerateRandomDID() @@ -136,6 +142,11 @@ func TestCoreDocument_PrepareNewVersion(t *testing.T) { assert.Contains(t, cs, c1) assert.Contains(t, cs, c2) assert.Nil(t, ncd.Document.CoredocumentSalts) + h = sha256.New() + h.Write(ncd.Document.NextPreimage) + var expectedNextVersion []byte + expectedNextVersion = h.Sum(expectedNextVersion) + assert.Equal(t, expectedNextVersion, ncd.Document.NextVersion) ncd, err = cd.PrepareNewVersion(c, true) assert.NoError(t, err) @@ -159,10 +170,11 @@ func TestGetSigningProofHashes(t *testing.T) { Value: []byte{}, } - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) cd.Document.EmbeddedData = docAny cd.Document.DataRoot = utils.RandomSlice(32) - err := cd.setSalts() + err = cd.setSalts() assert.NoError(t, err) _, err = cd.CalculateSigningRoot(documenttypes.InvoiceDataTypeUrl) @@ -171,7 +183,7 @@ func TestGetSigningProofHashes(t *testing.T) { _, err = cd.CalculateDocumentRoot() assert.Nil(t, err) - hashes, err := cd.getSigningRootProofHashes() + hashes, err := cd.GetSigningRootProof() assert.Nil(t, err) assert.Equal(t, 1, len(hashes)) @@ -181,10 +193,11 @@ func TestGetSigningProofHashes(t *testing.T) { } func TestGetDocumentSigningTree(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) // no data root - _, err := cd.signingRootTree(documenttypes.InvoiceDataTypeUrl) + _, err = cd.signingRootTree(documenttypes.InvoiceDataTypeUrl) assert.Error(t, err) // successful tree generation @@ -204,10 +217,11 @@ func TestGetDocumentSigningTree(t *testing.T) { // TestGetDocumentRootTree tests that the documentroottree is properly calculated func TestGetDocumentRootTree(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) // no signing root generated - _, err := cd.DocumentRootTree() + _, err = cd.DocumentRootTree() assert.Error(t, err) // successful Document root generation @@ -235,7 +249,8 @@ func TestCoreDocument_GenerateProofs(t *testing.T) { Value: []byte{}, } - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) cd.Document.EmbeddedData = docAny assert.NoError(t, cd.setSalts()) cd.Document.DataRoot = testTree.RootHash() @@ -298,7 +313,8 @@ func TestCoreDocument_GenerateProofs(t *testing.T) { } func TestCoreDocument_setSalts(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) assert.Nil(t, cd.Document.CoredocumentSalts) assert.NoError(t, cd.setSalts()) diff --git a/documents/documents_test/anchor_test.go b/documents/documents_test/anchor_test.go index 325b57dae..e75d81268 100644 --- a/documents/documents_test/anchor_test.go +++ b/documents/documents_test/anchor_test.go @@ -21,6 +21,11 @@ type mockAnchorProcessor struct { mock.Mock } +func (m *mockAnchorProcessor) PreAnchorDocument(ctx context.Context, model documents.Model) error { + args := m.Called(ctx, model) + return args.Error(0) +} + func (m *mockAnchorProcessor) Send(ctx context.Context, cd coredocumentpb.CoreDocument, recipient identity.DID) (err error) { args := m.Called(ctx, cd, recipient) return args.Error(0) @@ -77,7 +82,7 @@ func TestAnchorDocument(t *testing.T) { m.On("CurrentVersion").Return(id).Once() proc := &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(errors.New("error")).Once() - model, err := documents.AnchorDocument(ctxh, m, proc, updater) + model, err := documents.AnchorDocument(ctxh, m, proc, updater, false) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -90,7 +95,8 @@ func TestAnchorDocument(t *testing.T) { proc = &mockAnchorProcessor{} proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(errors.New("error")).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + proc.On("PreAnchorDocument", ctxh, m).Return(nil).Once() + model, err = documents.AnchorDocument(ctxh, m, proc, updater, true) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -104,7 +110,8 @@ func TestAnchorDocument(t *testing.T) { proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(errors.New("error")).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + proc.On("PreAnchorDocument", ctxh, m).Return(nil).Once() + model, err = documents.AnchorDocument(ctxh, m, proc, updater, true) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -118,8 +125,9 @@ func TestAnchorDocument(t *testing.T) { proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() + proc.On("PreAnchorDocument", ctxh, m).Return(nil).Once() proc.On("AnchorDocument", m).Return(errors.New("error")).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater, true) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -133,9 +141,10 @@ func TestAnchorDocument(t *testing.T) { proc.On("PrepareForSignatureRequests", m).Return(nil).Once() proc.On("RequestSignatures", ctxh, m).Return(nil).Once() proc.On("PrepareForAnchoring", m).Return(nil).Once() + proc.On("PreAnchorDocument", ctxh, m).Return(nil).Once() proc.On("AnchorDocument", m).Return(nil).Once() proc.On("SendDocument", ctxh, m).Return(errors.New("error")).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater, true) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, model) @@ -151,7 +160,7 @@ func TestAnchorDocument(t *testing.T) { proc.On("PrepareForAnchoring", m).Return(nil).Once() proc.On("AnchorDocument", m).Return(nil).Once() proc.On("SendDocument", ctxh, m).Return(nil).Once() - model, err = documents.AnchorDocument(ctxh, m, proc, updater) + model, err = documents.AnchorDocument(ctxh, m, proc, updater, false) m.AssertExpectations(t) proc.AssertExpectations(t) assert.Nil(t, err) diff --git a/documents/model.go b/documents/model.go index 750efd735..dab671d1d 100644 --- a/documents/model.go +++ b/documents/model.go @@ -22,6 +22,9 @@ type Model interface { // CurrentVersion returns the current version identifier of the Document CurrentVersion() []byte + // CurrentVersionPreimage returns the current version pre-image of the Document. This is intended to hide the next version of an updated version of the document. + CurrentVersionPreimage() []byte + // PreviousVersion returns the previous version identifier of the Document PreviousVersion() []byte @@ -47,6 +50,9 @@ type Model interface { // CalculateDocumentRoot returns the Document root of the model. CalculateDocumentRoot() ([]byte, error) + // GetSigningRootProof get the proof for signing root of the model. + GetSigningRootProof() (hashes [][]byte, err error) + // PreviousDocumentRoot returns the Document root of the previous version. PreviousDocumentRoot() []byte diff --git a/documents/processor.go b/documents/processor.go index a0fd73467..95b15d6a3 100644 --- a/documents/processor.go +++ b/documents/processor.go @@ -121,6 +121,36 @@ func (dp defaultProcessor) PrepareForAnchoring(model Model) error { return nil } +// PreAnchorDocument pre-commits a document +func (dp defaultProcessor) PreAnchorDocument(ctx context.Context, model Model) error { + signingRoot, err := model.CalculateSigningRoot() + if err != nil { + return err + } + + anchorID, err := anchors.ToAnchorID(model.CurrentVersion()) + if err != nil { + return err + } + + sRoot, err := anchors.ToDocumentRoot(signingRoot) + if err != nil { + return err + } + + log.Infof("Pre-anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], signingRoot: %#x", model.ID(), model.CurrentVersion(), model.NextVersion(), sRoot) + done, err := dp.anchorRepository.PreCommitAnchor(ctx, anchorID, sRoot) + + isDone := <-done + + if !isDone { + return errors.New("failed to pre-commit anchor: %v", err) + } + + log.Infof("Pre-anchored document with identifiers: [document: %#x, current: %#x, next: %#x], signingRoot: %#x", model.ID(), model.CurrentVersion(), model.NextVersion(), sRoot) + return nil +} + // AnchorDocument validates the model, and anchors the document func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) error { pav := PreAnchorValidator(dp.identityService) @@ -139,17 +169,23 @@ func (dp defaultProcessor) AnchorDocument(ctx context.Context, model Model) erro return errors.New("failed to get document root: %v", err) } - anchorID, err := anchors.ToAnchorID(model.CurrentVersion()) + anchorIDPreimage, err := anchors.ToAnchorID(model.CurrentVersionPreimage()) if err != nil { return errors.New("failed to get anchor ID: %v", err) } + signingRootProof, err := model.GetSigningRootProof() + if err != nil { + return errors.New("failed to get signing root proof: %v", err) + } + + signingRootProofHashes, err := utils.ConvertProofForEthereum(signingRootProof) if err != nil { - return errors.New("failed to generate ethereum MAC: %v", err) + return errors.New("failed to get signing root proof in ethereum format: %v", err) } log.Infof("Anchoring document with identifiers: [document: %#x, current: %#x, next: %#x], rootHash: %#x", model.ID(), model.CurrentVersion(), model.NextVersion(), dr) - done, err := dp.anchorRepository.CommitAnchor(ctx, anchorID, rootHash, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) + done, err := dp.anchorRepository.CommitAnchor(ctx, anchorIDPreimage, rootHash, signingRootProofHashes) isDone := <-done diff --git a/documents/processor_test.go b/documents/processor_test.go index a84ab0518..9bfae99f9 100644 --- a/documents/processor_test.go +++ b/documents/processor_test.go @@ -45,6 +45,12 @@ func (m *mockModel) CalculateDocumentRoot() ([]byte, error) { return dr, args.Error(1) } +func (m *mockModel) GetSigningRootProof() (hashes [][]byte, err error) { + args := m.Called() + dr, _ := args.Get(0).([][]byte) + return dr, args.Error(1) +} + func (m *mockModel) PreviousDocumentRoot() []byte { args := m.Called() dr, _ := args.Get(0).([]byte) @@ -68,6 +74,12 @@ func (m *mockModel) CurrentVersion() []byte { return id } +func (m *mockModel) CurrentVersionPreimage() []byte { + args := m.Called() + id, _ := args.Get(0).([]byte) + return id +} + func (m *mockModel) NextVersion() []byte { args := m.Called() id, _ := args.Get(0).([]byte) @@ -343,8 +355,10 @@ func TestDefaultProcessor_AnchorDocument(t *testing.T) { model = new(mockModel) model.On("ID").Return(id) model.On("CurrentVersion").Return(id) + model.On("CurrentVersionPreimage").Return(id) model.On("NextVersion").Return(next) model.On("CalculateSigningRoot").Return(sr, nil) + model.On("GetSigningRootProof").Return([][32]byte{utils.RandomByte32()}, nil) model.On("Signatures").Return() model.On("CalculateDocumentRoot").Return(utils.RandomSlice(32), nil) model.sigs = append(model.sigs, sig) diff --git a/documents/read_acls.go b/documents/read_acls.go index 9c49dde32..49e483eba 100644 --- a/documents/read_acls.go +++ b/documents/read_acls.go @@ -186,7 +186,7 @@ func (cd *CoreDocument) CreateNFTProofs( pfKeys = append(pfKeys, pks...) } - signingRootProofHashes, err := cd.getSigningRootProofHashes() + signingRootProofHashes, err := cd.GetSigningRootProof() if err != nil { return nil, errors.New("failed to generate signing root proofs: %v", err) } diff --git a/documents/read_acls_test.go b/documents/read_acls_test.go index ec04b1a22..88c50d867 100644 --- a/documents/read_acls_test.go +++ b/documents/read_acls_test.go @@ -26,7 +26,8 @@ import ( ) func TestReadACLs_initReadRules(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) cd.initReadRules(nil) assert.Nil(t, cd.Document.Roles) assert.Nil(t, cd.Document.ReadRules) @@ -42,7 +43,8 @@ func TestReadACLs_initReadRules(t *testing.T) { } func TestReadAccessValidator_AccountCanRead(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) account := testingidentity.GenerateRandomDID() cd.Document.DocumentRoot = utils.RandomSlice(32) ncd, err := cd.PrepareNewVersion([]string{account.String()}, false) @@ -69,12 +71,13 @@ func (m mockRegistry) OwnerOf(registry common.Address, tokenID []byte) (common.A } func TestCoreDocument_addNFTToReadRules(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) // wrong registry or token format registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") tokenID := utils.RandomSlice(34) - err := cd.addNFTToReadRules(registry, tokenID) + err = cd.addNFTToReadRules(registry, tokenID) assert.Error(t, err) assert.Nil(t, cd.Document.CoredocumentSalts) assert.Nil(t, cd.Document.ReadRules) @@ -126,7 +129,8 @@ func TestCoreDocument_NFTOwnerCanRead(t *testing.T) { } func TestCoreDocumentModel_AddNFT(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) cd.Document.DocumentRoot = utils.RandomSlice(32) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") registry2 := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") @@ -135,7 +139,7 @@ func TestCoreDocumentModel_AddNFT(t *testing.T) { assert.Nil(t, cd.Document.ReadRules) assert.Nil(t, cd.Document.Roles) - cd, err := cd.AddNFT(true, registry, tokenID) + cd, err = cd.AddNFT(true, registry, tokenID) assert.Nil(t, err) assert.Len(t, cd.Document.Nfts, 1) assert.Len(t, cd.Document.Nfts[0].RegistryId, 32) @@ -159,14 +163,15 @@ func TestCoreDocumentModel_AddNFT(t *testing.T) { } func TestCoreDocument_IsNFTMinted(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") assert.False(t, cd.IsNFTMinted(nil, registry)) cd.Document.DocumentRoot = utils.RandomSlice(32) tokenID := utils.RandomSlice(32) owner := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da02") - cd, err := cd.AddNFT(true, registry, tokenID) + cd, err = cd.AddNFT(true, registry, tokenID) assert.Nil(t, err) tr := new(mockRegistry) @@ -176,7 +181,8 @@ func TestCoreDocument_IsNFTMinted(t *testing.T) { } func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") tokenID := utils.RandomSlice(32) @@ -198,7 +204,8 @@ func TestCoreDocument_getReadAccessProofKeys(t *testing.T) { } func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) registry := common.HexToAddress("0xf72855759a39fb75fc7341139f5d7a3974d4da08") pf, err := getNFTUniqueProofKey(cd.Document.Nfts, registry) assert.Error(t, err) @@ -216,7 +223,8 @@ func TestCoreDocument_getNFTUniqueProofKey(t *testing.T) { } func TestCoreDocument_getRoleProofKey(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) roleKey := make([]byte, 32, 32) account := testingidentity.GenerateRandomDID() pf, err := getRoleProofKey(cd.Document.Roles, roleKey, account) @@ -236,7 +244,8 @@ func TestCoreDocument_getRoleProofKey(t *testing.T) { } func TestCoreDocumentModel_GetNFTProofs(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) invData := &invoicepb.InvoiceData{} dataSalts, err := GenerateNewSalts(invData, "invoice", []byte{1, 0, 0, 0}) assert.NoError(t, err) @@ -378,7 +387,8 @@ func TestCoreDocumentModel_ATOwnerCanRead(t *testing.T) { } func TestCoreDocumentModel_AddAccessToken(t *testing.T) { - m := newCoreDocument() + m, err := newCoreDocument() + assert.NoError(t, err) m.Document.DocumentRoot = utils.RandomSlice(32) ctx := testingconfig.CreateAccountContext(t, cfg) account, err := contextutil.Account(ctx) diff --git a/documents/service.go b/documents/service.go index cb80165f6..6d919d492 100644 --- a/documents/service.go +++ b/documents/service.go @@ -5,8 +5,6 @@ import ( "context" "time" - "github.com/centrifuge/go-centrifuge/transactions" - "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" "github.com/centrifuge/centrifuge-protobufs/gen/go/notification" "github.com/centrifuge/go-centrifuge/anchors" @@ -14,6 +12,7 @@ import ( "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/notification" + "github.com/centrifuge/go-centrifuge/transactions" "github.com/centrifuge/go-centrifuge/utils" "github.com/centrifuge/precise-proofs/proofs/proto" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/documents/tree_test.go b/documents/tree_test.go index 9c321cc08..a8034d0be 100644 --- a/documents/tree_test.go +++ b/documents/tree_test.go @@ -9,7 +9,8 @@ import ( ) func TestConvertToProofAndProtoSalts(t *testing.T) { - cd := newCoreDocument() + cd, err := newCoreDocument() + assert.NoError(t, err) salts, err := GenerateNewSalts(&cd.Document, "", nil) assert.NoError(t, err) assert.NotNil(t, salts) diff --git a/identity/ideth/execute_integration_test.go b/identity/ideth/execute_integration_test.go index 5f37dc19f..ce731f1ca 100644 --- a/identity/ideth/execute_integration_test.go +++ b/identity/ideth/execute_integration_test.go @@ -22,6 +22,7 @@ import ( "github.com/centrifuge/go-centrifuge/anchors" "github.com/centrifuge/go-centrifuge/bootstrap" "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/crypto" "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" @@ -57,16 +58,19 @@ func TestExecute_successful(t *testing.T) { actionKey := utils.AddressTo32Bytes(common.HexToAddress(actionAddress)) key := id.NewKey(actionKey, &(id.KeyPurposeAction.Value), utils.ByteSliceToBigInt([]byte{123})) err = idSrv.AddKey(aCtx, key) - assert.Nil(t, err) + assert.NoError(t, err) // init params - testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + preimage, hashed, err := crypto.GenerateHashPair(32) + assert.NoError(t, err) + testAnchorIdPreimage, _ := anchors.ToAnchorID(preimage) + testAnchorId, _ := anchors.ToAnchorID(hashed) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) proofs := [][anchors.DocumentProofLength]byte{utils.RandomByte32()} // call execute - err = idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorId.BigInt(), testRootHash, proofs) + err = idSrv.Execute(aCtx, anchorAddress, anchors.AnchorContractABI, "commit", testAnchorIdPreimage.BigInt(), testRootHash, proofs) assert.Nil(t, err, "Execute method calls should be successful") checkAnchor(t, testAnchorId, rootHash) @@ -125,12 +129,15 @@ func TestAnchorWithoutExecute_successful(t *testing.T) { anchorAddress := getAnchorAddress(cfg) anchorContract := bindAnchorContract(t, anchorAddress) - testAnchorId, _ := anchors.ToAnchorID(utils.RandomSlice(32)) + preimage, hashed, err := crypto.GenerateHashPair(32) + assert.NoError(t, err) + testAnchorIdPreimage, _ := anchors.ToAnchorID(preimage) + testAnchorId, _ := anchors.ToAnchorID(hashed) rootHash := utils.RandomSlice(32) testRootHash, _ := anchors.ToDocumentRoot(rootHash) //commit without execute method - commitAnchorWithoutExecute(t, anchorContract, testAnchorId, testRootHash) + commitAnchorWithoutExecute(t, anchorContract, testAnchorIdPreimage, testRootHash) opts, _ := client.GetGethCallOpts(false) result, err := anchorContract.GetAnchorById(opts, testAnchorId.BigInt()) diff --git a/identity/ideth/service.go b/identity/ideth/service.go index 34bc69bbf..6e439458a 100644 --- a/identity/ideth/service.go +++ b/identity/ideth/service.go @@ -7,18 +7,16 @@ import ( "strings" "github.com/centrifuge/centrifuge-protobufs/gen/go/coredocument" - "github.com/centrifuge/go-centrifuge/crypto" - "github.com/centrifuge/go-centrifuge/config" - "github.com/centrifuge/go-centrifuge/crypto/ed25519" - "github.com/centrifuge/go-centrifuge/utils" - "github.com/centrifuge/go-centrifuge/contextutil" + "github.com/centrifuge/go-centrifuge/crypto" + "github.com/centrifuge/go-centrifuge/crypto/ed25519" "github.com/centrifuge/go-centrifuge/errors" "github.com/centrifuge/go-centrifuge/ethereum" id "github.com/centrifuge/go-centrifuge/identity" "github.com/centrifuge/go-centrifuge/queue" "github.com/centrifuge/go-centrifuge/transactions" + "github.com/centrifuge/go-centrifuge/utils" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 6f301ec61..94755b56c 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -346,7 +346,7 @@ func createProofData(model documents.Model, proofspb []*proofspb.Proof) (*proofD } salts[i] = salt32 - property, err := convertProofProperty(p.SortedHashes) + property, err := utils.ConvertProofForEthereum(p.SortedHashes) if err != nil { return nil, err } @@ -356,19 +356,6 @@ func createProofData(model documents.Model, proofspb []*proofspb.Proof) (*proofD return &proofData{Props: props, Values: values, Salts: salts, Proofs: proofs}, nil } -func convertProofProperty(sortedHashes [][]byte) ([][32]byte, error) { - var property [][32]byte - for _, hash := range sortedHashes { - hash32, err := utils.SliceToByte32(hash) - if err != nil { - return nil, err - } - property = append(property, hash32) - } - - return property, nil -} - func bindContract(address common.Address, client ethereum.Client) (*EthereumPaymentObligationContract, error) { return NewEthereumPaymentObligationContract(address, client.GetEthClient()) } diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 32403828e..2c5998300 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -178,6 +178,7 @@ func TestPaymentObligationService(t *testing.T) { configMock.On("GetReceiveEventNotificationEndpoint").Return("") configMock.On("GetP2PKeyPair").Return("", "") configMock.On("GetSigningKeyPair").Return("", "") + configMock.On("GetPrecommitEnabled").Return(false) queueSrv := new(testingutils.MockQueue) txMan := &testingtx.MockTxManager{} txMan.On("ExecuteWithinTX", mock.Anything, mock.Anything, mock.Anything, mock.Anything, diff --git a/p2p/receiver/handler_integration_test.go b/p2p/receiver/handler_integration_test.go index fb319c2f5..97e2e12b5 100644 --- a/p2p/receiver/handler_integration_test.go +++ b/p2p/receiver/handler_integration_test.go @@ -168,7 +168,7 @@ func TestHandler_SendAnchoredDocument_update_fail(t *testing.T) { // Anchor document accDID, err := contextutil.AccountDID(ctx) assert.NoError(t, err) - anchorIDTyped, _ := anchors.ToAnchorID(cd.CurrentVersion) + anchorIDTyped, _ := anchors.ToAnchorID(cd.CurrentPreimage) docRootTyped, _ := anchors.ToDocumentRoot(cd.DocumentRoot) anchorConfirmations, err := anchorRepo.CommitAnchor(ctx, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) @@ -213,7 +213,7 @@ func TestHandler_SendAnchoredDocument(t *testing.T) { po.Document.DocumentRoot = tree.RootHash() // Anchor document - anchorIDTyped, _ := anchors.ToAnchorID(po.Document.CurrentVersion) + anchorIDTyped, _ := anchors.ToAnchorID(po.Document.CurrentPreimage) docRootTyped, _ := anchors.ToDocumentRoot(po.Document.DocumentRoot) anchorConfirmations, err := anchorRepo.CommitAnchor(ctxh, anchorIDTyped, docRootTyped, [][anchors.DocumentProofLength]byte{utils.RandomByte32()}) assert.Nil(t, err) diff --git a/resources/data.go b/resources/data.go index 984e595b6..63dbd15ac 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x59\x73\xdc\x36\x12\x7e\x9f\x5f\xd1\x25\xbf\x24\x55\xcb\x11\x78\x93\x53\x95\xda\x9a\xd3\x76\x2c\x2b\xa3\xc3\x51\xac\x97\x35\x08\x36\x67\x60\x71\x00\x1a\x00\xe7\xf0\xaf\xdf\x02\xc8\x51\x24\xcb\x52\x76\x93\xca\xae\x5e\xc4\x01\xd0\x8d\x3e\xbe\xfe\xd0\xc0\x2b\x98\x61\x45\xdb\xda\x40\x89\x5b\xac\x65\xb3\x41\x61\xc0\xa0\x36\x02\x0d\xd0\x15\xe5\x42\x1b\x50\x5c\xdc\x61\x71\x18\x30\x14\x46\xf1\xaa\x5d\xe1\x39\x9a\x9d\x54\x77\x23\x50\xad\xd6\x9c\x8a\x35\xaf\xeb\x81\x53\xc6\x05\x82\x59\x23\x94\xbd\x5e\xd1\xad\xd4\x60\xd6\xd4\xc0\xf4\x5e\x03\x6c\x28\x17\xc6\xea\x1f\x1c\x97\x8c\x06\x00\xaf\xe0\x4c\x32\x5a\x3b\x13\xb8\x58\x01\x93\xc2\x28\xca\x0c\xd0\xb2\x54\xa8\x35\x6a\x10\x88\x25\x18\x09\x05\x82\x46\x03\x3b\x6e\xd6\x80\x62\x0b\x5b\xaa\x38\x2d\x6a\xd4\xc3\x01\x1c\xe5\xad\x4a\x00\x5e\x8e\x20\x0c\x43\xf7\x8d\x66\x8d\x0a\xdb\x4d\xef\xc1\xdb\x72\x04\x59\x98\x75\x73\x85\x94\x46\x1b\x45\x9b\x25\xa2\xd2\x9d\xac\x07\x27\xa7\xbc\x89\x4e\xfd\x20\x1d\x92\x21\x19\xfa\xa7\x86\x35\xa7\x61\x16\x90\xe0\x94\x37\x95\x3e\xbd\xd8\x5c\x5f\xec\x8b\xdd\x5d\x7b\xfb\xf1\xe3\xac\x6a\xbf\x5e\x17\xfb\xf9\xf8\x12\xaf\xcf\xa7\x67\xf2\xeb\xe1\x10\xc7\xd9\xf6\x42\xac\x7e\xdd\x2e\xdf\x7f\x3e\xfb\x78\x77\xf2\x07\x4a\xc3\xa3\xd2\x5f\xab\x64\x7e\x9e\x6c\xee\xbe\xdc\xe0\xe7\x9b\x77\x37\xc1\x97\x65\xeb\x27\xbf\x35\xe5\xeb\xf0\xee\x67\xe9\x5f\x87\x9b\x35\x5d\x2f\x27\xf1\x15\xc6\xc2\xef\x94\x1e\x43\x35\x3e\x46\xaa\x73\xc0\xba\x8f\xc2\x70\x73\x58\x50\x66\xa4\x3a\x8c\xe0\xe4\xe4\x9b\x99\x4b\x5c\x71\x6d\x1e\x4d\x51\xc1\xd6\x52\x5d\x62\x23\x35\xff\x46\xaa\xa1\x07\x0b\x93\x5f\x8a\x9a\xaf\xa8\xe1\x52\xb8\x39\x97\xbc\xf7\x94\x8b\xef\x42\xa9\xcf\x31\xfc\x70\xd9\x61\xe9\xc7\x01\x3c\xc4\x4e\x67\xea\x2b\x38\x6f\x37\xa8\x38\x83\xb7\x33\x90\x95\xc3\xd1\x03\xc4\xf4\x3a\xee\x53\x1a\xfb\xbd\xd4\xe4\x98\x37\xa8\xb9\x36\x56\x52\xc8\x12\x9f\x42\xae\x51\x72\xcb\xdd\x84\x74\xba\x1f\x18\x70\x34\xf4\x0f\x71\x10\xc6\xc3\x20\x88\x87\x01\x21\xc3\x28\xf8\x16\x0b\x7e\x30\x0b\xdf\x49\x79\x73\xc6\x39\xbb\xf8\x75\x77\xbd\xbe\x9e\x7c\x4c\xf6\xef\xd8\x52\x9e\x55\xc9\xe5\xc5\xc7\x9f\x17\xcd\xae\xf2\x55\x1a\xef\xce\xf6\xc1\xed\x65\xd8\x4c\x4b\xff\xe4\x7b\xea\xb3\x64\x18\xf8\xe4\x39\xf5\x17\xb7\xef\xc7\xd9\xeb\xe5\x1b\xb5\x9d\xdf\x4e\xf2\x5d\x79\x27\x3f\xb0\xf1\x78\x33\xbd\x7d\xd3\xe4\x78\x38\xdc\x46\x57\xf3\x6c\xb5\x50\xe1\xfa\xfa\xfc\xb7\x93\x3e\x46\xf3\x1e\xf7\xf7\x99\x78\x3b\x03\x0f\xfa\x6c\x3c\x57\x19\x51\x2f\x7c\x46\x6d\x78\xa0\xc4\xa6\x96\x07\x2c\xe1\x6a\x43\x95\x81\x69\x0f\x38\x0d\x95\x54\x2e\xa0\x2b\xbe\x45\xf1\x28\x94\x4f\x41\x09\xcf\xa2\x92\xec\x17\x61\x99\x67\x55\x58\x25\x59\x92\xcc\xd3\x34\x08\x49\x1c\x93\x28\xf4\xd3\xd8\xcf\xc7\x7e\x30\x63\x55\x86\x19\xe6\xe3\x17\xf0\x4b\xf6\x79\x92\x10\x46\xc2\xbc\x0c\x7d\x3f\x8a\x43\x5a\x91\x32\xce\x58\x9c\x24\x49\x1a\x84\x65\xce\x82\x8a\xa6\x65\x82\xec\x05\xa4\x93\x7d\x1c\xa6\xc1\x04\x93\x24\xa4\x65\xb8\x98\x21\x99\x04\x8b\x24\x4a\xd3\x84\x64\xfe\x94\xa4\xe9\x34\x9a\xc4\x94\x46\x71\xfa\x52\x4d\x90\x7d\xbc\x20\x41\x9e\x67\xf9\x6c\x9e\x8e\xc7\x11\x49\xe8\x8c\xf8\xb3\x99\x5f\x06\x71\x99\x54\x01\x92\xc0\x9f\x23\x12\x92\xf5\xd5\xf3\x4e\x6e\x69\x17\xbe\x07\x58\x2f\x50\x09\x5a\xaf\x91\xaf\xd6\xa6\xc7\xe2\xab\x57\xaf\xfa\xc4\x74\x12\x8b\xf1\x45\xff\xdb\x83\x1b\x4b\x87\x5c\x54\xad\xa2\x70\x90\x2d\xac\x2c\x8f\x0b\x40\xa5\xa4\xb2\x28\xbb\x5e\x73\x0d\x0a\xbf\xb4\x76\x17\xae\x41\x48\x03\xba\x6d\x1a\xa9\x0c\x96\x50\x20\xa3\xad\x46\x2b\xa9\x5c\x11\xd9\x25\xaa\x15\xc2\x72\xb1\x63\x5a\x6d\xa8\xb1\x95\xd4\xda\xa1\x21\x5c\xb6\xa2\x1b\xf7\xbc\x7e\xec\x27\xaa\xd8\x9a\x6f\x71\x78\xf2\x8f\xde\x28\x80\x9d\x2d\x44\x23\xa1\x94\xff\x74\x12\x14\x6a\xc7\xf2\x0d\x55\xdc\x1c\xba\x8d\x9c\x96\x3b\xe7\x0f\xae\x46\xdd\xcf\x4f\xfd\x02\xcf\x63\x6b\xca\xc5\x4f\xdd\xb4\xe7\x59\x6b\x7f\x0a\x49\x48\x22\xf0\xbc\x1d\x55\x4d\xff\xcf\x2b\xa8\x52\x1c\x15\xc4\x49\x46\x08\x21\xe0\x79\x42\x7a\x54\x30\x8e\xc2\x78\x45\x2d\xd9\x9d\xee\xc6\x34\xaa\x2d\x7a\xb5\x0d\x2a\x78\xde\x86\xee\xbd\xc6\xd6\x3a\x04\xb1\x15\xd2\x82\x36\x7a\x2d\x4d\x3f\xe8\xc6\x36\x5c\x3c\xfa\x69\x6d\xa6\xcc\xf0\x2d\x82\xe7\x59\x8c\xdb\x10\xc9\xaa\x7a\x1a\x09\xf0\xbc\xb2\xf0\x98\xdc\x34\x76\xbd\x14\xa0\x75\x69\x5d\xa2\x6c\x8d\x9e\xe6\x5f\x11\x22\x92\x27\xe0\x79\x9f\xb5\x14\xaa\x61\xde\x5a\x6a\xa3\x81\xd6\xf5\x83\x31\x2e\x0c\xaa\x8a\x32\xb4\xe3\x9f\x1e\xa7\xfb\x69\x30\xbf\x97\xf9\x89\x75\x1f\x4b\x5b\x92\x02\x3b\x43\x8c\x84\x1b\x2c\xae\xec\xb8\xd1\xe0\x62\xa2\xa0\x52\x72\x03\xad\x30\xaa\xd5\x16\x12\x52\xf1\x15\x17\x23\x18\x0e\x4f\x9e\xcd\xa7\xad\xfd\x27\xb9\xfc\xe4\x79\xad\xd0\xb4\x42\x0f\xf7\x8d\xd4\xf8\x09\xaa\x9a\xae\xbe\x01\xf0\x7f\x47\xf8\xc1\x5f\x24\xfc\x47\xb5\xf4\x1f\x53\xbe\x4f\xa2\xa1\x1f\x47\x43\x3f\x1b\xc6\x4f\x8e\xff\x23\x27\x2f\x75\xc2\x29\x7e\x68\x17\xb7\xe7\xad\xff\x7a\xbf\xd5\x87\xc9\xf5\x95\xba\xd6\xf9\xd6\x4c\x92\xc2\xbc\x1f\x8b\x37\x0b\x79\xf6\xb9\xb8\xfb\x3a\xa5\x27\xdf\x51\x1f\x0f\xfd\x2c\x1e\x06\x61\xfa\xec\x06\xd3\xd7\x6c\xc7\xaf\x3f\xcb\x77\x37\x6f\xaa\x09\x8d\xb2\xe0\xc3\xd2\x50\xfc\xb0\x3f\x3f\xdb\x95\xd9\xd7\x42\x4c\xfc\xab\x74\x87\xe3\xdb\x0f\xfb\xdb\x97\x49\xdf\x91\xc6\xb3\x94\x1f\xfc\x0d\x9c\xff\x02\xe5\x4f\xc3\x10\xa3\x64\x9e\x55\x69\x56\x45\xc1\x74\x41\x22\x9f\x4e\x72\x42\x72\x3f\x88\x17\x61\x16\x64\x64\x9e\x91\x79\x38\x7d\x91\xf2\xe3\x88\x62\x98\x86\x15\xc9\x93\x8a\x56\x41\x59\x24\x45\x46\xa3\x24\xf5\x53\x46\x8a\x3c\x43\x56\x51\x92\xc6\x65\xf9\x22\xe5\xb3\x79\x40\x93\x79\x10\x05\xd3\x28\x4e\x27\x2c\x9d\xb3\x02\x09\x2b\xf2\x72\x9c\x55\xc1\x62\x31\x1d\x07\x7e\x90\x86\x2c\x7f\x99\xf2\xa3\x3c\x08\x90\xfa\x94\xc4\xcc\x8f\xe3\x28\xc5\x71\x58\xa5\x34\xc4\x71\x3e\x21\xd5\x64\x11\xe4\x49\x3c\x8f\x92\x64\xd1\x53\xfe\xa5\x6c\xb4\xc1\x27\xa4\x5f\xca\x55\x43\x0d\x5b\xff\xb9\xbe\x28\xfc\x8b\x65\x72\xdc\x1d\x7e\xb8\xfe\x65\xf6\x0b\x30\x85\x96\xf3\x55\x6f\xaa\x2d\x15\xa7\xe7\xc7\x67\x2b\xe7\x6f\x6f\x97\xfe\x7f\x0d\x53\x17\x84\xe7\xaa\x27\xfc\xdf\x16\x4f\x94\x96\xa1\x9f\x47\x55\x16\x67\xa5\xbf\xa0\x41\x32\x8d\x7d\x9a\x87\x49\xe8\x4f\xe7\xe3\x04\x17\x34\x4e\xc9\x3c\x0b\xc3\x97\x8b\x27\xf6\x13\x32\xf1\x03\x92\xfb\x2c\xf2\xe7\xe9\x34\xf2\x2b\x32\x19\xc7\x63\xcc\x83\x98\x92\x28\x48\x58\x44\xc7\xf3\xf1\x8b\xc5\x33\x0f\x83\x20\x23\x29\x09\xd3\x74\x82\xc9\x6c\x46\xc2\x2a\xc8\x93\xc4\x1f\xcf\xfc\x3c\x9a\x97\x24\xcc\xaa\x20\x0b\x49\xf5\x07\xfd\x52\x16\x10\x46\xe2\x79\x86\xf3\xb4\x4c\xc2\x34\x20\xb3\x45\x36\x8b\x31\x99\xc6\x79\x96\x8e\x59\x32\xcb\xf3\x6c\x1a\x05\x27\x03\x7b\xd9\xa4\x86\xc2\x95\x91\x8a\xae\x70\xa0\xbb\xff\xdd\x15\x72\x49\xcd\xda\x85\xb8\xb6\x37\x91\xd9\x04\x2a\x5e\xe3\xc0\x6e\x6a\xd6\x23\x38\x35\x9b\xe6\xf4\xf7\xab\xec\xbf\x4a\x6a\xe8\xd0\xad\x2c\x0b\xab\x77\x2a\x45\xc5\x57\xad\x72\x66\xdd\x6f\xc0\xdc\xe8\xd5\x9f\xdf\xa6\x53\xf0\x64\xb7\x31\x63\xb2\x15\x46\xc3\x1d\x1e\xa0\xf7\x62\x40\xfb\x41\xbb\xcf\x1d\x1e\xec\x30\xf6\x1a\x8f\x53\x56\xf6\xed\x7d\x4f\xb0\xb3\x48\x74\x88\x1a\x2f\xdf\x02\x15\x25\x2c\x83\x25\x5c\x75\x07\xba\x2d\x7e\x14\xb6\xba\x07\xb6\x6e\xdf\x48\x6d\x04\xdd\xe0\x08\x88\xbb\x7c\x92\xc1\x2b\x58\x4a\x65\x7a\x25\x56\xc1\xf7\x05\xed\xa2\x11\x64\x24\x0b\xec\xe6\xb6\xdc\x3d\x23\x5d\x4f\x04\xec\x61\xcc\xf4\xa0\x09\x9a\x2e\x44\x57\x0d\x32\x5e\x1d\x60\xbe\x37\xee\xe8\x85\xb7\xcb\x07\xb6\xba\x5e\x81\x51\x61\xaf\xf2\x0a\x6d\x3b\x54\x02\x35\xc0\x2b\x28\x70\xcd\x45\x09\xe7\xe3\x6b\xab\x06\x7b\xe9\xb7\xcb\x11\xec\x86\xfb\xe1\x61\xf8\xb5\x4b\x80\xb5\xba\xd5\x58\xde\xd7\x93\xf5\xba\xa6\x07\x54\x36\x0d\xce\x5c\xc7\x06\x6e\xf5\x35\xdf\xa0\x6c\x9d\x9b\x02\x64\x83\xa2\x7f\x5f\xe8\x9b\x21\xc7\x7e\xae\xc1\x1b\xc0\x71\xb8\x17\x19\xc1\x49\x48\xb4\x03\xdd\x45\x8b\x2d\x7e\xe3\xae\xdb\x9d\xea\x83\x60\x6b\x25\x85\x6c\xb5\x25\x54\x86\x5a\x73\xb1\x1a\x7c\xb1\x02\x5d\x30\xba\xd7\x11\xdd\xb9\xde\x6e\x0a\x54\x96\x92\x2d\x75\xa0\xd2\xa7\x4c\x0a\x6d\x59\xbe\xa7\xe7\x9d\xbd\x94\x16\xae\xdb\x93\x8c\x9a\x2e\x32\xda\x50\x65\xda\x66\x00\x56\xfe\xa6\x13\x1c\x41\xe7\xde\x42\x21\x6a\x68\x1b\x98\x2e\x3f\x00\x3b\xb0\x1a\x75\xe7\x6a\xb7\x81\x6d\xe4\x77\x94\xbb\x47\x15\x6b\x2f\x6e\xd1\xa2\x08\xfa\xe9\x1b\xca\x9d\xb7\xef\xaf\x46\xe0\x0f\xfa\x23\xa7\xb7\x50\xa1\x51\x1c\x5d\x43\x2a\x77\x7d\xb0\x29\x18\xaa\xed\x91\x63\xff\x5d\x76\x0b\x46\xe0\x13\x1b\xa3\x7b\xe6\xd4\x2e\xfb\x9c\x3d\x8e\xd7\xe0\xc8\x9b\x3d\x44\xb0\x46\x4b\x89\xbb\x35\x67\xeb\x7b\x4e\x85\x1e\xe7\x36\x29\xf6\x42\xd2\x9f\x7a\xd2\xc6\xaf\x3f\xae\x4a\xe0\x5d\xe7\xc9\x5a\x6d\xe4\xa6\xdf\xe4\x58\x84\xfd\xfb\x53\x5f\x5e\xe7\x0e\xef\x27\x1b\xca\xc5\xc9\xfd\x2b\x93\xab\xef\x5e\xf1\xfd\xbe\xac\xb6\x77\x85\x0e\x9a\x3f\xec\xd0\x5d\x95\xb8\x42\xd8\x69\x90\x0a\x78\xc3\xfa\xa7\x27\x5a\xd4\x68\x3f\x99\x3b\x28\xbb\x68\xda\x03\xd1\x0a\x7e\xb8\x3c\x1b\xc1\xda\x98\x66\x74\x7a\xea\x7a\x73\xdb\xd0\x8f\xf2\x38\x8a\x8f\x38\x70\x4f\x63\x2b\x6a\x7d\xe1\xcc\x9a\xbb\xa2\x7a\x69\x3f\x6d\x0c\x8f\x7f\x4f\x16\xd7\x7c\xc3\x4d\xb7\xf8\xcc\x7e\x8e\x20\x4a\xfd\x20\xcc\xb2\x47\xf8\x36\xd2\x25\xba\x4b\x93\xf8\xdd\x33\xa3\xa8\xd0\xf4\xbe\xf1\xb7\x3e\x94\x65\xf7\x94\x46\xc1\xdd\x8d\x1c\x71\x74\xae\x80\x51\x7c\xb5\x42\x85\x65\x57\x0d\x06\xf7\xe6\x88\x91\xae\x22\x12\x62\x4b\xe2\xb9\x8d\x15\xd2\x12\xa4\xa8\x0f\xb6\xd2\x8e\x75\x72\x7c\x4f\x3c\x9a\xf4\xbb\xea\x4b\xa4\xe5\x63\xf5\x7e\xdc\x6b\x3f\xb7\x99\x78\x68\x7b\x23\x65\x0d\x1b\xba\xbf\xc7\xa5\x91\xa0\x51\x94\x16\x93\x0f\x96\xc9\xad\x63\x81\x0d\xdd\xdf\xc3\x33\xe8\x63\xfa\x7d\x95\xee\x86\xb5\xa5\xb5\xd3\x7b\xe8\x6a\x87\x5a\x03\x59\xab\x94\x7b\xcb\x7a\x20\xb1\xa6\x1a\x0a\x44\x01\x25\x1a\x64\xc6\x85\xe9\xa8\xc0\xee\x67\x4f\xc5\xa0\xf7\x60\xc6\xb5\x43\x8b\xd3\xa8\xe5\xe6\x09\xda\x34\x94\xf2\xe1\x45\x1c\xcc\xde\x59\x44\x1b\x6e\x2b\x6c\xbf\x94\xb2\x1e\x33\xcb\x28\x73\x61\x35\x95\x23\x30\xaa\x45\x5b\x6b\x54\x1c\xa0\xc4\xa2\x5d\xad\x7a\x36\xb3\x25\xe0\xb8\x63\x25\xc1\x6e\x32\x70\xb3\x5d\xa9\x35\x8d\x92\x95\x4b\xcf\xbd\x88\xe5\x49\x3b\x3a\x82\x8a\xd6\x1a\x07\xff\x0e\x00\x00\xff\xff\x34\x74\x03\xb1\x11\x16\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x59\x73\x1b\x37\x12\x7e\xe7\xaf\xe8\x92\x5f\x92\xaa\x1d\x6a\xee\x83\x55\xa9\x2d\xea\xf0\x11\xcb\x0a\x75\x45\xb1\x5e\xd6\x18\xa0\x41\xc2\x1a\x02\x63\x00\xc3\xc3\xbf\x7e\x0b\x98\x21\x23\x59\x96\xb2\x9b\x54\x76\xf5\xa2\x21\x80\x6e\x34\xba\xbf\xef\xc3\xf1\x0a\x4e\x90\x93\xae\xb1\xc0\x70\x85\x8d\x6a\x97\x28\x2d\x58\x34\x56\xa2\x05\x32\x27\x42\x1a\x0b\x5a\xc8\x7b\xac\xb7\x23\x8a\xd2\x6a\xc1\xbb\x39\x9e\xa3\x5d\x2b\x7d\x3f\x01\xdd\x19\x23\x88\x5c\x88\xa6\x19\x79\x67\x42\x22\xd8\x05\x02\x1b\xfc\xca\x7e\xa4\x01\xbb\x20\x16\x8e\xf7\x1e\x60\x49\x84\xb4\xce\xff\x68\x37\x64\x32\x02\x78\x05\x67\x8a\x92\xc6\x87\x20\xe4\x1c\xa8\x92\x56\x13\x6a\x81\x30\xa6\xd1\x18\x34\x20\x11\x19\x58\x05\x35\x82\x41\x0b\x6b\x61\x17\x80\x72\x05\x2b\xa2\x05\xa9\x1b\x34\xe3\x11\xec\xec\x9d\x4b\x00\xc1\x26\x90\x24\x89\xff\x46\xbb\x40\x8d\xdd\x72\x58\xc1\x3b\x36\x81\x32\x29\xfb\xbe\x5a\x29\x6b\xac\x26\xed\x0c\x51\x9b\xde\x36\x80\x83\x43\xd1\xa6\x87\x51\x5c\x8c\xc3\x71\x38\x8e\x0e\x2d\x6d\x0f\x93\x32\x0e\xe3\x43\xd1\x72\x73\x78\xb1\xbc\xbe\xd8\xd4\xeb\xfb\xee\xee\xe3\xc7\x13\xde\x7d\xbd\xae\x37\xa7\xd3\x4b\xbc\x3e\x3f\x3e\x53\x5f\xb7\xdb\x2c\x2b\x57\x17\x72\xfe\xeb\x6a\xf6\xe1\xf3\xd9\xc7\xfb\x83\x3f\x70\x9a\xec\x9c\xfe\xca\xf3\xd3\xf3\x7c\x79\xff\xe5\x16\x3f\xdf\xbe\xbf\x8d\xbf\xcc\xba\x28\xff\xad\x65\x6f\x92\xfb\x9f\x55\x74\x9d\x2c\x17\x64\x31\x3b\xca\xae\x30\x93\x51\xef\x74\x97\xaa\xe9\x2e\x53\xfd\x02\xdc\xf2\x51\x5a\x61\xb7\xaf\x09\xb5\x4a\x6f\x27\x70\x70\xf0\x4d\xcf\x25\xce\x85\xb1\x8f\xba\x88\xa4\x0b\xa5\x2f\xb1\x55\x46\x7c\x63\xd5\x92\xad\x83\xc9\x2f\x75\x23\xe6\xc4\x0a\x25\x7d\x9f\x2f\xde\x07\x22\xe4\x77\xa1\x34\xd4\x18\x7e\xb8\xec\xb1\xf4\xe3\x08\x1e\x62\xa7\x0f\xf5\x15\x9c\x77\x4b\xd4\x82\xc2\xbb\x13\x50\xdc\xe3\xe8\x01\x62\x06\x1f\xfb\x92\x66\xd1\x60\x75\xb4\xab\x1b\x34\xc2\x58\x67\x29\x15\xc3\xa7\x90\x6b\xb5\x5a\x09\xdf\xa1\xbc\xef\x07\x01\xec\x02\xfd\x43\x1c\x24\xd9\x38\x8e\xb3\x71\x1c\x86\xe3\x34\xfe\x16\x0b\x51\x7c\x92\xbc\x57\xea\xf6\x4c\x08\x7a\xf1\xeb\xfa\x7a\x71\x7d\xf4\x31\xdf\xbc\xa7\x33\x75\xc6\xf3\xcb\x8b\x8f\x3f\xbf\x6e\xd7\x3c\xd2\x45\xb6\x3e\xdb\xc4\x77\x97\x49\x7b\xcc\xa2\x83\xef\xb9\x2f\xf3\x71\x1c\x85\xcf\xb9\xbf\xb8\xfb\x30\x2d\xdf\xcc\xde\xea\xd5\xe9\xdd\x51\xb5\x66\xf7\xea\x86\x4e\xa7\xcb\xe3\xbb\xb7\x6d\x85\xdb\xed\x5d\x7a\x75\x5a\xce\x5f\xeb\x64\x71\x7d\xfe\xdb\xc1\x90\xa3\xd3\x01\xf7\xfb\x4a\xbc\x3b\x81\x00\x86\x6a\x3c\xc7\x8c\x74\x30\x3e\x23\x2e\x3d\xc0\xb0\x6d\xd4\x16\x19\x5c\x2d\x89\xb6\x70\x3c\x00\xce\x00\x57\xda\x27\x74\x2e\x56\x28\x1f\xa5\xf2\x29\x28\xe1\x59\x54\x86\x9b\x8c\xc4\x69\x95\x17\x9c\xb3\xb4\x24\x31\x89\x68\x99\x30\x56\x66\x49\xc6\xea\x92\xd5\xac\x62\x24\xca\x73\x9a\xe4\x2f\xe0\x37\xdc\x54\x79\x1e\xd2\x30\xa9\x58\x12\x45\x69\x96\x10\x1e\xb2\xac\xa4\x59\x9e\xe7\x45\x9c\xb0\x8a\xc6\x9c\x14\x2c\x47\xfa\x02\xd2\xc3\x4d\x86\x29\x61\x69\x11\xe5\x65\x9e\xc4\x51\x5e\x57\x09\xe5\x49\x8c\x51\xcc\xf2\x8a\x53\x1e\x15\x45\x9c\xd5\x59\xc2\x5e\xe2\x44\xb8\xc9\x6b\x96\xf0\x2c\x09\x8b\x88\x55\xbc\xac\x38\xa5\x59\x15\x46\x59\x95\xd7\x45\x4a\x93\x9a\x45\xb4\xa8\xa2\xb0\x48\x07\xf6\xbc\x57\x2b\xd2\xa7\xef\x01\xd6\x6b\xd4\x92\x34\x0b\x14\xf3\x85\x1d\xb0\xf8\xea\xd5\xab\xa1\x30\xbd\xc5\xeb\xe9\xc5\xf0\x3b\x80\x5b\x27\x87\x42\xf2\x4e\x13\xd8\xaa\x0e\xe6\x4e\xc7\x25\xa0\xd6\x4a\x3b\x94\x5d\x2f\x84\x01\x8d\x5f\x3a\x37\x8b\x30\x20\x95\x05\xd3\xb5\xad\xd2\x16\x19\xd4\x48\x49\x67\xd0\x59\x6a\x4f\x22\x37\x44\x77\x52\x3a\x2d\xf6\x4a\x6b\x2c\xb1\x8e\x49\x9d\x6b\x1a\xc3\x65\x27\xfb\xf6\x20\x18\xda\x7e\x22\x9a\x2e\xc4\x0a\xc7\x07\xff\x18\x82\x02\x58\x3b\x22\x5a\x05\x4c\xfd\xd3\x5b\x10\x68\xbc\xca\xb7\x44\x0b\xbb\xed\x27\xf2\x5e\xee\xfd\x7a\x70\x3e\xe9\x7f\x7e\x1a\x06\x04\x01\x5d\x10\x21\x7f\xea\xbb\x83\xc0\x45\xfb\x53\x12\x26\x61\x0a\x41\xb0\x26\xba\x1d\xfe\x05\x35\xd1\x5a\xa0\x86\x2c\x2f\xc3\x30\x0c\x21\x08\xa4\x0a\x88\xa4\x02\xa5\x0d\xea\x46\xd1\x7b\xd3\xb7\x19\xd4\x2b\x0c\x1a\x97\x54\x08\x82\x25\xd9\x04\xad\xe3\x3a\xc4\x99\x33\x32\x92\xb4\x66\xa1\xec\xd0\xe8\xdb\x96\x42\x3e\xfa\xe9\x62\x26\xd4\x8a\x15\x42\x10\x38\x8c\xbb\x14\x29\xce\x9f\x66\x02\x82\x80\xd5\x01\x55\xcb\xd6\x8d\x57\x12\x8c\x61\x6e\x49\x84\x2e\x30\x30\xe2\x2b\x42\x1a\x56\x39\x04\xc1\x67\xa3\xa4\x6e\x69\xb0\x50\xc6\x1a\x20\x4d\xf3\xa0\x4d\x48\x8b\x9a\x13\x8a\xae\xfd\xd3\xe3\x72\x3f\x4d\xe6\xf7\x2a\x7f\xe4\x96\x8f\xcc\x51\x52\x62\x1f\x88\x55\x70\x8b\xf5\x95\x6b\xb7\x06\x7c\x4e\x34\x70\xad\x96\xd0\x49\xab\x3b\xe3\x20\xa1\xb4\x98\x0b\x39\x81\xf1\xf8\xe0\xd9\x7a\x3a\xee\x3f\xa9\xe5\xa7\x20\xe8\xa4\x21\x1c\x03\xdc\xb4\xca\xe0\x27\xe0\x0d\x99\x7f\x03\xe0\xff\x4e\xf0\xe3\xbf\x28\xf8\x8f\xb8\xf4\x1f\x4b\x7e\x14\xa6\xe3\x28\x4b\xc7\x51\x39\xce\x9e\x6c\xff\x3b\x4d\x9e\x99\x5c\x10\xbc\xe9\x5e\xdf\x9d\x77\xd1\x9b\xcd\xca\x6c\x8f\xae\xaf\xf4\xb5\xa9\x56\xf6\x28\xaf\xed\x87\xa9\x7c\xfb\x5a\x9d\x7d\xae\xef\xbf\x1e\x93\x83\xef\xb8\xcf\xc6\x51\x99\x8d\xe3\xa4\x78\x76\x82\xe3\x37\x74\x2d\xae\x3f\xab\xf7\xb7\x6f\xf9\x11\x49\xcb\xf8\x66\x66\x09\xde\x6c\xce\xcf\xd6\xac\xfc\x5a\xcb\xa3\xe8\xaa\x58\xe3\xf4\xee\x66\x73\xf7\xb2\xe8\x7b\xd1\x78\x56\xf2\xe3\xbf\x41\xf3\x5f\x90\xfc\x98\xb3\x8c\xf3\xb2\x62\xc8\xeb\x38\x23\x21\x29\xb0\x8e\x39\xc6\x2c\x42\xa4\x61\x1c\x95\x45\x9d\xe5\x18\x25\x2f\x4a\x7e\x96\x12\x4c\x8a\x84\x87\x55\xce\x09\x8f\x59\x9d\xd7\x25\x49\xf3\x22\x2a\x68\x58\x57\x25\x52\x4e\xc2\x22\x63\xec\x45\xc9\xc7\x9a\xb3\x12\x13\x92\x87\x65\x98\xb1\x34\x8c\x29\xab\xc3\x3c\xa5\x75\x56\xd7\x45\xc5\xe2\x34\x2e\xa3\x88\xc5\xf4\x65\xc9\xe7\x55\x92\x54\xac\x4a\xa2\xa8\x26\x71\x59\xd2\x22\x2f\xcb\xb0\x8a\x79\x5d\xc6\x09\x2f\x63\x96\x44\x59\x9e\x72\x5e\x0f\x92\x7f\xa9\x5a\x63\xf1\x89\xe8\x33\x35\x6f\x89\xa5\x8b\x3f\x77\x2e\x4a\xfe\x22\x4d\x76\xb3\xc3\x0f\xd7\xbf\x9c\xfc\x02\x54\xa3\xd3\x7c\x3d\x84\xea\xa8\xe2\xfd\xfc\xf8\x2c\x73\xfe\xf6\xe3\xd2\xff\xef\xc0\xd4\x27\xe1\x39\xf6\x24\xff\x5b\xf2\x54\xbc\x8a\x79\x18\x92\x84\x65\x05\x2b\x78\x12\xe5\x18\x53\x12\x97\x55\x95\x33\x9e\xc5\x55\x54\x66\x21\x96\x84\xbe\x4c\x9e\x2c\xca\xc3\xa3\x28\x0e\xab\x88\xa6\xd1\x69\x71\x9c\x46\x3c\x3c\x9a\x66\x53\xac\x1c\x21\xd3\x38\xa7\x29\x99\x9e\x4e\x5f\x24\x0f\xcf\x59\x4e\x12\xe4\x55\x8c\x55\x15\x21\xe6\x75\xc1\x49\x54\xd2\xb8\x08\x63\x92\x25\x71\x1e\x96\x31\x21\xac\x7a\x99\x3c\x69\x52\x84\x59\xc6\x6a\xc6\xd3\x2c\x2e\x13\x86\x29\xc9\xb1\xc2\xb0\xaa\xab\x10\xc3\x34\x21\x69\x49\x63\x56\x47\x07\x23\x77\xd9\x24\x96\xc0\x95\x55\x9a\xcc\x71\x64\xfa\xff\xfd\x15\x72\x46\xec\xc2\xa7\xb8\x71\x37\x91\x93\x23\xe0\xa2\xc1\x91\x9b\xd4\x2e\x26\x70\x68\x97\xed\xe1\xef\x57\xd9\x7f\x31\x62\xc9\xd8\x8f\x64\xb5\xf3\x7b\xac\x24\x17\xf3\x4e\xfb\xb0\xf6\x13\x50\xdf\x7a\xf5\xe7\xa7\xe9\x1d\x3c\x99\x6d\x4a\xa9\xea\xa4\x35\x70\x8f\x5b\x18\x56\x31\x22\x43\xa3\x9b\xe7\x1e\xb7\xae\x19\x07\x8f\xbb\x2e\x67\xfb\x6e\x7f\x26\x58\x3b\x24\x7a\x44\x4d\x67\xef\x80\x48\x06\xb3\x78\x06\x57\xfd\x86\xee\xc8\x8f\xd2\xb1\x7b\xe4\x78\xfb\x56\x19\x2b\xc9\x12\x27\x10\xfa\xcb\x67\x38\x7a\x05\x33\xa5\xed\xe0\xc4\x39\xf8\xbe\xa1\x1b\x34\x81\x32\x2c\x63\x37\xb9\xa3\x7b\x60\x95\x3f\x13\x01\x7d\x98\x33\x33\x6a\xe3\xb6\x4f\xd1\x55\x8b\x54\xf0\x2d\x9c\x6e\xac\xdf\x7a\xe1\xdd\xec\x41\xac\xfe\xac\x40\x89\x74\x57\x79\x8d\xee\x38\xc4\x80\x58\x10\x1c\x6a\x5c\x08\xc9\xe0\x7c\x7a\xed\xdc\xe0\x60\xfd\x6e\x36\x81\xf5\x78\x33\xde\x8e\xbf\xf6\x05\x70\x51\x77\x06\xd9\x9e\x4f\x6e\xd5\x0d\xd9\xa2\x76\x65\xf0\xe1\x7a\x35\xf0\xa3\xaf\xc5\x12\x55\xe7\x97\x29\x41\xb5\x28\x87\xf7\x85\xe1\x30\xe4\xd5\xcf\x1f\xf0\x46\xb0\x6b\x1e\x4c\x26\x70\x90\x84\xc6\x83\xee\xa2\xc3\x0e\xbf\x59\xae\x9f\x9d\x98\xad\xa4\x0b\xad\xa4\xea\x8c\x13\x54\x8a\xc6\x08\x39\x1f\x7d\x71\x06\x7d\x32\xfa\xd7\x11\xd3\x2f\xbd\x5b\xd6\xa8\x9d\x24\x3b\xe9\x40\x6d\x0e\xa9\x92\xc6\xa9\xfc\x20\xcf\x6b\x77\x29\xad\xfd\x69\x4f\x51\x62\xfb\xcc\x18\x4b\xb4\xed\xda\x11\x38\xfb\xdb\xde\x70\x02\xfd\xf2\x5e\x6b\x44\x03\x5d\x0b\xc7\xb3\x1b\xa0\x5b\xda\xa0\xe9\x97\xda\x4f\xe0\x0e\xf2\x6b\x22\xfc\xa3\x8a\x8b\x17\x57\xe8\x50\x04\x43\xf7\x2d\x11\x7e\xb5\x1f\xae\x26\x10\x8d\x86\x2d\x67\x88\x50\xa3\xd5\x02\xfd\x81\x54\xad\x87\x64\x13\xb0\xc4\xb8\x2d\xc7\xfd\xbb\xec\x07\x4c\x20\x0a\x5d\x8e\xf6\xca\x69\x7c\xf5\x05\x7d\x9c\xaf\xd1\x4e\x37\x07\x88\x60\x83\x4e\x12\xd7\x0b\x41\x17\x7b\x4d\x85\x01\xe7\xae\x28\xee\x42\x32\xec\x7a\xca\xe5\x6f\xd8\xae\x18\x88\xfe\xe4\x49\x3b\x63\xd5\x72\x98\x64\x47\xc2\xe1\xfd\x69\xa0\xd7\xb9\xc7\xfb\xc1\x92\x08\x79\xb0\x7f\x65\xf2\xfc\x1e\x1c\xef\xe7\xa5\x8d\xbb\x2b\xf4\xd0\xfc\x61\x8d\xfe\xaa\x24\x34\xc2\xda\x80\xd2\x20\x5a\x3a\x3c\x3d\x91\xba\x41\xf7\x49\xfd\x46\xd9\x67\xd3\x6d\x88\xce\xf0\xe6\xf2\x6c\x02\x0b\x6b\xdb\xc9\xe1\xa1\x3f\x9b\xbb\x03\xfd\xa4\xca\xd2\x6c\x87\x03\xff\x34\x36\x27\x6e\x2d\x82\xba\x70\xe7\xc4\xcc\xdc\xa7\xcb\xe1\xee\xef\xc9\xe0\x46\x2c\x85\xed\x07\x9f\xb9\xcf\x09\xa4\x45\x14\x27\x65\xf9\x08\xdf\x56\xf9\x42\xf7\x65\x92\xbf\xaf\xcc\x6a\x22\x0d\xd9\x1f\xfc\xdd\x1a\x18\xeb\x9f\xd2\x08\xf8\xbb\x91\x17\x8e\x7e\x29\x60\xb5\x98\xcf\x51\x23\xeb\xd9\x60\x71\x63\x77\x18\xe9\x19\x91\x87\x8e\x12\xcf\x4d\xac\x91\x30\x50\xb2\xd9\x3a\xa6\xed\x78\xb2\x7b\x4f\xdc\x85\xf4\xbb\xeb\x4b\x24\xec\xb1\xfb\x28\x1b\xbc\x9f\xbb\x4a\x3c\x8c\xbd\x55\xaa\x81\x25\xd9\xec\x71\x69\x15\x18\x94\xcc\x61\xf2\xc1\x30\xb5\xf2\x2a\xb0\x24\x9b\x3d\x3c\xe3\x21\xa7\xdf\x77\xe9\x6f\x58\x2b\xd2\x78\xbf\xdb\x9e\x3b\xc4\x05\x48\x3b\xad\xfd\x5b\xd6\x03\x8b\x05\x31\x50\x23\x4a\x60\x68\x91\x5a\x9f\xa6\x9d\x03\x37\x9f\xdb\x15\xe3\x61\x05\x27\xc2\x78\xb4\x78\x8f\x46\x2d\x9f\xa0\xcd\x00\x53\x0f\x2f\xe2\x60\x37\x3e\x22\xd2\x0a\xc7\xb0\xcd\x4c\xa9\x66\x4a\x9d\xa2\x9c\x4a\xe7\x89\x4d\xc0\xea\x0e\x1d\xd7\x88\xdc\x02\xc3\xba\x9b\xcf\x07\x35\x73\x14\xf0\xda\x31\x57\xe0\x26\x19\xf9\xde\x9e\x6a\x6d\xab\x15\xf7\xe5\xd9\x9b\x38\x9d\x74\xad\x13\xe0\xa4\x31\x38\x1a\xf5\xbb\xfb\xf0\x74\xda\x6a\xa4\x6a\xe9\x91\xe6\x27\xfc\x77\x00\x00\x00\xff\xff\xf3\x86\xba\x5a\x2f\x16\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,12 +84,12 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5649, mode: os.FileMode(420), modTime: time.Unix(1551103801, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5679, mode: os.FileMode(420), modTime: time.Unix(1551789277, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\x3b\x8f\xdc\x36\x10\xee\xf5\x2b\x08\xa6\xb8\x66\x1f\x7c\xbf\xba\x94\x81\x91\x34\x09\xe0\x7a\x48\x0e\xd7\xc4\xde\x6a\x15\x92\xba\xf3\xc2\xf0\x7f\x0f\xb4\xde\x4b\xae\xcb\xb9\x9b\x19\x7d\x8f\x19\xe9\x53\xc2\x79\xb4\x5a\xd6\x13\xfe\x81\xe3\xf5\xda\xce\x81\x0c\xec\xa3\xce\xa7\x09\xc7\x17\x6c\xb8\x5e\xc2\x44\x08\xa4\x74\x5d\xe7\xd1\xb7\x9a\x90\x0b\xd4\x39\x90\x7b\x49\xc8\x19\x6f\x81\x3c\x7d\xa3\x90\x73\xc3\xde\x69\xa0\xce\x47\x06\xce\x68\x27\x93\x52\x4a\x41\x2a\xd9\xf2\xa8\x8c\x44\x96\x65\xd2\x1a\x90\x2b\x2e\x40\xd3\x1d\x4d\xed\xb6\x8c\x2b\x0d\xdf\x68\xaa\xcb\x17\x6c\x34\x50\xc0\xbe\xe7\xc2\xed\xd3\x68\x1b\xe0\x3e\x1e\xf8\x75\xd0\x40\x93\xb5\xbe\x38\x69\x7d\xb6\x96\x65\x2f\x52\x49\x3c\xe7\xac\xc0\x15\xc9\xb3\x06\x06\x39\xb9\x22\x80\x45\x01\x5c\x31\x2e\x2d\xcb\xd2\x48\x56\xa4\x4b\x2c\x39\xf8\x57\x6f\x81\x06\x97\xbe\xd9\xd6\x17\x1a\xa8\x34\x89\x1b\x87\x56\xc6\xe2\x1d\x2b\x68\x75\x64\x56\xd8\xe2\x3c\x03\xcb\x21\xd3\xef\x3b\x7a\xce\x85\x06\xda\xef\x0b\xd3\x7b\xfb\x9f\x48\x3e\x3f\xe3\x4c\x83\x14\x3b\x3a\xd3\x20\x8c\xe0\x4a\xed\xe8\x42\x03\xdf\xd1\x46\x83\xdb\xd1\x0e\xcf\xdb\x01\x19\x79\x44\x6e\x50\x26\xef\xb8\x57\x2a\x73\x4c\x20\xa2\x8b\xc2\xa2\x42\x83\x2c\xea\x58\xa2\x92\x11\x99\xb4\x06\x74\x76\xce\xf9\x02\xc6\x7a\x10\x8e\x0b\xb1\x2d\x72\x81\xb4\xbd\x8a\xc4\x85\x8b\x8e\x6b\xad\x75\x04\x8e\x90\x6d\x02\xf4\xcc\x30\x74\x4e\x09\x28\x09\x9c\xd4\x26\x33\xa3\xb4\x8e\xd9\x83\xb6\x5a\x44\x30\x25\x25\xe6\x05\x96\x4d\xa9\x66\x1a\xa8\xd2\xc8\x0c\x03\xb3\xcf\x02\x70\xaf\x64\x74\x7b\x2f\x44\xd9\x2b\xe5\x84\x57\xde\x67\x69\x33\xdd\xd1\x17\x6c\xbd\x5e\xb7\x23\xbf\x3f\x3d\x3e\xfc\x02\xbd\xbf\x5e\x5b\x0e\xe4\xe9\x6d\xf4\xc8\x40\x20\x1f\x8d\xc0\x34\xd5\x8c\xf3\xa8\xe3\xf6\x5b\x0e\x84\xb2\xaf\x1f\xce\xce\x34\xfd\x42\x7e\x7d\xa4\x72\xcb\x20\xe9\xe3\xda\xe0\x84\xd3\xfb\xa8\x9e\xf1\xb6\x8d\x31\x90\xe3\xb8\x2c\xc7\xb7\x47\xd3\xf4\xf7\x8a\x2b\x6e\x88\x79\xbd\x7c\xbe\xb6\x33\xb6\x1e\x88\x98\x08\x79\xbd\x37\x9f\xa1\x8e\xbf\xea\x05\x7f\xff\x33\x10\x3e\x4d\x9b\xcc\x06\x5e\xc4\xf2\xe3\x07\x58\xd6\xf8\x5c\xd3\xa7\x2d\xf9\x87\xc3\xf1\x70\x38\xc6\xb5\x3e\xe7\x63\xc3\x7e\x5d\x5b\xc2\x7e\x5c\xc4\xf2\x09\x6f\x87\x65\x8d\x87\x05\x2f\x3f\x38\xad\xbe\xc0\xc0\xff\x27\x9d\x37\xe2\x9d\xd4\xeb\x69\xae\xf3\xe9\x83\x9e\x0f\xf4\xcf\xfb\xbe\x23\xbe\x79\xff\x13\x00\x00\xff\xff\x59\xcf\xd7\x6b\x17\x04\x00\x00") +var _goCentrifugeBuildConfigsTesting_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\xb9\x8e\xe4\x36\x10\xcd\xf5\x15\x04\x1d\x4c\xd2\x07\x4f\xf1\xc8\x1c\x1a\x0b\x3b\xb1\x81\x8d\x8b\x64\xb1\x87\xe8\xd1\x61\x92\x9a\xd9\xc6\x62\xff\xdd\x50\x6f\x8f\xbd\x99\x67\xb3\xaa\xd2\x3b\xaa\xa4\xa7\x88\x73\xaf\x25\x6f\x17\xfc\x03\xfb\xdb\x52\xaf\x9e\x74\x6c\xbd\xcc\x97\x01\xfb\x33\x56\xdc\x26\x3f\x10\x02\x31\x2e\xdb\xdc\xdb\x5e\x13\x32\x41\x99\x3d\xb9\x97\x84\x5c\xf1\xe6\xc9\xd3\x57\x0a\x29\x55\x6c\x8d\x7a\x6a\x5d\x60\x60\x47\x6d\x65\x54\x4a\x29\x88\x39\x19\x1e\xd4\x28\x91\x25\x19\xb5\x06\xe4\x8a\x0b\xd0\xf4\x40\x63\xbd\xad\x7d\xa1\xfe\x2b\x8d\x65\x7d\xc6\x4a\x3d\x05\x6c\x47\x2e\xec\x31\xf6\xba\x03\xee\xe3\x8e\x5f\x3a\xf5\x34\x1a\xe3\xb2\x95\xc6\x25\x63\x58\x72\x22\xe6\xc8\x53\x4a\x0a\x6c\x96\x3c\x69\x60\x90\xa2\xcd\x02\x58\x10\xc0\x15\xe3\xd2\xb0\x24\x47\xc9\xb2\xb4\x91\x45\x0b\xff\xea\xad\x50\x61\x6a\xbb\x6d\x79\xa5\x9e\xca\x31\xf2\xd1\xa2\x91\x21\x3b\xcb\x32\x1a\x1d\x98\x11\x26\x5b\xc7\xc0\x70\x48\xf4\xdb\x81\x5e\x53\xa6\x9e\xb6\xfb\xc2\xf4\xde\xfe\x27\x92\xae\x2f\x38\x53\x2f\xc5\x81\xce\xd4\x8b\x51\x70\xa5\x0e\x74\xa5\x9e\x1f\x68\xa5\xde\x1e\x68\x83\x97\xfd\x80\x84\x3c\x20\x1f\x51\x46\x67\xb9\x53\x2a\x71\x8c\x20\x82\x0d\xc2\xa0\xc2\x11\x59\xd0\x21\x07\x25\x03\x32\x69\x46\xd0\xc9\x5a\xeb\x32\x8c\xc6\x81\xb0\x5c\x88\x7d\x91\x09\xe2\xfe\x2a\x22\x17\x36\x58\xae\xb5\xd6\x01\x38\x42\x32\x11\xd0\xb1\x91\xa1\xb5\x4a\x40\x8e\x60\xa5\x1e\x13\x1b\x95\xd6\x21\x39\xd0\x46\x8b\x00\x63\x8e\x91\x39\x81\x79\x57\x2a\x89\x7a\xaa\x34\xb2\x91\xc1\x78\x4c\x02\xf0\xa8\x64\xb0\x47\x27\x44\x3e\x2a\x65\x85\x53\xce\x25\x69\x12\x3d\xd0\x57\xac\xad\x2c\xfb\x91\xdf\x9e\x1e\x1f\x7e\x85\xd6\xde\x96\x9a\x3c\x79\x7a\x1f\x3d\x32\xe0\xc9\x47\x23\x30\x0c\x25\xe1\xdc\x4b\xbf\xfd\x96\x3c\xa1\xec\xcb\x87\xb3\x33\x0c\xbf\x90\x5f\x1f\xa9\xdc\x33\x48\x5a\x5f\x2a\x5c\x70\xf8\x31\xaa\x57\xbc\xed\x63\xf4\xe4\xdc\xa7\xf5\xfc\xfe\x68\x18\xfe\xde\x70\xc3\x1d\x31\x6f\xd3\xe7\xa5\x5e\xb1\x36\x4f\xc4\x40\xc8\xdb\xbd\xf9\x0c\xa5\xff\x55\x26\xfc\xfd\x4f\x4f\xf8\x30\xec\x32\x3b\x78\x15\xeb\xf7\x1f\x60\xdd\xc2\x4b\x89\x9f\xf6\xe4\x9f\x4e\xe7\xd3\xe9\x1c\xb6\xf2\x92\xce\x15\xdb\xb2\xd5\x88\xed\xbc\x8a\xf5\x13\xde\x4e\xeb\x16\x4e\x2b\x4e\xdf\x39\xb5\xbc\x42\xc7\xff\x27\x5d\x77\xe2\x9d\xd4\xca\x65\x2e\xf3\xe5\x83\x9e\x0f\xf4\xcf\xfb\xfe\x40\x7c\xf7\x1e\x60\x8e\xcf\x4b\x7d\x98\xaf\x15\xe3\x32\x4d\xa5\x7b\xd2\xeb\x86\xff\x04\x00\x00\xff\xff\x1f\xaf\xbe\x5d\x34\x04\x00\x00") func goCentrifugeBuildConfigsTesting_configYamlBytes() ([]byte, error) { return bindataRead( @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1047, mode: os.FileMode(420), modTime: time.Unix(1551360206, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1076, mode: os.FileMode(420), modTime: time.Unix(1551798935, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,7 +204,6 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } - var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -262,3 +261,4 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } + diff --git a/testingutils/config/config.go b/testingutils/config/config.go index aa047c373..b7155ddda 100644 --- a/testingutils/config/config.go +++ b/testingutils/config/config.go @@ -164,6 +164,11 @@ func (m *MockConfig) GetSigningKeyPair() (pub, priv string) { return args.Get(0).(string), args.Get(1).(string) } +func (m *MockConfig) GetPrecommitEnabled() bool { + args := m.Called() + return args.Get(0).(bool) +} + func CreateAccountContext(t *testing.T, cfg config.Configuration) context.Context { return CreateTenantContextWithContext(t, context.Background(), cfg) } diff --git a/testingutils/documents/documents.go b/testingutils/documents/documents.go index 3661d28dd..34847f498 100644 --- a/testingutils/documents/documents.go +++ b/testingutils/documents/documents.go @@ -66,6 +66,12 @@ func (m *MockModel) CurrentVersion() []byte { return args.Get(0).([]byte) } +func (m *MockModel) CurrentVersionPreimage() []byte { + args := m.Called() + id, _ := args.Get(0).([]byte) + return id +} + func (m *MockModel) PackCoreDocument() (coredocumentpb.CoreDocument, error) { args := m.Called() dm, _ := args.Get(0).(coredocumentpb.CoreDocument) diff --git a/testworld/nft_test.go b/testworld/nft_test.go index 0ae070629..e0bcba91a 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -6,9 +6,8 @@ import ( "net/http" "testing" - "github.com/centrifuge/go-centrifuge/documents" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/documents" "github.com/stretchr/testify/assert" ) diff --git a/testworld/park.go b/testworld/park.go index 2d1cee56e..dd9ca45bb 100644 --- a/testworld/park.go +++ b/testworld/park.go @@ -5,18 +5,14 @@ package testworld import ( "context" "fmt" + "net/http" "os" "os/signal" - - "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" - "testing" - "time" - "net/http" - "github.com/centrifuge/go-centrifuge/bootstrap" + "github.com/centrifuge/go-centrifuge/bootstrap/bootstrappers" "github.com/centrifuge/go-centrifuge/cmd" "github.com/centrifuge/go-centrifuge/config" "github.com/centrifuge/go-centrifuge/errors" @@ -270,7 +266,7 @@ func newHost( func (h *host) init() error { if h.createConfig { - err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, h.p2pTimeout, h.smartContractAddrs) + err := cmd.CreateConfig(h.dir, h.ethNodeUrl, h.accountKeyPath, h.accountPassword, h.network, h.apiPort, h.p2pPort, h.bootstrapNodes, h.txPoolAccess, false, h.p2pTimeout, h.smartContractAddrs) if err != nil { return err } diff --git a/testworld/start_test.go b/testworld/start_test.go index e313a321f..08a4027dd 100644 --- a/testworld/start_test.go +++ b/testworld/start_test.go @@ -8,9 +8,8 @@ import ( "os" "testing" - "github.com/centrifuge/go-centrifuge/testingutils" - "github.com/centrifuge/go-centrifuge/config" + "github.com/centrifuge/go-centrifuge/testingutils" ) type testType string diff --git a/utils/tools.go b/utils/tools.go index 49c9111b7..a3255cc13 100644 --- a/utils/tools.go +++ b/utils/tools.go @@ -6,7 +6,6 @@ import ( "math/big" "github.com/centrifuge/go-centrifuge/errors" - "github.com/centrifuge/gocelery" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -200,3 +199,17 @@ func ConvertIntToByte32(n int) ([32]byte, error) { func ConvertByte32ToInt(nb [32]byte) int { return int(binary.BigEndian.Uint64(nb[:])) } + +// ConvertProofForEthereum converts a proof to 32 byte format needed by ethereum +func ConvertProofForEthereum(sortedHashes [][]byte) ([][32]byte, error) { + var property [][32]byte + for _, hash := range sortedHashes { + hash32, err := SliceToByte32(hash) + if err != nil { + return nil, err + } + property = append(property, hash32) + } + + return property, nil +} From 7dac9fa49d32f630cce2c70dc97244284eb4448f Mon Sep 17 00:00:00 2001 From: Vimukthi Date: Wed, 6 Mar 2019 12:19:25 +0100 Subject: [PATCH 217/220] Add smart contract addresses for v0.5.5 (#818) * Add smart contract addresses * Add smart contract addresses --- build/configs/default_config.yaml | 18 +++++++++--------- resources/data.go | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index f961e2407..7054913bf 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -27,10 +27,10 @@ networks: ethereumNetworkId: 4 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x5a24967ffd48a2a1c83dd8535db8dbd9da166c36" + identityFactory: "0x1b05047e8118a6daf444f2245660f5d3f4620a9d" identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" - anchorRepository: "0x5e4ad4716863216b93cf32e12d69fcf17725b53d" - paymentObligation: "0x6bd3f53071d9f89fcc5901596b74c3bd1c791074" + anchorRepository: "0xe98b0c6dd9026743f73667efaf8a950d0d8f49d2" + paymentObligation: "0xbc1ae72fbb6a20825f5136ccba0e83d6b8e7849d" # Kovan test network bernalheights: @@ -51,10 +51,10 @@ networks: ethereumNetworkId: 42 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x2fd5ff89defb25a0a7eb2fe2d1eec02187b56e13" + identityFactory: "0x966168018e40c41874d86cedfbc80ee6bb8a5764" identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" - anchorRepository: "0xebfd8e3a60805d402cdb064cb5bb79d242811d2c" - paymentObligation: "0xf9339d9311ba288c7688092fb823f82d31564ffb" + anchorRepository: "0xf77110dd6e28b2ca751370a6f820eb2774db3810" + paymentObligation: "0x277129ce2fb7207c0f0e4a60d2d0b5f8cfa0bbbb" # Ropsten test network dogpatch: @@ -68,10 +68,10 @@ networks: ethereumNetworkId: 3 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x9f92f00a3d57d7f316e2ca28996df5291850e8ac" + identityFactory: "0x8a54c47d66521e6fdcdf31c421e0612154df846b" identityRegistry: "0x55160B12091c41E7C41f0BA5Ae925a0426c4aAEA" - anchorRepository: "0xf6d6a3ef92e991ee6b7fa18c2702a5326082aad9" - paymentObligation: "0x437055dbdf45283de4a6e9e09b90e043a48c2db1" + anchorRepository: "0xf622748701c125ed2231ccf3fcfb7a2b01fa8355" + paymentObligation: "0xdd47aea747c2204d244051363ee40bc2b52bc9df" # Data Storage storage: diff --git a/resources/data.go b/resources/data.go index 63dbd15ac..a0da2d3c0 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x59\x73\x1b\x37\x12\x7e\xe7\xaf\xe8\x92\x5f\x92\xaa\x1d\x6a\xee\x83\x55\xa9\x2d\xea\xf0\x11\xcb\x0a\x75\x45\xb1\x5e\xd6\x18\xa0\x41\xc2\x1a\x02\x63\x00\xc3\xc3\xbf\x7e\x0b\x98\x21\x23\x59\x96\xb2\x9b\x54\x76\xf5\xa2\x21\x80\x6e\x34\xba\xbf\xef\xc3\xf1\x0a\x4e\x90\x93\xae\xb1\xc0\x70\x85\x8d\x6a\x97\x28\x2d\x58\x34\x56\xa2\x05\x32\x27\x42\x1a\x0b\x5a\xc8\x7b\xac\xb7\x23\x8a\xd2\x6a\xc1\xbb\x39\x9e\xa3\x5d\x2b\x7d\x3f\x01\xdd\x19\x23\x88\x5c\x88\xa6\x19\x79\x67\x42\x22\xd8\x05\x02\x1b\xfc\xca\x7e\xa4\x01\xbb\x20\x16\x8e\xf7\x1e\x60\x49\x84\xb4\xce\xff\x68\x37\x64\x32\x02\x78\x05\x67\x8a\x92\xc6\x87\x20\xe4\x1c\xa8\x92\x56\x13\x6a\x81\x30\xa6\xd1\x18\x34\x20\x11\x19\x58\x05\x35\x82\x41\x0b\x6b\x61\x17\x80\x72\x05\x2b\xa2\x05\xa9\x1b\x34\xe3\x11\xec\xec\x9d\x4b\x00\xc1\x26\x90\x24\x89\xff\x46\xbb\x40\x8d\xdd\x72\x58\xc1\x3b\x36\x81\x32\x29\xfb\xbe\x5a\x29\x6b\xac\x26\xed\x0c\x51\x9b\xde\x36\x80\x83\x43\xd1\xa6\x87\x51\x5c\x8c\xc3\x71\x38\x8e\x0e\x2d\x6d\x0f\x93\x32\x0e\xe3\x43\xd1\x72\x73\x78\xb1\xbc\xbe\xd8\xd4\xeb\xfb\xee\xee\xe3\xc7\x13\xde\x7d\xbd\xae\x37\xa7\xd3\x4b\xbc\x3e\x3f\x3e\x53\x5f\xb7\xdb\x2c\x2b\x57\x17\x72\xfe\xeb\x6a\xf6\xe1\xf3\xd9\xc7\xfb\x83\x3f\x70\x9a\xec\x9c\xfe\xca\xf3\xd3\xf3\x7c\x79\xff\xe5\x16\x3f\xdf\xbe\xbf\x8d\xbf\xcc\xba\x28\xff\xad\x65\x6f\x92\xfb\x9f\x55\x74\x9d\x2c\x17\x64\x31\x3b\xca\xae\x30\x93\x51\xef\x74\x97\xaa\xe9\x2e\x53\xfd\x02\xdc\xf2\x51\x5a\x61\xb7\xaf\x09\xb5\x4a\x6f\x27\x70\x70\xf0\x4d\xcf\x25\xce\x85\xb1\x8f\xba\x88\xa4\x0b\xa5\x2f\xb1\x55\x46\x7c\x63\xd5\x92\xad\x83\xc9\x2f\x75\x23\xe6\xc4\x0a\x25\x7d\x9f\x2f\xde\x07\x22\xe4\x77\xa1\x34\xd4\x18\x7e\xb8\xec\xb1\xf4\xe3\x08\x1e\x62\xa7\x0f\xf5\x15\x9c\x77\x4b\xd4\x82\xc2\xbb\x13\x50\xdc\xe3\xe8\x01\x62\x06\x1f\xfb\x92\x66\xd1\x60\x75\xb4\xab\x1b\x34\xc2\x58\x67\x29\x15\xc3\xa7\x90\x6b\xb5\x5a\x09\xdf\xa1\xbc\xef\x07\x01\xec\x02\xfd\x43\x1c\x24\xd9\x38\x8e\xb3\x71\x1c\x86\xe3\x34\xfe\x16\x0b\x51\x7c\x92\xbc\x57\xea\xf6\x4c\x08\x7a\xf1\xeb\xfa\x7a\x71\x7d\xf4\x31\xdf\xbc\xa7\x33\x75\xc6\xf3\xcb\x8b\x8f\x3f\xbf\x6e\xd7\x3c\xd2\x45\xb6\x3e\xdb\xc4\x77\x97\x49\x7b\xcc\xa2\x83\xef\xb9\x2f\xf3\x71\x1c\x85\xcf\xb9\xbf\xb8\xfb\x30\x2d\xdf\xcc\xde\xea\xd5\xe9\xdd\x51\xb5\x66\xf7\xea\x86\x4e\xa7\xcb\xe3\xbb\xb7\x6d\x85\xdb\xed\x5d\x7a\x75\x5a\xce\x5f\xeb\x64\x71\x7d\xfe\xdb\xc1\x90\xa3\xd3\x01\xf7\xfb\x4a\xbc\x3b\x81\x00\x86\x6a\x3c\xc7\x8c\x74\x30\x3e\x23\x2e\x3d\xc0\xb0\x6d\xd4\x16\x19\x5c\x2d\x89\xb6\x70\x3c\x00\xce\x00\x57\xda\x27\x74\x2e\x56\x28\x1f\xa5\xf2\x29\x28\xe1\x59\x54\x86\x9b\x8c\xc4\x69\x95\x17\x9c\xb3\xb4\x24\x31\x89\x68\x99\x30\x56\x66\x49\xc6\xea\x92\xd5\xac\x62\x24\xca\x73\x9a\xe4\x2f\xe0\x37\xdc\x54\x79\x1e\xd2\x30\xa9\x58\x12\x45\x69\x96\x10\x1e\xb2\xac\xa4\x59\x9e\xe7\x45\x9c\xb0\x8a\xc6\x9c\x14\x2c\x47\xfa\x02\xd2\xc3\x4d\x86\x29\x61\x69\x11\xe5\x65\x9e\xc4\x51\x5e\x57\x09\xe5\x49\x8c\x51\xcc\xf2\x8a\x53\x1e\x15\x45\x9c\xd5\x59\xc2\x5e\xe2\x44\xb8\xc9\x6b\x96\xf0\x2c\x09\x8b\x88\x55\xbc\xac\x38\xa5\x59\x15\x46\x59\x95\xd7\x45\x4a\x93\x9a\x45\xb4\xa8\xa2\xb0\x48\x07\xf6\xbc\x57\x2b\xd2\xa7\xef\x01\xd6\x6b\xd4\x92\x34\x0b\x14\xf3\x85\x1d\xb0\xf8\xea\xd5\xab\xa1\x30\xbd\xc5\xeb\xe9\xc5\xf0\x3b\x80\x5b\x27\x87\x42\xf2\x4e\x13\xd8\xaa\x0e\xe6\x4e\xc7\x25\xa0\xd6\x4a\x3b\x94\x5d\x2f\x84\x01\x8d\x5f\x3a\x37\x8b\x30\x20\x95\x05\xd3\xb5\xad\xd2\x16\x19\xd4\x48\x49\x67\xd0\x59\x6a\x4f\x22\x37\x44\x77\x52\x3a\x2d\xf6\x4a\x6b\x2c\xb1\x8e\x49\x9d\x6b\x1a\xc3\x65\x27\xfb\xf6\x20\x18\xda\x7e\x22\x9a\x2e\xc4\x0a\xc7\x07\xff\x18\x82\x02\x58\x3b\x22\x5a\x05\x4c\xfd\xd3\x5b\x10\x68\xbc\xca\xb7\x44\x0b\xbb\xed\x27\xf2\x5e\xee\xfd\x7a\x70\x3e\xe9\x7f\x7e\x1a\x06\x04\x01\x5d\x10\x21\x7f\xea\xbb\x83\xc0\x45\xfb\x53\x12\x26\x61\x0a\x41\xb0\x26\xba\x1d\xfe\x05\x35\xd1\x5a\xa0\x86\x2c\x2f\xc3\x30\x0c\x21\x08\xa4\x0a\x88\xa4\x02\xa5\x0d\xea\x46\xd1\x7b\xd3\xb7\x19\xd4\x2b\x0c\x1a\x97\x54\x08\x82\x25\xd9\x04\xad\xe3\x3a\xc4\x99\x33\x32\x92\xb4\x66\xa1\xec\xd0\xe8\xdb\x96\x42\x3e\xfa\xe9\x62\x26\xd4\x8a\x15\x42\x10\x38\x8c\xbb\x14\x29\xce\x9f\x66\x02\x82\x80\xd5\x01\x55\xcb\xd6\x8d\x57\x12\x8c\x61\x6e\x49\x84\x2e\x30\x30\xe2\x2b\x42\x1a\x56\x39\x04\xc1\x67\xa3\xa4\x6e\x69\xb0\x50\xc6\x1a\x20\x4d\xf3\xa0\x4d\x48\x8b\x9a\x13\x8a\xae\xfd\xd3\xe3\x72\x3f\x4d\xe6\xf7\x2a\x7f\xe4\x96\x8f\xcc\x51\x52\x62\x1f\x88\x55\x70\x8b\xf5\x95\x6b\xb7\x06\x7c\x4e\x34\x70\xad\x96\xd0\x49\xab\x3b\xe3\x20\xa1\xb4\x98\x0b\x39\x81\xf1\xf8\xe0\xd9\x7a\x3a\xee\x3f\xa9\xe5\xa7\x20\xe8\xa4\x21\x1c\x03\xdc\xb4\xca\xe0\x27\xe0\x0d\x99\x7f\x03\xe0\xff\x4e\xf0\xe3\xbf\x28\xf8\x8f\xb8\xf4\x1f\x4b\x7e\x14\xa6\xe3\x28\x4b\xc7\x51\x39\xce\x9e\x6c\xff\x3b\x4d\x9e\x99\x5c\x10\xbc\xe9\x5e\xdf\x9d\x77\xd1\x9b\xcd\xca\x6c\x8f\xae\xaf\xf4\xb5\xa9\x56\xf6\x28\xaf\xed\x87\xa9\x7c\xfb\x5a\x9d\x7d\xae\xef\xbf\x1e\x93\x83\xef\xb8\xcf\xc6\x51\x99\x8d\xe3\xa4\x78\x76\x82\xe3\x37\x74\x2d\xae\x3f\xab\xf7\xb7\x6f\xf9\x11\x49\xcb\xf8\x66\x66\x09\xde\x6c\xce\xcf\xd6\xac\xfc\x5a\xcb\xa3\xe8\xaa\x58\xe3\xf4\xee\x66\x73\xf7\xb2\xe8\x7b\xd1\x78\x56\xf2\xe3\xbf\x41\xf3\x5f\x90\xfc\x98\xb3\x8c\xf3\xb2\x62\xc8\xeb\x38\x23\x21\x29\xb0\x8e\x39\xc6\x2c\x42\xa4\x61\x1c\x95\x45\x9d\xe5\x18\x25\x2f\x4a\x7e\x96\x12\x4c\x8a\x84\x87\x55\xce\x09\x8f\x59\x9d\xd7\x25\x49\xf3\x22\x2a\x68\x58\x57\x25\x52\x4e\xc2\x22\x63\xec\x45\xc9\xc7\x9a\xb3\x12\x13\x92\x87\x65\x98\xb1\x34\x8c\x29\xab\xc3\x3c\xa5\x75\x56\xd7\x45\xc5\xe2\x34\x2e\xa3\x88\xc5\xf4\x65\xc9\xe7\x55\x92\x54\xac\x4a\xa2\xa8\x26\x71\x59\xd2\x22\x2f\xcb\xb0\x8a\x79\x5d\xc6\x09\x2f\x63\x96\x44\x59\x9e\x72\x5e\x0f\x92\x7f\xa9\x5a\x63\xf1\x89\xe8\x33\x35\x6f\x89\xa5\x8b\x3f\x77\x2e\x4a\xfe\x22\x4d\x76\xb3\xc3\x0f\xd7\xbf\x9c\xfc\x02\x54\xa3\xd3\x7c\x3d\x84\xea\xa8\xe2\xfd\xfc\xf8\x2c\x73\xfe\xf6\xe3\xd2\xff\xef\xc0\xd4\x27\xe1\x39\xf6\x24\xff\x5b\xf2\x54\xbc\x8a\x79\x18\x92\x84\x65\x05\x2b\x78\x12\xe5\x18\x53\x12\x97\x55\x95\x33\x9e\xc5\x55\x54\x66\x21\x96\x84\xbe\x4c\x9e\x2c\xca\xc3\xa3\x28\x0e\xab\x88\xa6\xd1\x69\x71\x9c\x46\x3c\x3c\x9a\x66\x53\xac\x1c\x21\xd3\x38\xa7\x29\x99\x9e\x4e\x5f\x24\x0f\xcf\x59\x4e\x12\xe4\x55\x8c\x55\x15\x21\xe6\x75\xc1\x49\x54\xd2\xb8\x08\x63\x92\x25\x71\x1e\x96\x31\x21\xac\x7a\x99\x3c\x69\x52\x84\x59\xc6\x6a\xc6\xd3\x2c\x2e\x13\x86\x29\xc9\xb1\xc2\xb0\xaa\xab\x10\xc3\x34\x21\x69\x49\x63\x56\x47\x07\x23\x77\xd9\x24\x96\xc0\x95\x55\x9a\xcc\x71\x64\xfa\xff\xfd\x15\x72\x46\xec\xc2\xa7\xb8\x71\x37\x91\x93\x23\xe0\xa2\xc1\x91\x9b\xd4\x2e\x26\x70\x68\x97\xed\xe1\xef\x57\xd9\x7f\x31\x62\xc9\xd8\x8f\x64\xb5\xf3\x7b\xac\x24\x17\xf3\x4e\xfb\xb0\xf6\x13\x50\xdf\x7a\xf5\xe7\xa7\xe9\x1d\x3c\x99\x6d\x4a\xa9\xea\xa4\x35\x70\x8f\x5b\x18\x56\x31\x22\x43\xa3\x9b\xe7\x1e\xb7\xae\x19\x07\x8f\xbb\x2e\x67\xfb\x6e\x7f\x26\x58\x3b\x24\x7a\x44\x4d\x67\xef\x80\x48\x06\xb3\x78\x06\x57\xfd\x86\xee\xc8\x8f\xd2\xb1\x7b\xe4\x78\xfb\x56\x19\x2b\xc9\x12\x27\x10\xfa\xcb\x67\x38\x7a\x05\x33\xa5\xed\xe0\xc4\x39\xf8\xbe\xa1\x1b\x34\x81\x32\x2c\x63\x37\xb9\xa3\x7b\x60\x95\x3f\x13\x01\x7d\x98\x33\x33\x6a\xe3\xb6\x4f\xd1\x55\x8b\x54\xf0\x2d\x9c\x6e\xac\xdf\x7a\xe1\xdd\xec\x41\xac\xfe\xac\x40\x89\x74\x57\x79\x8d\xee\x38\xc4\x80\x58\x10\x1c\x6a\x5c\x08\xc9\xe0\x7c\x7a\xed\xdc\xe0\x60\xfd\x6e\x36\x81\xf5\x78\x33\xde\x8e\xbf\xf6\x05\x70\x51\x77\x06\xd9\x9e\x4f\x6e\xd5\x0d\xd9\xa2\x76\x65\xf0\xe1\x7a\x35\xf0\xa3\xaf\xc5\x12\x55\xe7\x97\x29\x41\xb5\x28\x87\xf7\x85\xe1\x30\xe4\xd5\xcf\x1f\xf0\x46\xb0\x6b\x1e\x4c\x26\x70\x90\x84\xc6\x83\xee\xa2\xc3\x0e\xbf\x59\xae\x9f\x9d\x98\xad\xa4\x0b\xad\xa4\xea\x8c\x13\x54\x8a\xc6\x08\x39\x1f\x7d\x71\x06\x7d\x32\xfa\xd7\x11\xd3\x2f\xbd\x5b\xd6\xa8\x9d\x24\x3b\xe9\x40\x6d\x0e\xa9\x92\xc6\xa9\xfc\x20\xcf\x6b\x77\x29\xad\xfd\x69\x4f\x51\x62\xfb\xcc\x18\x4b\xb4\xed\xda\x11\x38\xfb\xdb\xde\x70\x02\xfd\xf2\x5e\x6b\x44\x03\x5d\x0b\xc7\xb3\x1b\xa0\x5b\xda\xa0\xe9\x97\xda\x4f\xe0\x0e\xf2\x6b\x22\xfc\xa3\x8a\x8b\x17\x57\xe8\x50\x04\x43\xf7\x2d\x11\x7e\xb5\x1f\xae\x26\x10\x8d\x86\x2d\x67\x88\x50\xa3\xd5\x02\xfd\x81\x54\xad\x87\x64\x13\xb0\xc4\xb8\x2d\xc7\xfd\xbb\xec\x07\x4c\x20\x0a\x5d\x8e\xf6\xca\x69\x7c\xf5\x05\x7d\x9c\xaf\xd1\x4e\x37\x07\x88\x60\x83\x4e\x12\xd7\x0b\x41\x17\x7b\x4d\x85\x01\xe7\xae\x28\xee\x42\x32\xec\x7a\xca\xe5\x6f\xd8\xae\x18\x88\xfe\xe4\x49\x3b\x63\xd5\x72\x98\x64\x47\xc2\xe1\xfd\x69\xa0\xd7\xb9\xc7\xfb\xc1\x92\x08\x79\xb0\x7f\x65\xf2\xfc\x1e\x1c\xef\xe7\xa5\x8d\xbb\x2b\xf4\xd0\xfc\x61\x8d\xfe\xaa\x24\x34\xc2\xda\x80\xd2\x20\x5a\x3a\x3c\x3d\x91\xba\x41\xf7\x49\xfd\x46\xd9\x67\xd3\x6d\x88\xce\xf0\xe6\xf2\x6c\x02\x0b\x6b\xdb\xc9\xe1\xa1\x3f\x9b\xbb\x03\xfd\xa4\xca\xd2\x6c\x87\x03\xff\x34\x36\x27\x6e\x2d\x82\xba\x70\xe7\xc4\xcc\xdc\xa7\xcb\xe1\xee\xef\xc9\xe0\x46\x2c\x85\xed\x07\x9f\xb9\xcf\x09\xa4\x45\x14\x27\x65\xf9\x08\xdf\x56\xf9\x42\xf7\x65\x92\xbf\xaf\xcc\x6a\x22\x0d\xd9\x1f\xfc\xdd\x1a\x18\xeb\x9f\xd2\x08\xf8\xbb\x91\x17\x8e\x7e\x29\x60\xb5\x98\xcf\x51\x23\xeb\xd9\x60\x71\x63\x77\x18\xe9\x19\x91\x87\x8e\x12\xcf\x4d\xac\x91\x30\x50\xb2\xd9\x3a\xa6\xed\x78\xb2\x7b\x4f\xdc\x85\xf4\xbb\xeb\x4b\x24\xec\xb1\xfb\x28\x1b\xbc\x9f\xbb\x4a\x3c\x8c\xbd\x55\xaa\x81\x25\xd9\xec\x71\x69\x15\x18\x94\xcc\x61\xf2\xc1\x30\xb5\xf2\x2a\xb0\x24\x9b\x3d\x3c\xe3\x21\xa7\xdf\x77\xe9\x6f\x58\x2b\xd2\x78\xbf\xdb\x9e\x3b\xc4\x05\x48\x3b\xad\xfd\x5b\xd6\x03\x8b\x05\x31\x50\x23\x4a\x60\x68\x91\x5a\x9f\xa6\x9d\x03\x37\x9f\xdb\x15\xe3\x61\x05\x27\xc2\x78\xb4\x78\x8f\x46\x2d\x9f\xa0\xcd\x00\x53\x0f\x2f\xe2\x60\x37\x3e\x22\xd2\x0a\xc7\xb0\xcd\x4c\xa9\x66\x4a\x9d\xa2\x9c\x4a\xe7\x89\x4d\xc0\xea\x0e\x1d\xd7\x88\xdc\x02\xc3\xba\x9b\xcf\x07\x35\x73\x14\xf0\xda\x31\x57\xe0\x26\x19\xf9\xde\x9e\x6a\x6d\xab\x15\xf7\xe5\xd9\x9b\x38\x9d\x74\xad\x13\xe0\xa4\x31\x38\x1a\xf5\xbb\xfb\xf0\x74\xda\x6a\xa4\x6a\xe9\x91\xe6\x27\xfc\x77\x00\x00\x00\xff\xff\xf3\x86\xba\x5a\x2f\x16\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x5b\x73\xdb\x36\x94\x7e\xd7\xaf\x38\xe3\xbc\xb4\x33\x4b\x19\x04\xaf\xd2\x4c\x67\x47\xbe\xe4\xd2\x38\xae\x7c\x49\xdd\xf8\x65\x03\x02\x87\x12\x62\x0a\x60\x00\x50\x97\xfc\xfa\x1d\x80\x94\x6b\xc7\xb1\xbb\xdb\x4e\x77\xfd\x62\x0a\xc0\xb9\x7f\xe7\xc3\xe5\x15\x9c\x60\xcd\xba\xc6\x81\xc0\x35\x36\xba\x5d\xa1\x72\xe0\xd0\x3a\x85\x0e\xd8\x82\x49\x65\x1d\x18\xa9\xee\xb0\xda\x8d\x38\x2a\x67\x64\xdd\x2d\xf0\x1c\xdd\x46\x9b\xbb\x29\x98\xce\x5a\xc9\xd4\x52\x36\xcd\x28\x28\x93\x0a\xc1\x2d\x11\xc4\xa0\x57\xf5\x2b\x2d\xb8\x25\x73\x70\x7c\xaf\x01\x56\x4c\x2a\xe7\xf5\x8f\xf6\x4b\xa6\x23\x80\x57\x70\xa6\x39\x6b\x82\x0b\x52\x2d\x80\x6b\xe5\x0c\xe3\x0e\x98\x10\x06\xad\x45\x0b\x0a\x51\x80\xd3\x50\x21\x58\x74\xb0\x91\x6e\x09\xa8\xd6\xb0\x66\x46\xb2\xaa\x41\x3b\x1e\xc1\x5e\xde\xab\x04\x90\x62\x0a\x49\x92\x84\x6f\x74\x4b\x34\xd8\xad\x86\x08\xde\x89\x29\x94\x49\xd9\xcf\x55\x5a\x3b\xeb\x0c\x6b\xe7\x88\xc6\xf6\xb2\x11\x1c\x1c\xca\x36\x3d\x8c\x69\x31\x26\x63\x32\x8e\x0f\x1d\x6f\x0f\x93\x92\x12\x7a\x28\xdb\xda\x1e\x5e\xac\xae\x2f\xb6\xd5\xe6\xae\xbb\xfd\xf4\xe9\xa4\xee\xbe\x5d\x57\xdb\xd3\xd9\x25\x5e\x9f\x1f\x9f\xe9\x6f\xbb\x5d\x96\x95\xeb\x0b\xb5\xf8\x7d\x3d\xff\xf0\xe5\xec\xd3\xdd\xc1\x5f\x28\x4d\xf6\x4a\x7f\xaf\xf3\xd3\xf3\x7c\x75\xf7\xf5\x06\xbf\xdc\xbc\xbf\xa1\x5f\xe7\x5d\x9c\xff\xd1\x8a\x37\xc9\xdd\xaf\x3a\xbe\x4e\x56\x4b\xb6\x9c\x1f\x65\x57\x98\xa9\xb8\x57\xba\x4f\xd5\x6c\x9f\xa9\x3e\x00\x1f\x3e\x2a\x27\xdd\xee\x35\xe3\x4e\x9b\xdd\x14\x0e\x0e\xbe\x9b\xb9\xc4\x85\xb4\xee\xd1\x14\x53\x7c\xa9\xcd\x25\xb6\xda\xca\xef\xa4\x5a\xb6\xf3\x30\xf9\xad\x6a\xe4\x82\x39\xa9\x55\x98\x0b\xc5\xfb\xc0\xa4\xfa\x21\x94\x86\x1a\xc3\x4f\x97\x3d\x96\x7e\x1e\xc1\x43\xec\xf4\xae\xbe\x82\xf3\x6e\x85\x46\x72\x78\x77\x02\xba\x0e\x38\x7a\x80\x98\x41\xc7\x7d\x49\xb3\x78\x90\x3a\xda\xd7\x0d\x1a\x69\x9d\x97\x54\x5a\xe0\x53\xc8\xb5\x46\xaf\x65\x98\xd0\x41\xf7\x03\x07\xf6\x8e\xfe\x25\x0e\x92\x6c\x4c\x69\x36\xa6\x84\x8c\x53\xfa\x3d\x16\x62\x7a\x92\xbc\xd7\xfa\xe6\x4c\x4a\x7e\xf1\xfb\xe6\x7a\x79\x7d\xf4\x29\xdf\xbe\xe7\x73\x7d\x56\xe7\x97\x17\x9f\x7e\x7d\xdd\x6e\xea\xd8\x14\xd9\xe6\x6c\x4b\x6f\x2f\x93\xf6\x58\xc4\x07\x3f\x52\x5f\xe6\x63\x1a\x93\xe7\xd4\x5f\xdc\x7e\x98\x95\x6f\xe6\x6f\xcd\xfa\xf4\xf6\x68\xb2\x11\x77\xfa\x23\x9f\xcd\x56\xc7\xb7\x6f\xdb\x09\xee\x76\xb7\xe9\xd5\x69\xb9\x78\x6d\x92\xe5\xf5\xf9\x1f\x07\x43\x8e\x4e\x07\xdc\xdf\x57\xe2\xdd\x09\x44\x30\x54\xe3\xb9\xce\x48\x07\xe1\x33\xe6\xd3\x03\x02\xdb\x46\xef\x50\xc0\xd5\x8a\x19\x07\xc7\x03\xe0\x2c\xd4\xda\x84\x84\x2e\xe4\x1a\xd5\xa3\x54\x3e\x05\x25\x3c\x8b\x4a\xb2\x8d\x2b\x92\x91\xb4\xc0\x32\x8e\x4b\x96\x0b\x56\xa7\x69\x5a\x53\x9a\x66\x79\x4e\xea\x4c\x24\x75\x9a\x53\xc2\x26\xe2\x05\xfc\x92\xed\x24\xcf\x09\x27\xc9\x44\x24\x71\x9c\x66\x09\xab\x89\xc8\x4a\x9e\xe5\x79\x5e\xd0\x44\x4c\x38\xad\x59\x21\x72\xe4\x2f\x20\x9d\x6c\x71\x52\x56\x84\xe7\x42\x4c\x08\xcd\x8b\x34\xa9\x8b\x24\xcf\x0b\xac\x59\x5d\xb2\x49\x46\x04\x11\x65\x9d\x4e\x04\x7d\xa9\x27\xc8\xb6\xe2\x31\xc3\x82\xd6\x55\x95\x33\x4a\x4a\x9a\xd5\x59\x9c\xe4\x9c\x57\x8c\x60\x99\x88\xbc\x2a\xb1\x28\x53\x1f\x4f\xe8\x9e\xf7\x7a\xcd\xfa\xf4\x3d\xc0\x7a\x85\x46\xb1\x66\x89\x72\xb1\x74\x03\x16\x5f\xbd\x7a\x35\x14\xa6\x97\x78\x3d\xbb\x18\x7e\x47\x70\xe3\xe9\x50\xaa\xba\x33\x0c\x76\xba\x83\x85\xe7\x71\x05\x68\x8c\x36\x1e\x65\xd7\x4b\x69\xc1\xe0\xd7\xce\x5b\x91\x16\x94\x76\x60\xbb\xb6\xd5\xc6\xa1\x80\x0a\x39\xeb\x2c\x7a\x49\x13\x9a\xc8\x2f\x31\x9d\x52\x9e\x8b\x03\xd3\x5a\xc7\x9c\xef\xa4\xce\x0f\x8d\xe1\xb2\x53\xfd\x78\x14\x0d\x63\xbf\x30\xc3\x97\x72\x8d\xe3\x83\xff\x18\x9c\x02\xd8\xf8\x46\x74\x1a\x84\xfe\xcf\x20\xc1\xa0\x09\x2c\xdf\x32\x23\xdd\xae\x37\x14\xb4\xdc\x85\x78\x70\x31\xed\x7f\x7e\x1e\x16\x44\x11\x5f\x32\xa9\x7e\xe9\xa7\xa3\xc8\x7b\xfb\x4b\x42\x12\x92\x42\x14\x6d\x98\x69\x87\x7f\x51\xc5\x8c\x91\x68\x20\xcb\x4b\x42\x08\x81\x28\x52\x3a\x62\x8a\x4b\x54\x2e\xaa\x1a\xcd\xef\x6c\x3f\x66\xd1\xac\x31\x6a\x7c\x52\x21\x8a\x56\x6c\x1b\xb5\xbe\xd7\x81\x66\x5e\xc8\x2a\xd6\xda\xa5\x76\xc3\x60\x18\x5b\x49\xf5\xe8\xa7\xf7\x99\x71\x27\xd7\x08\x51\xe4\x31\xee\x53\xa4\xeb\xfa\x69\x26\x20\x8a\x44\x15\x71\xbd\x6a\xfd\x7a\xad\xc0\x5a\xe1\x43\x62\x7c\x89\x91\x95\xdf\x10\x52\x32\xc9\x21\x8a\xbe\x58\xad\x4c\xcb\xa3\xa5\xb6\xce\x02\x6b\x9a\x07\x63\x52\x39\x34\x35\xe3\xe8\xc7\x3f\x3f\x2e\xf7\xd3\x64\xfe\xa8\xf2\x47\x3e\x7c\x14\xbe\x25\x15\xf6\x8e\x38\x0d\x37\x58\x5d\xf9\x71\x67\x21\xe4\xc4\x40\x6d\xf4\x0a\x3a\xe5\x4c\x67\x3d\x24\xb4\x91\x0b\xa9\xa6\x30\x1e\x1f\x3c\x5b\x4f\xdf\xfb\x4f\x6a\xf9\x39\x8a\x3a\x65\x59\x8d\x11\x6e\x5b\x6d\xf1\x33\xd4\x0d\x5b\x7c\x07\xe0\xff\x1d\xe1\xd3\x7f\x48\xf8\x8f\x7a\xe9\x7f\x4c\xf9\x31\x49\xc7\x71\x96\x8e\xe3\x72\x9c\x3d\xd9\xfe\xf7\x9c\x3c\xb7\xb9\x64\xf8\xb1\x7b\x7d\x7b\xde\xc5\x6f\xb6\x6b\xbb\x3b\xba\xbe\x32\xd7\x76\xb2\x76\x47\x79\xe5\x3e\xcc\xd4\xdb\xd7\xfa\xec\x4b\x75\xf7\xed\x98\x1d\xfc\x40\x7d\x36\x8e\xcb\x6c\x4c\x93\xe2\x59\x03\xc7\x6f\xf8\x46\x5e\x7f\xd1\xef\x6f\xde\xd6\x47\x2c\x2d\xe9\xc7\xb9\x63\xf8\x71\x7b\x7e\xb6\x11\xe5\xb7\x4a\x1d\xc5\x57\xc5\x06\x67\xb7\x1f\xb7\xb7\x2f\x93\x7e\x20\x8d\x67\x29\x9f\xfe\x0b\x9c\xff\x02\xe5\x4f\xf2\x3c\xce\x4b\x12\x97\x98\x12\x9e\xc6\x65\x91\x8a\x32\xe7\x28\xea\x8a\x97\x04\x31\xaf\xaa\x92\x65\x45\x9e\xbe\x48\xf9\x59\xca\x30\x29\x92\x9a\x4c\xf2\x9a\xd5\x54\x54\x79\x55\xb2\x34\x2f\xe2\x82\x93\x6a\x52\x22\xaf\x19\x29\x32\x21\x5e\xa4\xfc\xba\x28\xe2\x98\x08\x91\x23\x2d\x2b\xca\x59\x91\xc5\x49\x41\x58\x5e\x97\x94\x60\x45\x8b\x22\x15\x55\x52\xc6\xe4\x65\xca\xa7\x45\x11\xd3\x09\x47\x5a\x57\x05\x25\x05\x27\x35\xc1\x94\xe5\x44\x50\x41\xaa\xac\x2e\xbd\x2b\x55\x55\x55\x03\xe5\x5f\xea\xd6\x3a\x7c\x42\xfa\x42\x2f\x5a\xe6\xf8\xf2\xef\x9d\x8b\x92\x7f\xd8\x26\x7b\xeb\xf0\xd3\xf5\x6f\x27\xbf\x01\x37\xe8\x39\xdf\x0c\xae\xfa\x56\x09\x7a\x7e\x7e\xb6\x73\xfe\xf5\xe3\xd2\xff\xdf\x81\xa9\x4f\xc2\x73\xdd\x93\xfc\xdf\x36\x4f\xc9\xb2\x94\xa7\x85\xc8\xf3\x8c\xc6\x98\xd7\x82\x8b\x3a\x89\x79\x4a\x63\x24\x79\x4c\xe3\x2c\x15\x75\x99\xe6\xd5\xcb\xcd\x93\xc5\x39\x39\x8a\x29\x99\xc4\x3c\x8d\x4f\x8b\xe3\x34\xae\xc9\xd1\x2c\x9b\xe1\x84\x66\x8c\xa4\x34\xe7\x29\x9b\x9d\xce\x5e\x6e\x9e\x9c\xd2\x22\x2d\x0b\x12\xf3\x98\x66\x28\x28\x4d\x62\xce\xeb\xa4\xe6\x75\x55\x30\x5a\x91\xb8\x66\x65\x92\x65\x2f\x37\x8f\x10\x69\xc1\x90\x15\x69\xc1\x29\x25\xa9\xa0\x69\x4a\xfc\x89\x29\x41\x4c\x49\xc5\x69\x95\xd1\x8a\x4f\x44\x7d\x30\xf2\x97\x4d\xe6\x18\x5c\x39\x6d\xd8\x02\x47\xb6\xff\xdf\x5f\x21\xe7\xcc\x2d\x43\x8a\x1b\x7f\x13\x39\x39\x82\x5a\x36\x38\xf2\x46\xdd\x72\x0a\x87\x6e\xd5\x1e\xfe\x79\x95\xfd\x2f\xc1\x1c\x1b\x87\x95\xa2\xf2\x7a\x8f\xb5\xaa\xe5\xa2\x33\xc1\xad\x7b\x03\x3c\x8c\x5e\xfd\x7d\x33\xbd\x82\x27\xd6\x66\x9c\xeb\x4e\x39\x0b\x77\xb8\x83\x21\x8a\x11\x1b\x06\xbd\x9d\x3b\xdc\xf9\x61\x1c\x34\xee\xa7\xbc\xec\xbb\xfb\x33\xc1\xc6\x23\x31\x20\x6a\x36\x7f\x07\x4c\x09\x98\xd3\x39\x5c\xf5\x1b\xba\x6f\x7e\x54\xbe\xbb\x47\xbe\x6f\xdf\x6a\xeb\x14\x5b\xe1\x14\x48\xb8\x7c\x92\xd1\x2b\x98\x6b\xe3\x06\x25\x5e\xc1\x8f\x05\xfd\xa2\x29\x94\xa4\xa4\xde\xb8\x6f\xf7\xc8\xe9\x70\x26\x02\xfe\x30\x67\x76\xd4\xd2\xb6\x4f\xd1\x55\x8b\x5c\xd6\x3b\x38\xdd\xba\xb0\xf5\xc2\xbb\xf9\x03\x5f\xc3\x59\x81\x33\xe5\xaf\xf2\x06\xfd\x71\x48\x00\x73\x20\x6b\xa8\x70\x29\x95\x80\xf3\xd9\xb5\x57\x83\x83\xf4\xbb\xf9\x14\x36\xe3\xed\x78\x37\xfe\xd6\x17\xc0\x7b\xdd\x59\x14\xf7\xfd\xe4\xa3\x6e\xd8\x0e\x8d\x2f\x43\x70\x37\xb0\x41\x58\x7d\x2d\x57\xa8\xbb\x10\xa6\x02\xdd\xa2\x1a\xde\x17\x86\xc3\x50\x60\xbf\x70\xc0\x1b\xc1\x7e\x78\x10\x99\xc2\x41\x42\x6c\x00\xdd\x45\x87\x1d\x7e\x17\x6e\xb0\xce\xec\x4e\xf1\xa5\xd1\x4a\x77\xd6\x13\x2a\x47\x6b\xa5\x5a\x8c\xbe\x7a\x81\x3e\x19\xfd\xeb\x88\xed\x43\xef\x56\x15\x1a\x4f\xc9\x9e\x3a\xd0\xd8\x43\xae\x95\xf5\x2c\x3f\xd0\xf3\xc6\x5f\x4a\xab\x70\xda\xd3\x9c\xb9\x3e\x33\xd6\x31\xe3\xba\x76\x04\x5e\xfe\xa6\x17\x9c\x42\x1f\xde\x6b\x83\x68\xa1\x6b\xe1\x78\xfe\x11\xf8\x8e\x37\x68\xfb\x50\x7b\x03\xfe\x20\xbf\x61\x32\x3c\xaa\x78\x7f\x71\x8d\x1e\x45\x30\x4c\xdf\x30\x19\xa2\xfd\x70\x35\x85\x78\x34\x6c\x39\x83\x87\x06\x9d\x91\x18\x0e\xa4\x7a\x33\x24\x9b\x81\x63\xd6\x6f\x39\xfe\xdf\x65\xbf\x60\x0a\x31\xf1\x39\xba\x67\x4e\x1b\xaa\x2f\xf9\xe3\x7c\x8d\xf6\xbc\x39\x40\x04\x1b\xf4\x94\xb8\x59\x4a\xbe\xbc\xe7\x54\x18\x70\xee\x8b\xe2\x2f\x24\xc3\xae\xa7\x7d\xfe\x86\xed\x4a\x80\xec\x4f\x9e\xbc\xb3\x4e\xaf\x06\x23\xfb\x26\x1c\xde\x9f\x86\xf6\x3a\x0f\x78\x3f\x58\x31\xa9\x0e\xee\x5f\x99\x42\x7f\x0f\x8a\xef\xed\xf2\xc6\xdf\x15\x7a\x68\xfe\xb4\xc1\x70\x55\x92\x06\x61\x63\x41\x1b\x90\x2d\x1f\x9e\x9e\x58\xd5\xa0\xff\xe4\x61\xa3\xec\xb3\xe9\x37\x44\x2f\xf8\xf1\xf2\x6c\x0a\x4b\xe7\xda\xe9\xe1\x61\x38\x9b\xfb\x03\xfd\x74\x92\xa5\xd9\x1e\x07\xe1\x69\x6c\xc1\x7c\x2c\x92\x7b\x77\x17\xcc\xce\xfd\xa7\xcf\xe1\xfe\xef\xc9\xe2\x46\xae\xa4\xeb\x17\x9f\xf9\xcf\x29\xa4\x45\x4c\x93\xb2\x7c\x84\x6f\xa7\x43\xa1\xfb\x32\xa9\x3f\x23\x73\x86\x29\xcb\xee\x0f\xfe\x3e\x06\x21\xfa\xa7\x34\x06\xe1\x6e\x14\x88\xa3\x0f\x05\x9c\x91\x8b\x05\x1a\x14\x7d\x37\x38\xdc\xba\x3d\x46\xfa\x8e\xc8\x89\x6f\x89\xe7\x0c\x1b\x64\x02\xb4\x6a\x76\xbe\xd3\xf6\x7d\xb2\x7f\x4f\xdc\xbb\xf4\xa7\xea\x4b\x64\xe2\xb1\xfa\x38\x1b\xb4\x9f\xfb\x4a\x3c\xf4\xbd\xd5\xba\x81\x15\xdb\xde\xe3\xd2\x69\xb0\xa8\x84\xc7\xe4\x83\x65\x7a\x1d\x58\x60\xc5\xb6\xf7\xf0\xa4\x43\x4e\x7f\xac\x32\xdc\xb0\xd6\xac\x09\x7a\x77\x7d\xef\x30\xef\x20\xef\x8c\x09\x6f\x59\x0f\x24\x96\xcc\x42\x85\xa8\x40\xa0\x43\xee\x42\x9a\xf6\x0a\xbc\x3d\xbf\x2b\xd2\x21\x82\x13\x69\x03\x5a\x82\x46\xab\x57\x4f\xd0\x66\x41\xe8\x87\x17\x71\x70\xdb\xe0\x11\x6b\xa5\xef\xb0\xed\x5c\xeb\x66\xc6\x3d\xa3\x9c\x2a\xaf\x49\x4c\xc1\x99\x0e\x7d\xaf\x31\xb5\x03\x81\x55\xb7\x58\x0c\x6c\xe6\x5b\x20\x70\xc7\x42\x83\x37\x32\x0a\xb3\x7d\xab\xb5\xad\xd1\x75\x28\xcf\xbd\x88\xe7\x49\x3f\x3a\x85\x9a\x35\x16\x47\xa3\x7e\x77\x1f\x9e\x4e\x5b\x83\x5c\xaf\x02\xd2\x82\xc1\xff\x0e\x00\x00\xff\xff\x78\x36\xb5\xe4\x2f\x16\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5679, mode: os.FileMode(420), modTime: time.Unix(1551789277, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5679, mode: os.FileMode(420), modTime: time.Unix(1551869118, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1076, mode: os.FileMode(420), modTime: time.Unix(1551798935, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1076, mode: os.FileMode(420), modTime: time.Unix(1551869111, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From 1ab9a2d5a930786dbbfbdd7a31ce5633e820047a Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 6 Mar 2019 14:37:48 +0100 Subject: [PATCH 218/220] Feat(documents): add getChangedField for write_acls (#815) Closes #801 --- Gopkg.lock | 4 +- Gopkg.toml | 2 +- documents/coredocument.go | 1 + documents/coredocument_test.go | 7 + documents/error.go | 29 ---- documents/write_acls.go | 86 +++++++++++ documents/write_acls_test.go | 266 +++++++++++++++++++++++++++++++++ 7 files changed, 363 insertions(+), 32 deletions(-) create mode 100644 documents/write_acls.go create mode 100644 documents/write_acls_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 5faba6bd7..c41c62af7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -64,7 +64,7 @@ revision = "d269f08e89bd195f158787d2ea59274810abc943" [[projects]] - digest = "1:d356ff1419f848de543d6b2f6d95a9a2a38e5f630465c41e043704157aa9cdf3" + digest = "1:ed633c35a4197b4727799d73af6b13acc8c3a560b63cb9210c671b4af921a4d2" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "b5992325667104a35db388db0ef0cbf4b0c2bf03" + revision = "9c4069c8f8eca7c0b0a021e71241aa43f44f9bbc" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index 30944682e..eb7012e15 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,7 +28,7 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "b5992325667104a35db388db0ef0cbf4b0c2bf03" + revision = "9c4069c8f8eca7c0b0a021e71241aa43f44f9bbc" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" diff --git a/documents/coredocument.go b/documents/coredocument.go index 0dc6f9d91..1c2b38dd8 100644 --- a/documents/coredocument.go +++ b/documents/coredocument.go @@ -180,6 +180,7 @@ func (cd *CoreDocument) PrepareNewVersion(collaborators []string, initSalts bool ReadRules: cd.Document.ReadRules, TransitionRules: cd.Document.TransitionRules, Nfts: cd.Document.Nfts, + AccessTokens: cd.Document.AccessTokens, } err = populateVersions(&cdp, &cd.Document) diff --git a/documents/coredocument_test.go b/documents/coredocument_test.go index 4f89eff1d..a2f3c81e3 100644 --- a/documents/coredocument_test.go +++ b/documents/coredocument_test.go @@ -162,6 +162,13 @@ func TestCoreDocument_PrepareNewVersion(t *testing.T) { assert.Equal(t, cd.Document.CurrentVersion, ncd.Document.PreviousVersion) assert.Equal(t, cd.Document.DocumentIdentifier, ncd.Document.DocumentIdentifier) assert.Equal(t, cd.Document.DocumentRoot, ncd.Document.PreviousRoot) + assert.Len(t, cd.Document.Roles, 0) + assert.Len(t, cd.Document.ReadRules, 0) + assert.Len(t, ncd.Document.Roles, 1) + assert.Len(t, ncd.Document.ReadRules, 1) + assert.Len(t, ncd.Document.Roles[0].Collaborators, 2) + assert.Equal(t, ncd.Document.Roles[0].Collaborators[0], c1[:]) + assert.Equal(t, ncd.Document.Roles[0].Collaborators[1], c2[:]) } func TestGetSigningProofHashes(t *testing.T) { diff --git a/documents/error.go b/documents/error.go index c011f1a2a..ad51e7d95 100644 --- a/documents/error.go +++ b/documents/error.go @@ -35,50 +35,21 @@ const ( // ErrDocumentPersistence must be used when creating or updating a document in the system database failed ErrDocumentPersistence = errors.Error("error encountered when storing document in the system database") - // ErrDocumentPackingCoreDocument must be used when packing of core document for the given document failed - ErrDocumentPackingCoreDocument = errors.Error("core document packing failed") - // ErrDocumentUnPackingCoreDocument must be used when unpacking of core document for the given document failed ErrDocumentUnPackingCoreDocument = errors.Error("core document unpacking failed") // ErrDocumentPrepareCoreDocument must be used when preparing a new core document fails for the given document ErrDocumentPrepareCoreDocument = errors.Error("core document preparation failed") - // ErrDocumentSigning must be used when document signing related functionality fails - ErrDocumentSigning = errors.Error("document signing failed") - // ErrDocumentAnchoring must be used when document anchoring fails ErrDocumentAnchoring = errors.Error("document anchoring failed") - // ErrDocumentCollaborator must be used when there is an error in processing collaborators - ErrDocumentCollaborator = errors.Error("document collaborator issue") - // ErrDocumentProof must be used when document proof creation fails ErrDocumentProof = errors.Error("document proof error") // ErrDataRootInvalid must be used when the data root is invalid ErrDataRootInvalid = errors.Error("data root is invalid") - // Document repository errors - - // ErrDocumentRepositoryModelNotRegistered must be used when the model hasn't been registered in the database repository - ErrDocumentRepositoryModelNotRegistered = errors.Error("document model hasn't been registered in the database repository") - - // ErrDocumentRepositorySerialisation must be used when document repository encounters a marshalling error - ErrDocumentRepositorySerialisation = errors.Error("document repository encountered a marshalling error") - - // ErrDocumentRepositoryModelNotFound must be used when document repository can not locate the given model - ErrDocumentRepositoryModelNotFound = errors.Error("document repository could not locate the given model") - - // ErrDocumentRepositoryModelSave must be used when document repository can not save the given model - ErrDocumentRepositoryModelSave = errors.Error("document repository could not save the given model") - - // ErrDocumentRepositoryModelAllReadyExists must be used when document repository finds an already existing model when saving - ErrDocumentRepositoryModelAllReadyExists = errors.Error("document repository found an already existing model when saving") - - // ErrDocumentRepositoryModelDoesntExist must be used when document repository does not find an existing model for an update - ErrDocumentRepositoryModelDoesntExist = errors.Error("document repository did not find an existing model for an update") - // Read ACL errors // ErrNftNotFound must be used when the NFT is not found in the document diff --git a/documents/write_acls.go b/documents/write_acls.go new file mode 100644 index 000000000..6e8cfbb1b --- /dev/null +++ b/documents/write_acls.go @@ -0,0 +1,86 @@ +package documents + +import ( + "bytes" + + "github.com/centrifuge/precise-proofs/proofs" +) + +// changedField holds the compact property, old and new value of the field that is changed +// if the old is nil, then it is a set operation +// if new is nil, then it is an unset operation +// if both old and new are set, then it is an edit operation +type changedField struct { + property, old, new []byte +} + +// getChangedFields takes two document trees and returns the compact value, old and new value of the fields that are changed in new tree. +// Properties may have been added to the new tree or removed from the new tree. +// In Either case, since the new tree is different from old, that is considered a change. +func getChangedFields(oldTree, newTree *proofs.DocumentTree, lengthSuffix string) (changedFields []changedField) { + oldProps := oldTree.PropertyOrder() + newProps := newTree.PropertyOrder() + + props := make(map[string]proofs.Property) + for _, p := range append(oldProps, newProps...) { + // we can ignore the length property since any change in slice or map will return in addition or deletion of properties in the new tree + if p.Text == lengthSuffix { + continue + } + + if _, ok := props[p.ReadableName()]; ok { + continue + } + + props[p.ReadableName()] = p + } + + // check each property and append it changed fields if the value is different. + for k, p := range props { + _, ol := oldTree.GetLeafByProperty(k) + _, nl := newTree.GetLeafByProperty(k) + + if ol == nil { + changedFields = append(changedFields, newChangedField(p, nl, false)) + continue + } + + if nl == nil { + changedFields = append(changedFields, newChangedField(p, ol, true)) + continue + } + + ov := ol.Value + nv := nl.Value + if ol.Hashed { + ov = ol.Hash + nv = nl.Hash + } + + if !bytes.Equal(ov, nv) { + changedFields = append(changedFields, changedField{ + property: p.CompactName(), + old: ov, + new: nv, + }) + } + } + + return changedFields +} + +func newChangedField(p proofs.Property, leaf *proofs.LeafNode, old bool) changedField { + v := leaf.Value + if leaf.Hashed { + v = leaf.Hash + } + + cf := changedField{property: p.CompactName()} + if old { + cf.old = v + return cf + } + + cf.new = v + return cf +} diff --git a/documents/write_acls_test.go b/documents/write_acls_test.go new file mode 100644 index 000000000..92bc4edd5 --- /dev/null +++ b/documents/write_acls_test.go @@ -0,0 +1,266 @@ +// +build unit + +package documents + +import ( + "crypto/sha256" + "fmt" + "reflect" + "testing" + "time" + + "github.com/centrifuge/centrifuge-protobufs/gen/go/invoice" + "github.com/centrifuge/go-centrifuge/testingutils/identity" + "github.com/centrifuge/go-centrifuge/utils" + "github.com/centrifuge/precise-proofs/proofs" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/stretchr/testify/assert" +) + +func TestWriteACLs_getChangedFields_different_types(t *testing.T) { + cd, err := newCoreDocument() + assert.NoError(t, err) + ocd := cd.Document + ncd := invoicepb.InvoiceData{ + Currency: "EUR", + } + + oldTree := getTree(t, &ocd) + newTree := getTree(t, &ncd) + + cf := getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + // cf length should be len(ocd) and len(ncd) = 30 changed field + assert.Len(t, cf, 30) + +} + +func TestWriteACLs_getChangedFields_same_document(t *testing.T) { + cd, err := newCoreDocument() + assert.NoError(t, err) + ocd := cd.Document + oldTree := getTree(t, &ocd) + newTree := getTree(t, &ocd) + cf := getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 0) + + // check hashed field + ocd.PreviousRoot = utils.RandomSlice(32) + oldTree = getTree(t, &ocd) + newTree = getTree(t, &ocd) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 0) +} + +func testExpectedProps(t *testing.T, cf []changedField, eprops map[string]struct{}) { + for _, f := range cf { + _, ok := eprops[hexutil.Encode(f.property)] + if !ok { + assert.Failf(t, "", "expected %x property to be present", f.property) + } + } +} + +func TestWriteACLs_getChangedFields_with_core_document(t *testing.T) { + doc, err := newCoreDocument() + assert.NoError(t, err) + doc.Document.DocumentRoot = utils.RandomSlice(32) + ndoc, err := doc.PrepareNewVersion([]string{testingidentity.GenerateRandomDID().String()}, true) + assert.NoError(t, err) + + // preparing new version would have changed the following properties + // current_version + // previous_version + // next_version + // previous_root + // roles + // current pre image + // next pre image + // read_rules.roles + // read_rules.action + oldTree := getTree(t, &doc.Document) + newTree := getTree(t, &ndoc.Document) + cf := getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 9) + rprop := append(ndoc.Document.Roles[0].RoleKey, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0) + eprops := map[string]struct{}{ + hexutil.Encode([]byte{0, 0, 0, 4}): {}, + hexutil.Encode([]byte{0, 0, 0, 3}): {}, + hexutil.Encode([]byte{0, 0, 0, 16}): {}, + hexutil.Encode([]byte{0, 0, 0, 2}): {}, + hexutil.Encode([]byte{0, 0, 0, 22}): {}, + hexutil.Encode([]byte{0, 0, 0, 23}): {}, + hexutil.Encode([]byte{0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}): {}, + hexutil.Encode([]byte{0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}): {}, + hexutil.Encode(append([]byte{0, 0, 0, 1}, rprop...)): {}, + } + + testExpectedProps(t, cf, eprops) + + // prepare new version with out new collaborators + // this should only change + // current_version + // previous_version + // next_version + // previous_root + doc = ndoc + doc.Document.DocumentRoot = utils.RandomSlice(32) + ndoc, err = doc.PrepareNewVersion(nil, true) + assert.NoError(t, err) + oldTree = getTree(t, &doc.Document) + newTree = getTree(t, &ndoc.Document) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 6) + eprops = map[string]struct{}{ + hexutil.Encode([]byte{0, 0, 0, 4}): {}, + hexutil.Encode([]byte{0, 0, 0, 3}): {}, + hexutil.Encode([]byte{0, 0, 0, 16}): {}, + hexutil.Encode([]byte{0, 0, 0, 2}): {}, + hexutil.Encode([]byte{0, 0, 0, 22}): {}, + hexutil.Encode([]byte{0, 0, 0, 23}): {}, + } + testExpectedProps(t, cf, eprops) + + // test with different document + // this will change + // document identifier + // current version + // previous version + // next version + // previous_root + // roles (new doc will have empty role while old one has one role) + // read_rules (new doc will have empty read_rules while old one has read_rules) + doc = ndoc + ndoc, err = newCoreDocument() + assert.NoError(t, err) + oldTree = getTree(t, &doc.Document) + newTree = getTree(t, &ndoc.Document) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 10) + rprop = append(doc.Document.Roles[0].RoleKey, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0) + eprops = map[string]struct{}{ + hexutil.Encode([]byte{0, 0, 0, 9}): {}, + hexutil.Encode([]byte{0, 0, 0, 4}): {}, + hexutil.Encode([]byte{0, 0, 0, 3}): {}, + hexutil.Encode([]byte{0, 0, 0, 16}): {}, + hexutil.Encode([]byte{0, 0, 0, 2}): {}, + hexutil.Encode([]byte{0, 0, 0, 22}): {}, + hexutil.Encode([]byte{0, 0, 0, 23}): {}, + hexutil.Encode([]byte{0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}): {}, + hexutil.Encode([]byte{0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}): {}, + hexutil.Encode(append([]byte{0, 0, 0, 1}, rprop...)): {}, + } + testExpectedProps(t, cf, eprops) + + // add different roles and read rules and check + ndoc.Document.DocumentRoot = utils.RandomSlice(32) + ndoc, err = ndoc.PrepareNewVersion([]string{testingidentity.GenerateRandomDID().String()}, true) + assert.NoError(t, err) + oldTree = getTree(t, &doc.Document) + newTree = getTree(t, &ndoc.Document) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 10) + fmt.Println(cf) + rprop = append(ndoc.Document.Roles[0].RoleKey, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0) + rprop2 := append(doc.Document.Roles[0].RoleKey, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0) + eprops = map[string]struct{}{ + hexutil.Encode([]byte{0, 0, 0, 9}): {}, + hexutil.Encode([]byte{0, 0, 0, 4}): {}, + hexutil.Encode([]byte{0, 0, 0, 3}): {}, + hexutil.Encode([]byte{0, 0, 0, 16}): {}, + hexutil.Encode([]byte{0, 0, 0, 2}): {}, + hexutil.Encode([]byte{0, 0, 0, 22}): {}, + hexutil.Encode([]byte{0, 0, 0, 23}): {}, + hexutil.Encode([]byte{0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0}): {}, + hexutil.Encode(append([]byte{0, 0, 0, 1}, rprop...)): {}, + hexutil.Encode(append([]byte{0, 0, 0, 1}, rprop2...)): {}, + } + testExpectedProps(t, cf, eprops) +} + +func TestWriteACLs_getChangedFields_invoice_document(t *testing.T) { + dueDate, err := ptypes.TimestampProto(time.Now().Add(10 * time.Minute)) + assert.NoError(t, err) + + // no change + doc := &invoicepb.InvoiceData{ + InvoiceNumber: "12345", + SenderName: "Alice", + RecipientName: "Bob", + DateCreated: ptypes.TimestampNow(), + DueDate: dueDate, + } + + oldTree := getTree(t, doc) + newTree := getTree(t, doc) + cf := getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 0) + + // updated doc + ndoc := &invoicepb.InvoiceData{ + InvoiceNumber: "123456", // updated + SenderName: doc.SenderName, + RecipientName: doc.RecipientName, + DateCreated: doc.DateCreated, + DueDate: doc.DueDate, + Currency: "EUR", // new field + } + + oldTree = getTree(t, doc) + newTree = getTree(t, ndoc) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 2) + eprops := map[string]changedField{ + hexutil.Encode([]byte{0, 0, 0, 1}): { + property: []byte{0, 0, 0, 1}, + old: []byte{49, 50, 51, 52, 53}, + new: []byte{49, 50, 51, 52, 53, 54}, + }, + + hexutil.Encode([]byte{0, 0, 0, 13}): { + property: []byte{0, 0, 0, 13}, + old: []byte{}, + new: []byte{69, 85, 82}, + }, + } + + for _, f := range cf { + ef, ok := eprops[hexutil.Encode(f.property)] + if !ok { + t.Fatalf("expected %x property change", f.property) + } + + assert.True(t, reflect.DeepEqual(f, ef)) + } + + // completely new doc + // this should give 5 property changes + ndoc = new(invoicepb.InvoiceData) + oldTree = getTree(t, doc) + newTree = getTree(t, ndoc) + cf = getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) + assert.Len(t, cf, 5) + eprps := map[string]struct{}{ + hexutil.Encode([]byte{0, 0, 0, 1}): {}, + hexutil.Encode([]byte{0, 0, 0, 3}): {}, + hexutil.Encode([]byte{0, 0, 0, 8}): {}, + hexutil.Encode([]byte{0, 0, 0, 23}): {}, + hexutil.Encode([]byte{0, 0, 0, 22}): {}, + } + testExpectedProps(t, cf, eprps) +} + +func getTree(t *testing.T, doc proto.Message) *proofs.DocumentTree { + tr := proofs.NewDocumentTree(proofs.TreeOptions{ + CompactProperties: true, + EnableHashSorting: true, + SaltsLengthSuffix: proofs.DefaultSaltsLengthSuffix, + Hash: sha256.New(), + }) + + tree := &tr + assert.NoError(t, tree.AddLeavesFromDocument(doc)) + assert.NoError(t, tree.Generate()) + return tree +} From 2191fbf01cae728f8dc86ebc8d07ed658fee31bd Mon Sep 17 00:00:00 2001 From: Miguel Hervas Date: Thu, 7 Mar 2019 14:21:43 +0100 Subject: [PATCH 219/220] Latest nft (#823) * Adapt purposes + remove ethauth * comments * wip action key * remove IDConfig * fix unit * fixes * fixes * add abigen to makefile * merge * nft changes * latest contracts * fix tests --- Gopkg.lock | 8 +- Gopkg.toml | 4 +- Makefile | 18 ++ anchors/anchor_contract.go | 32 +-- build/configs/default_config.yaml | 22 +- documents/invoice/model.go | 5 + documents/write_acls_test.go | 4 +- identity/ideth/factory_contract.go | 56 +++-- identity/ideth/identity_contract.go | 64 +++--- nft/ethereum_payment_obligation.go | 50 +---- nft/ethereum_payment_obligation_contract.go | 232 ++++++++++---------- nft/ethereum_payment_obligation_test.go | 4 +- nft/payment_obligation_integration_test.go | 6 +- resources/data.go | 8 +- testworld/nft_test.go | 2 +- testworld/payloads.go | 2 + 16 files changed, 270 insertions(+), 247 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c41c62af7..d55c31101 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,14 +57,14 @@ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f" [[projects]] - digest = "1:36cbc3e655bd69044d0486115b9e7747db4ae15f0a6e03d851c4bf1408d83ac7" + digest = "1:ead823956932d64e6271256398aa0753b03d4a6dec8f522847841ca33b98f289" name = "github.com/centrifuge/centrifuge-ethereum-contracts" packages = ["."] pruneopts = "T" - revision = "d269f08e89bd195f158787d2ea59274810abc943" + revision = "be1a93f627115fcf9978a85c4b6b8f08adf87f35" [[projects]] - digest = "1:ed633c35a4197b4727799d73af6b13acc8c3a560b63cb9210c671b4af921a4d2" + digest = "1:8e4b7179dfb51d02daeb1c3ee4bb816243837b74a6c1bd663a803776c43b8eaf" name = "github.com/centrifuge/centrifuge-protobufs" packages = [ "documenttypes", @@ -76,7 +76,7 @@ "gen/go/purchaseorder", ] pruneopts = "T" - revision = "9c4069c8f8eca7c0b0a021e71241aa43f44f9bbc" + revision = "20c7fd5e4210e68d2a5662a8714d51ceeae031b8" [[projects]] digest = "1:6c7200e9917373ebe3c248ca47f9ee8a7924aa003c137cbfee2c763d7bc0643f" diff --git a/Gopkg.toml b/Gopkg.toml index eb7012e15..563e9a89d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,11 +28,11 @@ required = ["github.com/centrifuge/centrifuge-ethereum-contracts", "github.com/r [[constraint]] name = "github.com/centrifuge/centrifuge-protobufs" - revision = "9c4069c8f8eca7c0b0a021e71241aa43f44f9bbc" + revision = "20c7fd5e4210e68d2a5662a8714d51ceeae031b8" [[override]] name = "github.com/centrifuge/centrifuge-ethereum-contracts" - revision = "d269f08e89bd195f158787d2ea59274810abc943" + revision = "be1a93f627115fcf9978a85c4b6b8f08adf87f35" [[constraint]] name = "github.com/Masterminds/semver" diff --git a/Makefile b/Makefile index bc7538f69..4464e7d33 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,24 @@ vendorinstall: ## Installs all protobuf dependencies with go-vendorinstall go-vendorinstall golang.org/x/tools/cmd/goimports go get -u github.com/jteeuwen/go-bindata/... +abigen-install: ## Installs ABIGEN from vendor +abigen-install: vendorinstall + go-vendorinstall github.com/ethereum/go-ethereum/cmd/abigen + +gen-abi-bindings: ## Generates GO ABI Bindings +gen-abi-bindings: install-deps abigen-install + $(eval CONTRACTS_VERSION := $(shell cat vendor/github.com/centrifuge/centrifuge-ethereum-contracts/package.json | jq -r '.version')) + npm install --prefix tmp/contracts @centrifuge/ethereum-contracts@${CONTRACTS_VERSION} + @cat tmp/contracts/node_modules/\@centrifuge/ethereum-contracts/build/contracts/Identity.json | jq '.abi' > tmp/contracts/id.abi + @cat tmp/contracts/node_modules/\@centrifuge/ethereum-contracts/build/contracts/AnchorRepository.json | jq '.abi' > tmp/contracts/ar.abi + @cat tmp/contracts/node_modules/\@centrifuge/ethereum-contracts/build/contracts/PaymentObligation.json | jq '.abi' > tmp/contracts/po.abi + @cat tmp/contracts/node_modules/\@centrifuge/ethereum-contracts/build/contracts/IdentityFactory.json | jq '.abi' > tmp/contracts/idf.abi + @abigen --abi tmp/contracts/id.abi --pkg ideth --type IdentityContract --out ${GOPATH}/src/github.com/centrifuge/go-centrifuge/identity/ideth/identity_contract.go + @abigen --abi tmp/contracts/ar.abi --pkg anchors --type AnchorContract --out ${GOPATH}/src/github.com/centrifuge/go-centrifuge/anchors/anchor_contract.go + @abigen --abi tmp/contracts/po.abi --pkg nft --type EthereumPaymentObligationContract --out ${GOPATH}/src/github.com/centrifuge/go-centrifuge/nft/ethereum_payment_obligation_contract.go + @abigen --abi tmp/contracts/idf.abi --pkg ideth --type FactoryContract --out ${GOPATH}/src/github.com/centrifuge/go-centrifuge/identity/ideth/factory_contract.go + @rm -Rf ./tmp + install: ## Builds and Install binary for development install: install-deps vendorinstall @go install ./cmd/centrifuge/... diff --git a/anchors/anchor_contract.go b/anchors/anchor_contract.go index 138e7a2f8..4eb11a880 100644 --- a/anchors/anchor_contract.go +++ b/anchors/anchor_contract.go @@ -174,7 +174,7 @@ func (_AnchorContract *AnchorContractTransactorRaw) Transact(opts *bind.Transact // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +// Solidity: function getAnchorById(id uint256) constant returns(anchorId uint256, documentRoot bytes32) func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte @@ -190,7 +190,7 @@ func (_AnchorContract *AnchorContractCaller) GetAnchorById(opts *bind.CallOpts, // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +// Solidity: function getAnchorById(id uint256) constant returns(anchorId uint256, documentRoot bytes32) func (_AnchorContract *AnchorContractSession) GetAnchorById(id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte @@ -200,7 +200,7 @@ func (_AnchorContract *AnchorContractSession) GetAnchorById(id *big.Int) (struct // GetAnchorById is a free data retrieval call binding the contract method 0x32bf361b. // -// Solidity: function getAnchorById(uint256 id) constant returns(uint256 anchorId, bytes32 documentRoot) +// Solidity: function getAnchorById(id uint256) constant returns(anchorId uint256, documentRoot bytes32) func (_AnchorContract *AnchorContractCallerSession) GetAnchorById(id *big.Int) (struct { AnchorId *big.Int DocumentRoot [32]byte @@ -210,7 +210,7 @@ func (_AnchorContract *AnchorContractCallerSession) GetAnchorById(id *big.Int) ( // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +// Solidity: function hasValidPreCommit(anchorId uint256) constant returns(valid bool) func (_AnchorContract *AnchorContractCaller) HasValidPreCommit(opts *bind.CallOpts, anchorId *big.Int) (bool, error) { var ( ret0 = new(bool) @@ -222,56 +222,56 @@ func (_AnchorContract *AnchorContractCaller) HasValidPreCommit(opts *bind.CallOp // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +// Solidity: function hasValidPreCommit(anchorId uint256) constant returns(valid bool) func (_AnchorContract *AnchorContractSession) HasValidPreCommit(anchorId *big.Int) (bool, error) { return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, anchorId) } // HasValidPreCommit is a free data retrieval call binding the contract method 0xb5c7d034. // -// Solidity: function hasValidPreCommit(uint256 anchorId) constant returns(bool valid) +// Solidity: function hasValidPreCommit(anchorId uint256) constant returns(valid bool) func (_AnchorContract *AnchorContractCallerSession) HasValidPreCommit(anchorId *big.Int) (bool, error) { return _AnchorContract.Contract.HasValidPreCommit(&_AnchorContract.CallOpts, anchorId) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +// Solidity: function commit(anchorIdPreImage uint256, documentRoot bytes32, documentProofs bytes32[]) returns() func (_AnchorContract *AnchorContractTransactor) Commit(opts *bind.TransactOpts, anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { return _AnchorContract.contract.Transact(opts, "commit", anchorIdPreImage, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +// Solidity: function commit(anchorIdPreImage uint256, documentRoot bytes32, documentProofs bytes32[]) returns() func (_AnchorContract *AnchorContractSession) Commit(anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorIdPreImage, documentRoot, documentProofs) } // Commit is a paid mutator transaction binding the contract method 0x58522947. // -// Solidity: function commit(uint256 anchorIdPreImage, bytes32 documentRoot, bytes32[] documentProofs) returns() +// Solidity: function commit(anchorIdPreImage uint256, documentRoot bytes32, documentProofs bytes32[]) returns() func (_AnchorContract *AnchorContractTransactorSession) Commit(anchorIdPreImage *big.Int, documentRoot [32]byte, documentProofs [][32]byte) (*types.Transaction, error) { return _AnchorContract.Contract.Commit(&_AnchorContract.TransactOpts, anchorIdPreImage, documentRoot, documentProofs) } // PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +// Solidity: function preCommit(anchorId uint256, signingRoot bytes32) returns() func (_AnchorContract *AnchorContractTransactor) PreCommit(opts *bind.TransactOpts, anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { return _AnchorContract.contract.Transact(opts, "preCommit", anchorId, signingRoot) } // PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +// Solidity: function preCommit(anchorId uint256, signingRoot bytes32) returns() func (_AnchorContract *AnchorContractSession) PreCommit(anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, anchorId, signingRoot) } // PreCommit is a paid mutator transaction binding the contract method 0x53b36015. // -// Solidity: function preCommit(uint256 anchorId, bytes32 signingRoot) returns() +// Solidity: function preCommit(anchorId uint256, signingRoot bytes32) returns() func (_AnchorContract *AnchorContractTransactorSession) PreCommit(anchorId *big.Int, signingRoot [32]byte) (*types.Transaction, error) { return _AnchorContract.Contract.PreCommit(&_AnchorContract.TransactOpts, anchorId, signingRoot) } @@ -354,7 +354,7 @@ type AnchorContractAnchorCommitted struct { // FilterAnchorCommitted is a free log retrieval operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. // -// Solidity: event AnchorCommitted(address indexed from, uint256 indexed anchorId, bytes32 documentRoot, uint32 blockHeight) +// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) func (_AnchorContract *AnchorContractFilterer) FilterAnchorCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorCommittedIterator, error) { var fromRule []interface{} @@ -375,7 +375,7 @@ func (_AnchorContract *AnchorContractFilterer) FilterAnchorCommitted(opts *bind. // WatchAnchorCommitted is a free log subscription operation binding the contract event 0xd1eb81d62e07e99a310f0f4c9a107a644e475be1f4b7eaa3d5c731c140195ee9. // -// Solidity: event AnchorCommitted(address indexed from, uint256 indexed anchorId, bytes32 documentRoot, uint32 blockHeight) +// Solidity: e AnchorCommitted(from indexed address, anchorId indexed uint256, documentRoot bytes32, blockHeight uint32) func (_AnchorContract *AnchorContractFilterer) WatchAnchorCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { var fromRule []interface{} @@ -496,7 +496,7 @@ type AnchorContractAnchorPreCommitted struct { // FilterAnchorPreCommitted is a free log retrieval operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. // -// Solidity: event AnchorPreCommitted(address indexed from, uint256 indexed anchorId, uint32 blockHeight) +// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) func (_AnchorContract *AnchorContractFilterer) FilterAnchorPreCommitted(opts *bind.FilterOpts, from []common.Address, anchorId []*big.Int) (*AnchorContractAnchorPreCommittedIterator, error) { var fromRule []interface{} @@ -517,7 +517,7 @@ func (_AnchorContract *AnchorContractFilterer) FilterAnchorPreCommitted(opts *bi // WatchAnchorPreCommitted is a free log subscription operation binding the contract event 0xaa2928be4e330731bc1f0289edebfc72ccb9979ffc703a3de4edd8ea760462da. // -// Solidity: event AnchorPreCommitted(address indexed from, uint256 indexed anchorId, uint32 blockHeight) +// Solidity: e AnchorPreCommitted(from indexed address, anchorId indexed uint256, blockHeight uint32) func (_AnchorContract *AnchorContractFilterer) WatchAnchorPreCommitted(opts *bind.WatchOpts, sink chan<- *AnchorContractAnchorPreCommitted, from []common.Address, anchorId []*big.Int) (event.Subscription, error) { var fromRule []interface{} diff --git a/build/configs/default_config.yaml b/build/configs/default_config.yaml index 7054913bf..0b69e1698 100644 --- a/build/configs/default_config.yaml +++ b/build/configs/default_config.yaml @@ -11,7 +11,6 @@ networks: - "/ip4/127.0.0.1/tcp/38203/ipfs/QmVf6EN6mkqWejWKW2qPu16XpdG3kJo1T3mhahPB5Se5n1" contractAddresses: identityFactory: "" - identityRegistry: "" anchorRepository: "" paymentObligation: "" @@ -27,10 +26,9 @@ networks: ethereumNetworkId: 4 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x1b05047e8118a6daf444f2245660f5d3f4620a9d" - identityRegistry: "0x9660c039d311453af0d58c5666723d9c2fa7d6ec" - anchorRepository: "0xe98b0c6dd9026743f73667efaf8a950d0d8f49d2" - paymentObligation: "0xbc1ae72fbb6a20825f5136ccba0e83d6b8e7849d" + identityFactory: "0xffe0612006eedaeda188cd9df54574a68920a97d" + anchorRepository: "0xd3be7846016367a08ad083b06df98ad78212d0a5" + paymentObligation: "0x2d5b6470af1ac962c55b6bee92f3c38c609f371e" # Kovan test network bernalheights: @@ -51,10 +49,9 @@ networks: ethereumNetworkId: 42 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x966168018e40c41874d86cedfbc80ee6bb8a5764" - identityRegistry: "0x54ae373f096faf2db6b8a46717c0b98ecfa075dd" - anchorRepository: "0xf77110dd6e28b2ca751370a6f820eb2774db3810" - paymentObligation: "0x277129ce2fb7207c0f0e4a60d2d0b5f8cfa0bbbb" + identityFactory: "0x01adb663afd3a5d7655c89d2774cef51800f3bb6" + anchorRepository: "0x16f45eac73752eab73072fddbacbd0a58adc3a40" + paymentObligation: "0xeb1c6a36c4b1234aaae7ece88fb4f48d23d63146" # Ropsten test network dogpatch: @@ -68,10 +65,9 @@ networks: ethereumNetworkId: 3 # Latest deployed Smart Contracts for the given testnet contractAddresses: - identityFactory: "0x8a54c47d66521e6fdcdf31c421e0612154df846b" - identityRegistry: "0x55160B12091c41E7C41f0BA5Ae925a0426c4aAEA" - anchorRepository: "0xf622748701c125ed2231ccf3fcfb7a2b01fa8355" - paymentObligation: "0xdd47aea747c2204d244051363ee40bc2b52bc9df" + identityFactory: "0x1ba18b61337fa121339339b554730c0e70b9a81c" + anchorRepository: "0xff5f35f6f3910ed66a24b6e55542e66b868416a3" + paymentObligation: "0x48c25e7639e888e667f20d30b96653de054251d8" # Data Storage storage: diff --git a/documents/invoice/model.go b/documents/invoice/model.go index a228f226a..a094dfe77 100644 --- a/documents/invoice/model.go +++ b/documents/invoice/model.go @@ -30,6 +30,7 @@ type Invoice struct { *documents.CoreDocument InvoiceNumber string // invoice number or reference number + InvoiceStatus string // invoice status SenderName string // name of the sender company SenderStreet string // street and address details of the sender company SenderCity string @@ -80,6 +81,7 @@ func (i *Invoice) getClientData() *clientinvoicepb.InvoiceData { return &clientinvoicepb.InvoiceData{ InvoiceNumber: i.InvoiceNumber, + InvoiceStatus: i.InvoiceStatus, SenderName: i.SenderName, SenderStreet: i.SenderStreet, SenderCity: i.SenderCity, @@ -123,6 +125,7 @@ func (i *Invoice) createP2PProtobuf() *invoicepb.InvoiceData { return &invoicepb.InvoiceData{ InvoiceNumber: i.InvoiceNumber, + InvoiceStatus: i.InvoiceStatus, SenderName: i.SenderName, SenderStreet: i.SenderStreet, SenderCity: i.SenderCity, @@ -169,6 +172,7 @@ func (i *Invoice) InitInvoiceInput(payload *clientinvoicepb.InvoiceCreatePayload // initInvoiceFromData initialises invoice from invoiceData func (i *Invoice) initInvoiceFromData(data *clientinvoicepb.InvoiceData) error { i.InvoiceNumber = data.InvoiceNumber + i.InvoiceStatus = data.InvoiceStatus i.SenderName = data.SenderName i.SenderStreet = data.SenderStreet i.SenderCity = data.SenderCity @@ -221,6 +225,7 @@ func (i *Invoice) initInvoiceFromData(data *clientinvoicepb.InvoiceData) error { // loadFromP2PProtobuf loads the invoice from centrifuge protobuf invoice data func (i *Invoice) loadFromP2PProtobuf(invoiceData *invoicepb.InvoiceData) { i.InvoiceNumber = invoiceData.InvoiceNumber + i.InvoiceStatus = invoiceData.InvoiceStatus i.SenderName = invoiceData.SenderName i.SenderStreet = invoiceData.SenderStreet i.SenderCity = invoiceData.SenderCity diff --git a/documents/write_acls_test.go b/documents/write_acls_test.go index 92bc4edd5..19dd848d4 100644 --- a/documents/write_acls_test.go +++ b/documents/write_acls_test.go @@ -31,8 +31,8 @@ func TestWriteACLs_getChangedFields_different_types(t *testing.T) { newTree := getTree(t, &ncd) cf := getChangedFields(oldTree, newTree, proofs.DefaultSaltsLengthSuffix) - // cf length should be len(ocd) and len(ncd) = 30 changed field - assert.Len(t, cf, 30) + // cf length should be len(ocd) and len(ncd) = 31 changed field + assert.Len(t, cf, 31) } diff --git a/identity/ideth/factory_contract.go b/identity/ideth/factory_contract.go index ee6b62a5b..2b0992cbd 100644 --- a/identity/ideth/factory_contract.go +++ b/identity/ideth/factory_contract.go @@ -28,7 +28,7 @@ var ( ) // FactoryContractABI is the input ABI used to generate the binding from. -const FactoryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"createIdentityFor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" +const FactoryContractABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"identity\",\"type\":\"address\"}],\"name\":\"IdentityCreated\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[],\"name\":\"createIdentity\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"manager\",\"type\":\"address\"},{\"name\":\"keys\",\"type\":\"bytes32[]\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"}],\"name\":\"createIdentityFor\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"identityAddr\",\"type\":\"address\"}],\"name\":\"createdIdentity\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // FactoryContract is an auto generated Go binding around an Ethereum contract. type FactoryContract struct { @@ -172,6 +172,32 @@ func (_FactoryContract *FactoryContractTransactorRaw) Transact(opts *bind.Transa return _FactoryContract.Contract.contract.Transact(opts, method, params...) } +// CreatedIdentity is a free data retrieval call binding the contract method 0xfc252feb. +// +// Solidity: function createdIdentity(identityAddr address) constant returns(valid bool) +func (_FactoryContract *FactoryContractCaller) CreatedIdentity(opts *bind.CallOpts, identityAddr common.Address) (bool, error) { + var ( + ret0 = new(bool) + ) + out := ret0 + err := _FactoryContract.contract.Call(opts, out, "createdIdentity", identityAddr) + return *ret0, err +} + +// CreatedIdentity is a free data retrieval call binding the contract method 0xfc252feb. +// +// Solidity: function createdIdentity(identityAddr address) constant returns(valid bool) +func (_FactoryContract *FactoryContractSession) CreatedIdentity(identityAddr common.Address) (bool, error) { + return _FactoryContract.Contract.CreatedIdentity(&_FactoryContract.CallOpts, identityAddr) +} + +// CreatedIdentity is a free data retrieval call binding the contract method 0xfc252feb. +// +// Solidity: function createdIdentity(identityAddr address) constant returns(valid bool) +func (_FactoryContract *FactoryContractCallerSession) CreatedIdentity(identityAddr common.Address) (bool, error) { + return _FactoryContract.Contract.CreatedIdentity(&_FactoryContract.CallOpts, identityAddr) +} + // CreateIdentity is a paid mutator transaction binding the contract method 0x59d21ad9. // // Solidity: function createIdentity() returns() @@ -193,25 +219,25 @@ func (_FactoryContract *FactoryContractTransactorSession) CreateIdentity() (*typ return _FactoryContract.Contract.CreateIdentity(&_FactoryContract.TransactOpts) } -// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xc4ff1c23. // -// Solidity: function createIdentityFor(address owner) returns() -func (_FactoryContract *FactoryContractTransactor) CreateIdentityFor(opts *bind.TransactOpts, owner common.Address) (*types.Transaction, error) { - return _FactoryContract.contract.Transact(opts, "createIdentityFor", owner) +// Solidity: function createIdentityFor(manager address, keys bytes32[], purposes uint256[]) returns() +func (_FactoryContract *FactoryContractTransactor) CreateIdentityFor(opts *bind.TransactOpts, manager common.Address, keys [][32]byte, purposes []*big.Int) (*types.Transaction, error) { + return _FactoryContract.contract.Transact(opts, "createIdentityFor", manager, keys, purposes) } -// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xc4ff1c23. // -// Solidity: function createIdentityFor(address owner) returns() -func (_FactoryContract *FactoryContractSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { - return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) +// Solidity: function createIdentityFor(manager address, keys bytes32[], purposes uint256[]) returns() +func (_FactoryContract *FactoryContractSession) CreateIdentityFor(manager common.Address, keys [][32]byte, purposes []*big.Int) (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, manager, keys, purposes) } -// CreateIdentityFor is a paid mutator transaction binding the contract method 0xa480f9f7. +// CreateIdentityFor is a paid mutator transaction binding the contract method 0xc4ff1c23. // -// Solidity: function createIdentityFor(address owner) returns() -func (_FactoryContract *FactoryContractTransactorSession) CreateIdentityFor(owner common.Address) (*types.Transaction, error) { - return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, owner) +// Solidity: function createIdentityFor(manager address, keys bytes32[], purposes uint256[]) returns() +func (_FactoryContract *FactoryContractTransactorSession) CreateIdentityFor(manager common.Address, keys [][32]byte, purposes []*big.Int) (*types.Transaction, error) { + return _FactoryContract.Contract.CreateIdentityFor(&_FactoryContract.TransactOpts, manager, keys, purposes) } // FactoryContractIdentityCreatedIterator is returned from FilterIdentityCreated and is used to iterate over the raw logs and unpacked data for IdentityCreated events raised by the FactoryContract contract. @@ -289,7 +315,7 @@ type FactoryContractIdentityCreated struct { // FilterIdentityCreated is a free log retrieval operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. // -// Solidity: event IdentityCreated(address indexed identity) +// Solidity: e IdentityCreated(identity indexed address) func (_FactoryContract *FactoryContractFilterer) FilterIdentityCreated(opts *bind.FilterOpts, identity []common.Address) (*FactoryContractIdentityCreatedIterator, error) { var identityRule []interface{} @@ -306,7 +332,7 @@ func (_FactoryContract *FactoryContractFilterer) FilterIdentityCreated(opts *bin // WatchIdentityCreated is a free log subscription operation binding the contract event 0xac993fde3b9423ff59e4a23cded8e89074c9c8740920d1d870f586ba7c5c8cf0. // -// Solidity: event IdentityCreated(address indexed identity) +// Solidity: e IdentityCreated(identity indexed address) func (_FactoryContract *FactoryContractFilterer) WatchIdentityCreated(opts *bind.WatchOpts, sink chan<- *FactoryContractIdentityCreated, identity []common.Address) (event.Subscription, error) { var identityRule []interface{} diff --git a/identity/ideth/identity_contract.go b/identity/ideth/identity_contract.go index 02a6c5cb3..fd54ad483 100644 --- a/identity/ideth/identity_contract.go +++ b/identity/ideth/identity_contract.go @@ -28,7 +28,7 @@ var ( ) // IdentityContractABI is the input ABI used to generate the binding from. -const IdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressToKey\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"},{\"name\":\"result\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"message\",\"type\":\"bytes32\"},{\"name\":\"signature\",\"type\":\"bytes\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"isSignedWithPurpose\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" +const IdentityContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"getKey\",\"outputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"revokedAt\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addMultiPurposeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"},{\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"addKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"}],\"name\":\"revokeKey\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressToKey\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"getKeysByPurpose\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"keyHasPurpose\",\"outputs\":[{\"name\":\"found\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"managementAddress\",\"type\":\"address\"},{\"name\":\"keys\",\"type\":\"bytes32[]\"},{\"name\":\"purposes\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"purpose\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"key\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"revokedAt\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"keyType\",\"type\":\"uint256\"}],\"name\":\"KeyRevoked\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"},{\"name\":\"result\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"message\",\"type\":\"bytes32\"},{\"name\":\"signature\",\"type\":\"bytes\"},{\"name\":\"purpose\",\"type\":\"uint256\"}],\"name\":\"isSignedWithPurpose\",\"outputs\":[{\"name\":\"valid\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]" // IdentityContract is an auto generated Go binding around an Ethereum contract. type IdentityContract struct { @@ -174,7 +174,7 @@ func (_IdentityContract *IdentityContractTransactorRaw) Transact(opts *bind.Tran // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(address addr) constant returns(bytes32) +// Solidity: function addressToKey(addr address) constant returns(bytes32) func (_IdentityContract *IdentityContractCaller) AddressToKey(opts *bind.CallOpts, addr common.Address) ([32]byte, error) { var ( ret0 = new([32]byte) @@ -186,21 +186,21 @@ func (_IdentityContract *IdentityContractCaller) AddressToKey(opts *bind.CallOpt // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(address addr) constant returns(bytes32) +// Solidity: function addressToKey(addr address) constant returns(bytes32) func (_IdentityContract *IdentityContractSession) AddressToKey(addr common.Address) ([32]byte, error) { return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) } // AddressToKey is a free data retrieval call binding the contract method 0x574363c8. // -// Solidity: function addressToKey(address addr) constant returns(bytes32) +// Solidity: function addressToKey(addr address) constant returns(bytes32) func (_IdentityContract *IdentityContractCallerSession) AddressToKey(addr common.Address) ([32]byte, error) { return _IdentityContract.Contract.AddressToKey(&_IdentityContract.CallOpts, addr) } // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +// Solidity: function getKey(keyHash bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int @@ -218,7 +218,7 @@ func (_IdentityContract *IdentityContractCaller) GetKey(opts *bind.CallOpts, key // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +// Solidity: function getKey(keyHash bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) func (_IdentityContract *IdentityContractSession) GetKey(keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int @@ -229,7 +229,7 @@ func (_IdentityContract *IdentityContractSession) GetKey(keyHash [32]byte) (stru // GetKey is a free data retrieval call binding the contract method 0x12aaac70. // -// Solidity: function getKey(bytes32 keyHash) constant returns(bytes32 key, uint256[] purposes, uint256 revokedAt) +// Solidity: function getKey(keyHash bytes32) constant returns(key bytes32, purposes uint256[], revokedAt uint256) func (_IdentityContract *IdentityContractCallerSession) GetKey(keyHash [32]byte) (struct { Key [32]byte Purposes []*big.Int @@ -240,7 +240,7 @@ func (_IdentityContract *IdentityContractCallerSession) GetKey(keyHash [32]byte) // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +// Solidity: function getKeysByPurpose(purpose uint256) constant returns(bytes32[]) func (_IdentityContract *IdentityContractCaller) GetKeysByPurpose(opts *bind.CallOpts, purpose *big.Int) ([][32]byte, error) { var ( ret0 = new([][32]byte) @@ -252,21 +252,21 @@ func (_IdentityContract *IdentityContractCaller) GetKeysByPurpose(opts *bind.Cal // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +// Solidity: function getKeysByPurpose(purpose uint256) constant returns(bytes32[]) func (_IdentityContract *IdentityContractSession) GetKeysByPurpose(purpose *big.Int) ([][32]byte, error) { return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, purpose) } // GetKeysByPurpose is a free data retrieval call binding the contract method 0x9010f726. // -// Solidity: function getKeysByPurpose(uint256 purpose) constant returns(bytes32[]) +// Solidity: function getKeysByPurpose(purpose uint256) constant returns(bytes32[]) func (_IdentityContract *IdentityContractCallerSession) GetKeysByPurpose(purpose *big.Int) ([][32]byte, error) { return _IdentityContract.Contract.GetKeysByPurpose(&_IdentityContract.CallOpts, purpose) } // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +// Solidity: function isSignedWithPurpose(message bytes32, signature bytes, purpose uint256) constant returns(valid bool) func (_IdentityContract *IdentityContractCaller) IsSignedWithPurpose(opts *bind.CallOpts, message [32]byte, signature []byte, purpose *big.Int) (bool, error) { var ( ret0 = new(bool) @@ -278,21 +278,21 @@ func (_IdentityContract *IdentityContractCaller) IsSignedWithPurpose(opts *bind. // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +// Solidity: function isSignedWithPurpose(message bytes32, signature bytes, purpose uint256) constant returns(valid bool) func (_IdentityContract *IdentityContractSession) IsSignedWithPurpose(message [32]byte, signature []byte, purpose *big.Int) (bool, error) { return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, message, signature, purpose) } // IsSignedWithPurpose is a free data retrieval call binding the contract method 0x8699fd2b. // -// Solidity: function isSignedWithPurpose(bytes32 message, bytes signature, uint256 purpose) constant returns(bool valid) +// Solidity: function isSignedWithPurpose(message bytes32, signature bytes, purpose uint256) constant returns(valid bool) func (_IdentityContract *IdentityContractCallerSession) IsSignedWithPurpose(message [32]byte, signature []byte, purpose *big.Int) (bool, error) { return _IdentityContract.Contract.IsSignedWithPurpose(&_IdentityContract.CallOpts, message, signature, purpose) } // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +// Solidity: function keyHasPurpose(key bytes32, purpose uint256) constant returns(found bool) func (_IdentityContract *IdentityContractCaller) KeyHasPurpose(opts *bind.CallOpts, key [32]byte, purpose *big.Int) (bool, error) { var ( ret0 = new(bool) @@ -304,98 +304,98 @@ func (_IdentityContract *IdentityContractCaller) KeyHasPurpose(opts *bind.CallOp // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +// Solidity: function keyHasPurpose(key bytes32, purpose uint256) constant returns(found bool) func (_IdentityContract *IdentityContractSession) KeyHasPurpose(key [32]byte, purpose *big.Int) (bool, error) { return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, key, purpose) } // KeyHasPurpose is a free data retrieval call binding the contract method 0xd202158d. // -// Solidity: function keyHasPurpose(bytes32 key, uint256 purpose) constant returns(bool found) +// Solidity: function keyHasPurpose(key bytes32, purpose uint256) constant returns(found bool) func (_IdentityContract *IdentityContractCallerSession) KeyHasPurpose(key [32]byte, purpose *big.Int) (bool, error) { return _IdentityContract.Contract.KeyHasPurpose(&_IdentityContract.CallOpts, key, purpose) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +// Solidity: function addKey(key bytes32, purpose uint256, keyType uint256) returns() func (_IdentityContract *IdentityContractTransactor) AddKey(opts *bind.TransactOpts, key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.contract.Transact(opts, "addKey", key, purpose, keyType) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +// Solidity: function addKey(key bytes32, purpose uint256, keyType uint256) returns() func (_IdentityContract *IdentityContractSession) AddKey(key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, key, purpose, keyType) } // AddKey is a paid mutator transaction binding the contract method 0x1d381240. // -// Solidity: function addKey(bytes32 key, uint256 purpose, uint256 keyType) returns() +// Solidity: function addKey(key bytes32, purpose uint256, keyType uint256) returns() func (_IdentityContract *IdentityContractTransactorSession) AddKey(key [32]byte, purpose *big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.Contract.AddKey(&_IdentityContract.TransactOpts, key, purpose, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +// Solidity: function addMultiPurposeKey(key bytes32, purposes uint256[], keyType uint256) returns() func (_IdentityContract *IdentityContractTransactor) AddMultiPurposeKey(opts *bind.TransactOpts, key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.contract.Transact(opts, "addMultiPurposeKey", key, purposes, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +// Solidity: function addMultiPurposeKey(key bytes32, purposes uint256[], keyType uint256) returns() func (_IdentityContract *IdentityContractSession) AddMultiPurposeKey(key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, key, purposes, keyType) } // AddMultiPurposeKey is a paid mutator transaction binding the contract method 0x173d2616. // -// Solidity: function addMultiPurposeKey(bytes32 key, uint256[] purposes, uint256 keyType) returns() +// Solidity: function addMultiPurposeKey(key bytes32, purposes uint256[], keyType uint256) returns() func (_IdentityContract *IdentityContractTransactorSession) AddMultiPurposeKey(key [32]byte, purposes []*big.Int, keyType *big.Int) (*types.Transaction, error) { return _IdentityContract.Contract.AddMultiPurposeKey(&_IdentityContract.TransactOpts, key, purposes, keyType) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +// Solidity: function execute(to address, value uint256, data bytes) returns(success bool, result bytes) func (_IdentityContract *IdentityContractTransactor) Execute(opts *bind.TransactOpts, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { return _IdentityContract.contract.Transact(opts, "execute", to, value, data) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +// Solidity: function execute(to address, value uint256, data bytes) returns(success bool, result bytes) func (_IdentityContract *IdentityContractSession) Execute(to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, to, value, data) } // Execute is a paid mutator transaction binding the contract method 0xb61d27f6. // -// Solidity: function execute(address to, uint256 value, bytes data) returns(bool success, bytes result) +// Solidity: function execute(to address, value uint256, data bytes) returns(success bool, result bytes) func (_IdentityContract *IdentityContractTransactorSession) Execute(to common.Address, value *big.Int, data []byte) (*types.Transaction, error) { return _IdentityContract.Contract.Execute(&_IdentityContract.TransactOpts, to, value, data) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(bytes32 key) returns() +// Solidity: function revokeKey(key bytes32) returns() func (_IdentityContract *IdentityContractTransactor) RevokeKey(opts *bind.TransactOpts, key [32]byte) (*types.Transaction, error) { return _IdentityContract.contract.Transact(opts, "revokeKey", key) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(bytes32 key) returns() +// Solidity: function revokeKey(key bytes32) returns() func (_IdentityContract *IdentityContractSession) RevokeKey(key [32]byte) (*types.Transaction, error) { return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, key) } // RevokeKey is a paid mutator transaction binding the contract method 0x572f2210. // -// Solidity: function revokeKey(bytes32 key) returns() +// Solidity: function revokeKey(key bytes32) returns() func (_IdentityContract *IdentityContractTransactorSession) RevokeKey(key [32]byte) (*types.Transaction, error) { return _IdentityContract.Contract.RevokeKey(&_IdentityContract.TransactOpts, key) } @@ -477,7 +477,7 @@ type IdentityContractKeyAdded struct { // FilterKeyAdded is a free log retrieval operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. // -// Solidity: event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) +// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) func (_IdentityContract *IdentityContractFilterer) FilterKeyAdded(opts *bind.FilterOpts, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (*IdentityContractKeyAddedIterator, error) { var keyRule []interface{} @@ -502,7 +502,7 @@ func (_IdentityContract *IdentityContractFilterer) FilterKeyAdded(opts *bind.Fil // WatchKeyAdded is a free log subscription operation binding the contract event 0x480000bb1edad8ca1470381cc334b1917fbd51c6531f3a623ea8e0ec7e38a6e9. // -// Solidity: event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) +// Solidity: e KeyAdded(key indexed bytes32, purpose indexed uint256, keyType indexed uint256) func (_IdentityContract *IdentityContractFilterer) WatchKeyAdded(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyAdded, key [][32]byte, purpose []*big.Int, keyType []*big.Int) (event.Subscription, error) { var keyRule []interface{} @@ -627,7 +627,7 @@ type IdentityContractKeyRevoked struct { // FilterKeyRevoked is a free log retrieval operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. // -// Solidity: event KeyRevoked(bytes32 indexed key, uint256 indexed revokedAt, uint256 indexed keyType) +// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) func (_IdentityContract *IdentityContractFilterer) FilterKeyRevoked(opts *bind.FilterOpts, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (*IdentityContractKeyRevokedIterator, error) { var keyRule []interface{} @@ -652,7 +652,7 @@ func (_IdentityContract *IdentityContractFilterer) FilterKeyRevoked(opts *bind.F // WatchKeyRevoked is a free log subscription operation binding the contract event 0x8004a857c5cbc7c7c693a7c6a2852c373b5d03f882b57a8ee22dd2d4492331b1. // -// Solidity: event KeyRevoked(bytes32 indexed key, uint256 indexed revokedAt, uint256 indexed keyType) +// Solidity: e KeyRevoked(key indexed bytes32, revokedAt indexed uint256, keyType indexed uint256) func (_IdentityContract *IdentityContractFilterer) WatchKeyRevoked(opts *bind.WatchOpts, sink chan<- *IdentityContractKeyRevoked, key [][32]byte, revokedAt []*big.Int, keyType []*big.Int) (event.Subscription, error) { var keyRule []interface{} diff --git a/nft/ethereum_payment_obligation.go b/nft/ethereum_payment_obligation.go index 94755b56c..c319f635e 100644 --- a/nft/ethereum_payment_obligation.go +++ b/nft/ethereum_payment_obligation.go @@ -97,17 +97,7 @@ func (s *ethereumPaymentObligation) prepareMintRequest(ctx context.Context, toke return mreq, err } - dr, err := model.CalculateDocumentRoot() - if err != nil { - return mreq, err - } - - rootHash, err := anchors.ToDocumentRoot(dr) - if err != nil { - return mreq, err - } - - requestData, err := NewMintRequest(model, tokenID, req.DepositAddress, anchorID, nextAnchorID, docProofs.FieldProofs, rootHash) + requestData, err := NewMintRequest(tokenID, req.DepositAddress, anchorID, nextAnchorID, docProofs.FieldProofs) if err != nil { return mreq, err } @@ -204,9 +194,9 @@ func (s *ethereumPaymentObligation) minter(ctx context.Context, tokenID TokenID, return } - // to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte + // to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte ethTX, err := s.ethClient.SubmitTransactionWithRetries(contract.Mint, opts, requestData.To, requestData.TokenID, - requestData.TokenURI, requestData.AnchorID, requestData.NextAnchorID, requestData.Props, requestData.Values, + requestData.TokenURI, requestData.AnchorID, requestData.Props, requestData.Values, requestData.Salts, requestData.Proofs) if err != nil { errOut <- err @@ -287,8 +277,8 @@ type MintRequest struct { } // NewMintRequest converts the parameters and returns a struct with needed parameter for minting -func NewMintRequest(model documents.Model, tokenID TokenID, to common.Address, anchorID anchors.AnchorID, nextAnchorID anchors.AnchorID, proofs []*proofspb.Proof, rootHash [32]byte) (MintRequest, error) { - proofData, err := createProofData(model, proofs) +func NewMintRequest(tokenID TokenID, to common.Address, anchorID anchors.AnchorID, nextAnchorID anchors.AnchorID, proofs []*proofspb.Proof) (MintRequest, error) { + proofData, err := convertToProofData(proofs) if err != nil { return MintRequest{}, err } @@ -312,44 +302,28 @@ type proofData struct { Proofs [][][32]byte } -func createProofData(model documents.Model, proofspb []*proofspb.Proof) (*proofData, error) { - // TODO cleanup hard coded indexes using the model props - readRoleIndex := 5 - tokenRoleIndex := 7 - var props = make([][]byte, 2) // props are only required for readRole.property, tokenRole.property - var values = make([][]byte, 4) // values are only required for readRole.Value +func convertToProofData(proofspb []*proofspb.Proof) (*proofData, error) { + var props = make([][]byte, len(proofspb)) + var values = make([][]byte, len(proofspb)) var salts = make([][32]byte, len(proofspb)) var proofs = make([][][32]byte, len(proofspb)) // TODO remove later //proof, _ := documents.ConvertDocProofToClientFormat(&documents.DocumentProof{FieldProofs: proofspb}) //log.Info(json.MarshalIndent(proof, "", " ")) - for i, p := range proofspb { - if i == readRoleIndex { - props[0] = p.GetCompactName() - } - if i == tokenRoleIndex { - props[1] = p.GetCompactName() - } - - if i < 3 { - values[i] = p.Value - } - - if i == readRoleIndex { - values[3] = p.Value - } + for i, p := range proofspb { salt32, err := utils.SliceToByte32(p.Salt) if err != nil { return nil, err } - - salts[i] = salt32 property, err := utils.ConvertProofForEthereum(p.SortedHashes) if err != nil { return nil, err } + props[i] = p.GetCompactName() + values[i] = p.Value + salts[i] = salt32 proofs[i] = property } diff --git a/nft/ethereum_payment_obligation_contract.go b/nft/ethereum_payment_obligation_contract.go index 13f505432..f3fa56769 100644 --- a/nft/ethereum_payment_obligation_contract.go +++ b/nft/ethereum_payment_obligation_contract.go @@ -28,7 +28,7 @@ var ( ) // EthereumPaymentObligationContractABI is the input ABI used to generate the binding from. -const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"_mandatoryFields\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"anchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"bytes\"},{\"name\":\"currency\",\"type\":\"bytes\"},{\"name\":\"dueDate\",\"type\":\"bytes\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"registry\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"},{\"name\":\"registry\",\"type\":\"address\"},{\"name\":\"mandatoryFields\",\"type\":\"bytes[]\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"tokenURI\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"nextAnchorId\",\"type\":\"uint256\"},{\"name\":\"properties\",\"type\":\"bytes[]\"},{\"name\":\"values\",\"type\":\"bytes[]\"},{\"name\":\"salts\",\"type\":\"bytes32[]\"},{\"name\":\"proofs\",\"type\":\"bytes32[][]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" +const EthereumPaymentObligationContractABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getAnchorRegistry\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getIdentityFactory\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tokenURI\",\"type\":\"string\"}],\"name\":\"PaymentObligationMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getTokenDetails\",\"outputs\":[{\"name\":\"grossAmount\",\"type\":\"bytes\"},{\"name\":\"currency\",\"type\":\"bytes\"},{\"name\":\"dueDate\",\"type\":\"bytes\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"documentRoot\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"anchorRegistry\",\"type\":\"address\"},{\"name\":\"identityFactory\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\"},{\"name\":\"anchorRegistry\",\"type\":\"address\"},{\"name\":\"identityFactory\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\"},{\"name\":\"tokenURI\",\"type\":\"string\"},{\"name\":\"anchorId\",\"type\":\"uint256\"},{\"name\":\"properties\",\"type\":\"bytes[]\"},{\"name\":\"values\",\"type\":\"bytes[]\"},{\"name\":\"salts\",\"type\":\"bytes32[]\"},{\"name\":\"proofs\",\"type\":\"bytes32[][]\"}],\"name\":\"mint\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" // EthereumPaymentObligationContract is an auto generated Go binding around an Ethereum contract. type EthereumPaymentObligationContract struct { @@ -172,113 +172,113 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTrans return _EthereumPaymentObligationContract.Contract.contract.Transact(opts, method, params...) } -// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) MandatoryFields(opts *bind.CallOpts, arg0 *big.Int) ([]byte, error) { +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { var ( - ret0 = new([]byte) + ret0 = new(*big.Int) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "_mandatoryFields", arg0) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "balanceOf", owner) return *ret0, err } -// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) MandatoryFields(arg0 *big.Int) ([]byte, error) { - return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } -// MandatoryFields is a free data retrieval call binding the contract method 0x181a0bba. +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function _mandatoryFields(uint256 ) constant returns(bytes) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) MandatoryFields(arg0 *big.Int) ([]byte, error) { - return _EthereumPaymentObligationContract.Contract.MandatoryFields(&_EthereumPaymentObligationContract.CallOpts, arg0) +// Solidity: function balanceOf(owner address) constant returns(uint256) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) } -// AnchorRegistry is a free data retrieval call binding the contract method 0x5a180c0a. +// GetAnchorRegistry is a free data retrieval call binding the contract method 0x95d506fc. // -// Solidity: function anchorRegistry() constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) AnchorRegistry(opts *bind.CallOpts) (common.Address, error) { +// Solidity: function getAnchorRegistry() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetAnchorRegistry(opts *bind.CallOpts) (common.Address, error) { var ( ret0 = new(common.Address) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "anchorRegistry") + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getAnchorRegistry") return *ret0, err } -// AnchorRegistry is a free data retrieval call binding the contract method 0x5a180c0a. +// GetAnchorRegistry is a free data retrieval call binding the contract method 0x95d506fc. // -// Solidity: function anchorRegistry() constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) AnchorRegistry() (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.AnchorRegistry(&_EthereumPaymentObligationContract.CallOpts) +// Solidity: function getAnchorRegistry() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetAnchorRegistry() (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetAnchorRegistry(&_EthereumPaymentObligationContract.CallOpts) } -// AnchorRegistry is a free data retrieval call binding the contract method 0x5a180c0a. +// GetAnchorRegistry is a free data retrieval call binding the contract method 0x95d506fc. // -// Solidity: function anchorRegistry() constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) AnchorRegistry() (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.AnchorRegistry(&_EthereumPaymentObligationContract.CallOpts) +// Solidity: function getAnchorRegistry() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetAnchorRegistry() (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetAnchorRegistry(&_EthereumPaymentObligationContract.CallOpts) } -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function balanceOf(address owner) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( - ret0 = new(*big.Int) + ret0 = new(common.Address) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "balanceOf", owner) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getApproved", tokenId) return *ret0, err } -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function balanceOf(address owner) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) BalanceOf(owner common.Address) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } -// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. // -// Solidity: function balanceOf(address owner) constant returns(uint256) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) BalanceOf(owner common.Address) (*big.Int, error) { - return _EthereumPaymentObligationContract.Contract.BalanceOf(&_EthereumPaymentObligationContract.CallOpts, owner) +// Solidity: function getApproved(tokenId uint256) constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) } -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// GetIdentityFactory is a free data retrieval call binding the contract method 0xba207d9b. // -// Solidity: function getApproved(uint256 tokenId) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { +// Solidity: function getIdentityFactory() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetIdentityFactory(opts *bind.CallOpts) (common.Address, error) { var ( ret0 = new(common.Address) ) out := ret0 - err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getApproved", tokenId) + err := _EthereumPaymentObligationContract.contract.Call(opts, out, "getIdentityFactory") return *ret0, err } -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// GetIdentityFactory is a free data retrieval call binding the contract method 0xba207d9b. // -// Solidity: function getApproved(uint256 tokenId) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetApproved(tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) +// Solidity: function getIdentityFactory() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetIdentityFactory() (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetIdentityFactory(&_EthereumPaymentObligationContract.CallOpts) } -// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// GetIdentityFactory is a free data retrieval call binding the contract method 0xba207d9b. // -// Solidity: function getApproved(uint256 tokenId) constant returns(address) -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { - return _EthereumPaymentObligationContract.Contract.GetApproved(&_EthereumPaymentObligationContract.CallOpts, tokenId) +// Solidity: function getIdentityFactory() constant returns(address) +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetIdentityFactory() (common.Address, error) { + return _EthereumPaymentObligationContract.Contract.GetIdentityFactory(&_EthereumPaymentObligationContract.CallOpts) } // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +// Solidity: function getTokenDetails(tokenId uint256) constant returns(grossAmount bytes, currency bytes, dueDate bytes, anchorId uint256, documentRoot bytes32) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) GetTokenDetails(opts *bind.CallOpts, tokenId *big.Int) (struct { GrossAmount []byte Currency []byte @@ -300,7 +300,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +// Solidity: function getTokenDetails(tokenId uint256) constant returns(grossAmount bytes, currency bytes, dueDate bytes, anchorId uint256, documentRoot bytes32) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) GetTokenDetails(tokenId *big.Int) (struct { GrossAmount []byte Currency []byte @@ -313,7 +313,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSessi // GetTokenDetails is a free data retrieval call binding the contract method 0xc1e03728. // -// Solidity: function getTokenDetails(uint256 tokenId) constant returns(bytes grossAmount, bytes currency, bytes dueDate, uint256 anchorId, bytes32 documentRoot) +// Solidity: function getTokenDetails(tokenId uint256) constant returns(grossAmount bytes, currency bytes, dueDate bytes, anchorId uint256, documentRoot bytes32) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) GetTokenDetails(tokenId *big.Int) (struct { GrossAmount []byte Currency []byte @@ -326,7 +326,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { var ( ret0 = new(bool) @@ -338,14 +338,14 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) } // IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. // -// Solidity: function isApprovedForAll(address owner, address operator) constant returns(bool) +// Solidity: function isApprovedForAll(owner address, operator address) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { return _EthereumPaymentObligationContract.Contract.IsApprovedForAll(&_EthereumPaymentObligationContract.CallOpts, owner, operator) } @@ -378,7 +378,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(uint256 tokenId) constant returns(address) +// Solidity: function ownerOf(tokenId uint256) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { var ( ret0 = new(common.Address) @@ -390,21 +390,21 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(uint256 tokenId) constant returns(address) +// Solidity: function ownerOf(tokenId uint256) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) OwnerOf(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // OwnerOf is a free data retrieval call binding the contract method 0x6352211e. // -// Solidity: function ownerOf(uint256 tokenId) constant returns(address) +// Solidity: function ownerOf(tokenId uint256) constant returns(address) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { return _EthereumPaymentObligationContract.Contract.OwnerOf(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var ( ret0 = new(bool) @@ -416,14 +416,14 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) constant returns(bool) +// Solidity: function supportsInterface(interfaceId bytes4) constant returns(bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _EthereumPaymentObligationContract.Contract.SupportsInterface(&_EthereumPaymentObligationContract.CallOpts, interfaceId) } @@ -456,7 +456,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. // -// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +// Solidity: function tokenByIndex(index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenByIndex(opts *bind.CallOpts, index *big.Int) (*big.Int, error) { var ( ret0 = new(*big.Int) @@ -468,21 +468,21 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. // -// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +// Solidity: function tokenByIndex(index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenByIndex(index *big.Int) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, index) } // TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. // -// Solidity: function tokenByIndex(uint256 index) constant returns(uint256) +// Solidity: function tokenByIndex(index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenByIndex(index *big.Int) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.TokenByIndex(&_EthereumPaymentObligationContract.CallOpts, index) } // TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. // -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +// Solidity: function tokenOfOwnerByIndex(owner address, index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenOfOwnerByIndex(opts *bind.CallOpts, owner common.Address, index *big.Int) (*big.Int, error) { var ( ret0 = new(*big.Int) @@ -494,21 +494,21 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. // -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +// Solidity: function tokenOfOwnerByIndex(owner address, index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, owner, index) } // TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. // -// Solidity: function tokenOfOwnerByIndex(address owner, uint256 index) constant returns(uint256) +// Solidity: function tokenOfOwnerByIndex(owner address, index uint256) constant returns(uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenOfOwnerByIndex(owner common.Address, index *big.Int) (*big.Int, error) { return _EthereumPaymentObligationContract.Contract.TokenOfOwnerByIndex(&_EthereumPaymentObligationContract.CallOpts, owner, index) } // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(uint256 tokenId) constant returns(string) +// Solidity: function tokenURI(tokenId uint256) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCaller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { var ( ret0 = new(string) @@ -520,14 +520,14 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(uint256 tokenId) constant returns(string) +// Solidity: function tokenURI(tokenId uint256) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TokenURI(tokenId *big.Int) (string, error) { return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // -// Solidity: function tokenURI(uint256 tokenId) constant returns(string) +// Solidity: function tokenURI(tokenId uint256) constant returns(string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCallerSession) TokenURI(tokenId *big.Int) (string, error) { return _EthereumPaymentObligationContract.Contract.TokenURI(&_EthereumPaymentObligationContract.CallOpts, tokenId) } @@ -560,126 +560,126 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractCalle // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address to, uint256 tokenId) returns() +// Solidity: function approve(to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "approve", to, tokenId) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address to, uint256 tokenId) returns() +// Solidity: function approve(to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address to, uint256 tokenId) returns() +// Solidity: function approve(to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.Approve(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId) } -// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. +// Initialize is a paid mutator transaction binding the contract method 0x8f15b414. // -// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Initialize(opts *bind.TransactOpts, name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "initialize", name, symbol, registry, mandatoryFields) +// Solidity: function initialize(name string, symbol string, anchorRegistry address, identityFactory address) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Initialize(opts *bind.TransactOpts, name string, symbol string, anchorRegistry common.Address, identityFactory common.Address) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "initialize", name, symbol, anchorRegistry, identityFactory) } -// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. +// Initialize is a paid mutator transaction binding the contract method 0x8f15b414. // -// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Initialize(name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, registry, mandatoryFields) +// Solidity: function initialize(name string, symbol string, anchorRegistry address, identityFactory address) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Initialize(name string, symbol string, anchorRegistry common.Address, identityFactory common.Address) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, anchorRegistry, identityFactory) } -// Initialize is a paid mutator transaction binding the contract method 0xf0feba3e. +// Initialize is a paid mutator transaction binding the contract method 0x8f15b414. // -// Solidity: function initialize(string name, string symbol, address registry, bytes[] mandatoryFields) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Initialize(name string, symbol string, registry common.Address, mandatoryFields [][]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, registry, mandatoryFields) +// Solidity: function initialize(name string, symbol string, anchorRegistry address, identityFactory address) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Initialize(name string, symbol string, anchorRegistry common.Address, identityFactory common.Address) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Initialize(&_EthereumPaymentObligationContract.TransactOpts, name, symbol, anchorRegistry, identityFactory) } -// Mint is a paid mutator transaction binding the contract method 0xa237952f. +// Mint is a paid mutator transaction binding the contract method 0x525b006f. // -// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) +// Solidity: function mint(to address, tokenId uint256, tokenURI string, anchorId uint256, properties bytes[], values bytes[], salts bytes32[], proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) Mint(opts *bind.TransactOpts, to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.contract.Transact(opts, "mint", to, tokenId, tokenURI, anchorId, properties, values, salts, proofs) } -// Mint is a paid mutator transaction binding the contract method 0xa237952f. +// Mint is a paid mutator transaction binding the contract method 0x525b006f. // -// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) +// Solidity: function mint(to address, tokenId uint256, tokenURI string, anchorId uint256, properties bytes[], values bytes[], salts bytes32[], proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, properties, values, salts, proofs) } -// Mint is a paid mutator transaction binding the contract method 0xa237952f. +// Mint is a paid mutator transaction binding the contract method 0x525b006f. // -// Solidity: function mint(address to, uint256 tokenId, string tokenURI, uint256 anchorId, uint256 nextAnchorId, bytes[] properties, bytes[] values, bytes32[] salts, bytes32[][] proofs) returns() -func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, nextAnchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { - return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, nextAnchorId, properties, values, salts, proofs) +// Solidity: function mint(to address, tokenId uint256, tokenURI string, anchorId uint256, properties bytes[], values bytes[], salts bytes32[], proofs bytes32[][]) returns() +func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) Mint(to common.Address, tokenId *big.Int, tokenURI string, anchorId *big.Int, properties [][]byte, values [][]byte, salts [][32]byte, proofs [][][32]byte) (*types.Transaction, error) { + return _EthereumPaymentObligationContract.Contract.Mint(&_EthereumPaymentObligationContract.TransactOpts, to, tokenId, tokenURI, anchorId, properties, values, salts, proofs) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "safeTransferFrom", from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SafeTransferFrom is a paid mutator transaction binding the contract method 0xb88d4fde. // -// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) returns() +// Solidity: function safeTransferFrom(from address, to address, tokenId uint256, _data bytes) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int, _data []byte) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SafeTransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId, _data) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(address to, bool approved) returns() +// Solidity: function setApprovalForAll(to address, approved bool) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) SetApprovalForAll(opts *bind.TransactOpts, to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "setApprovalForAll", to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(address to, bool approved) returns() +// Solidity: function setApprovalForAll(to address, approved bool) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. // -// Solidity: function setApprovalForAll(address to, bool approved) returns() +// Solidity: function setApprovalForAll(to address, approved bool) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) SetApprovalForAll(to common.Address, approved bool) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.SetApprovalForAll(&_EthereumPaymentObligationContract.TransactOpts, to, approved) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.contract.Transact(opts, "transferFrom", from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +// Solidity: function transferFrom(from address, to address, tokenId uint256) returns() func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractTransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { return _EthereumPaymentObligationContract.Contract.TransferFrom(&_EthereumPaymentObligationContract.TransactOpts, from, to, tokenId) } @@ -761,7 +761,7 @@ type EthereumPaymentObligationContractApproval struct { // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) +// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractApprovalIterator, error) { var ownerRule []interface{} @@ -786,7 +786,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) +// Solidity: e Approval(owner indexed address, approved indexed address, tokenId indexed uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApproval, owner []common.Address, approved []common.Address, tokenId []*big.Int) (event.Subscription, error) { var ownerRule []interface{} @@ -911,7 +911,7 @@ type EthereumPaymentObligationContractApprovalForAll struct { // FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) +// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*EthereumPaymentObligationContractApprovalForAllIterator, error) { var ownerRule []interface{} @@ -932,7 +932,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. // -// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) +// Solidity: e ApprovalForAll(owner indexed address, operator indexed address, approved bool) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractApprovalForAll, owner []common.Address, operator []common.Address) (event.Subscription, error) { var ownerRule []interface{} @@ -1053,7 +1053,7 @@ type EthereumPaymentObligationContractPaymentObligationMinted struct { // FilterPaymentObligationMinted is a free log retrieval operation binding the contract event 0xe2e4e975c4de5fbb1416db2c5ff8e2f4108bbfcdfd27a1a1eb03935cbfa3b8f9. // -// Solidity: event PaymentObligationMinted(address to, uint256 tokenId, string tokenURI) +// Solidity: e PaymentObligationMinted(to address, tokenId uint256, tokenURI string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterPaymentObligationMinted(opts *bind.FilterOpts) (*EthereumPaymentObligationContractPaymentObligationMintedIterator, error) { logs, sub, err := _EthereumPaymentObligationContract.contract.FilterLogs(opts, "PaymentObligationMinted") @@ -1065,7 +1065,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchPaymentObligationMinted is a free log subscription operation binding the contract event 0xe2e4e975c4de5fbb1416db2c5ff8e2f4108bbfcdfd27a1a1eb03935cbfa3b8f9. // -// Solidity: event PaymentObligationMinted(address to, uint256 tokenId, string tokenURI) +// Solidity: e PaymentObligationMinted(to address, tokenId uint256, tokenURI string) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchPaymentObligationMinted(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractPaymentObligationMinted) (event.Subscription, error) { logs, sub, err := _EthereumPaymentObligationContract.contract.WatchLogs(opts, "PaymentObligationMinted") @@ -1177,7 +1177,7 @@ type EthereumPaymentObligationContractTransfer struct { // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) +// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*EthereumPaymentObligationContractTransferIterator, error) { var fromRule []interface{} @@ -1202,7 +1202,7 @@ func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilte // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) +// Solidity: e Transfer(from indexed address, to indexed address, tokenId indexed uint256) func (_EthereumPaymentObligationContract *EthereumPaymentObligationContractFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *EthereumPaymentObligationContractTransfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) { var fromRule []interface{} diff --git a/nft/ethereum_payment_obligation_test.go b/nft/ethereum_payment_obligation_test.go index 2c5998300..7d711aa0d 100644 --- a/nft/ethereum_payment_obligation_test.go +++ b/nft/ethereum_payment_obligation_test.go @@ -64,7 +64,7 @@ func TestCreateProofData(t *testing.T) { }, }, proofData{ - Values: [][]byte{v1, v2, []uint8(nil), []uint8(nil)}, + Values: [][]byte{v1, v2}, Proofs: [][][32]byte{{byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}, {byteSliceToByteArray32(sortedHashes[0]), byteSliceToByteArray32(sortedHashes[1])}}, Salts: [][32]byte{byteSliceToByteArray32(salt), byteSliceToByteArray32(salt)}, }, @@ -119,7 +119,7 @@ func TestCreateProofData(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - proofData, err := createProofData(nil, test.proofs) + proofData, err := convertToProofData(test.proofs) if test.err != nil { assert.Equal(t, test.err.Error(), err.Error()) } else if err != nil { diff --git a/nft/payment_obligation_integration_test.go b/nft/payment_obligation_integration_test.go index e3d9d80fc..38e4fed43 100644 --- a/nft/payment_obligation_integration_test.go +++ b/nft/payment_obligation_integration_test.go @@ -78,7 +78,9 @@ func prepareForNFTMinting(t *testing.T) (context.Context, []byte, common.Address model, err := invSrv.DeriveFromCreatePayload(ctx, &invoicepb.InvoiceCreatePayload{ Collaborators: []string{}, Data: &invoicepb.InvoiceData{ + Sender: did.String(), InvoiceNumber: "2132131", + InvoiceStatus: "unpaid", GrossAmount: 123, NetAmount: 123, Currency: "EUR", @@ -126,7 +128,7 @@ func TestPaymentObligationService_mint_grant_read_access(t *testing.T) { DocumentID: id, RegistryAddress: registry, DepositAddress: common.HexToAddress(depositAddr), - ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", documents.CDTreePrefix + ".next_version"}, + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "invoice.sender", "invoice.invoice_status", documents.CDTreePrefix + ".next_version"}, GrantNFTReadAccess: true, SubmitNFTReadAccessProof: true, SubmitTokenProof: true, @@ -177,7 +179,7 @@ func mintNFTWithProofs(t *testing.T, grantAccess, tokenProof, readAccessProof bo DocumentID: id, RegistryAddress: registry, DepositAddress: common.HexToAddress(depositAddr), - ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "cd_tree.next_version"}, + ProofFields: []string{"invoice.gross_amount", "invoice.currency", "invoice.due_date", "invoice.sender", "invoice.invoice_status", documents.CDTreePrefix + ".next_version"}, GrantNFTReadAccess: grantAccess, SubmitTokenProof: tokenProof, SubmitNFTReadAccessProof: readAccessProof, diff --git a/resources/data.go b/resources/data.go index a0da2d3c0..acd4a3661 100644 --- a/resources/data.go +++ b/resources/data.go @@ -69,7 +69,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x5b\x73\xdb\x36\x94\x7e\xd7\xaf\x38\xe3\xbc\xb4\x33\x4b\x19\x04\xaf\xd2\x4c\x67\x47\xbe\xe4\xd2\x38\xae\x7c\x49\xdd\xf8\x65\x03\x02\x87\x12\x62\x0a\x60\x00\x50\x97\xfc\xfa\x1d\x80\x94\x6b\xc7\xb1\xbb\xdb\x4e\x77\xfd\x62\x0a\xc0\xb9\x7f\xe7\xc3\xe5\x15\x9c\x60\xcd\xba\xc6\x81\xc0\x35\x36\xba\x5d\xa1\x72\xe0\xd0\x3a\x85\x0e\xd8\x82\x49\x65\x1d\x18\xa9\xee\xb0\xda\x8d\x38\x2a\x67\x64\xdd\x2d\xf0\x1c\xdd\x46\x9b\xbb\x29\x98\xce\x5a\xc9\xd4\x52\x36\xcd\x28\x28\x93\x0a\xc1\x2d\x11\xc4\xa0\x57\xf5\x2b\x2d\xb8\x25\x73\x70\x7c\xaf\x01\x56\x4c\x2a\xe7\xf5\x8f\xf6\x4b\xa6\x23\x80\x57\x70\xa6\x39\x6b\x82\x0b\x52\x2d\x80\x6b\xe5\x0c\xe3\x0e\x98\x10\x06\xad\x45\x0b\x0a\x51\x80\xd3\x50\x21\x58\x74\xb0\x91\x6e\x09\xa8\xd6\xb0\x66\x46\xb2\xaa\x41\x3b\x1e\xc1\x5e\xde\xab\x04\x90\x62\x0a\x49\x92\x84\x6f\x74\x4b\x34\xd8\xad\x86\x08\xde\x89\x29\x94\x49\xd9\xcf\x55\x5a\x3b\xeb\x0c\x6b\xe7\x88\xc6\xf6\xb2\x11\x1c\x1c\xca\x36\x3d\x8c\x69\x31\x26\x63\x32\x8e\x0f\x1d\x6f\x0f\x93\x92\x12\x7a\x28\xdb\xda\x1e\x5e\xac\xae\x2f\xb6\xd5\xe6\xae\xbb\xfd\xf4\xe9\xa4\xee\xbe\x5d\x57\xdb\xd3\xd9\x25\x5e\x9f\x1f\x9f\xe9\x6f\xbb\x5d\x96\x95\xeb\x0b\xb5\xf8\x7d\x3d\xff\xf0\xe5\xec\xd3\xdd\xc1\x5f\x28\x4d\xf6\x4a\x7f\xaf\xf3\xd3\xf3\x7c\x75\xf7\xf5\x06\xbf\xdc\xbc\xbf\xa1\x5f\xe7\x5d\x9c\xff\xd1\x8a\x37\xc9\xdd\xaf\x3a\xbe\x4e\x56\x4b\xb6\x9c\x1f\x65\x57\x98\xa9\xb8\x57\xba\x4f\xd5\x6c\x9f\xa9\x3e\x00\x1f\x3e\x2a\x27\xdd\xee\x35\xe3\x4e\x9b\xdd\x14\x0e\x0e\xbe\x9b\xb9\xc4\x85\xb4\xee\xd1\x14\x53\x7c\xa9\xcd\x25\xb6\xda\xca\xef\xa4\x5a\xb6\xf3\x30\xf9\xad\x6a\xe4\x82\x39\xa9\x55\x98\x0b\xc5\xfb\xc0\xa4\xfa\x21\x94\x86\x1a\xc3\x4f\x97\x3d\x96\x7e\x1e\xc1\x43\xec\xf4\xae\xbe\x82\xf3\x6e\x85\x46\x72\x78\x77\x02\xba\x0e\x38\x7a\x80\x98\x41\xc7\x7d\x49\xb3\x78\x90\x3a\xda\xd7\x0d\x1a\x69\x9d\x97\x54\x5a\xe0\x53\xc8\xb5\x46\xaf\x65\x98\xd0\x41\xf7\x03\x07\xf6\x8e\xfe\x25\x0e\x92\x6c\x4c\x69\x36\xa6\x84\x8c\x53\xfa\x3d\x16\x62\x7a\x92\xbc\xd7\xfa\xe6\x4c\x4a\x7e\xf1\xfb\xe6\x7a\x79\x7d\xf4\x29\xdf\xbe\xe7\x73\x7d\x56\xe7\x97\x17\x9f\x7e\x7d\xdd\x6e\xea\xd8\x14\xd9\xe6\x6c\x4b\x6f\x2f\x93\xf6\x58\xc4\x07\x3f\x52\x5f\xe6\x63\x1a\x93\xe7\xd4\x5f\xdc\x7e\x98\x95\x6f\xe6\x6f\xcd\xfa\xf4\xf6\x68\xb2\x11\x77\xfa\x23\x9f\xcd\x56\xc7\xb7\x6f\xdb\x09\xee\x76\xb7\xe9\xd5\x69\xb9\x78\x6d\x92\xe5\xf5\xf9\x1f\x07\x43\x8e\x4e\x07\xdc\xdf\x57\xe2\xdd\x09\x44\x30\x54\xe3\xb9\xce\x48\x07\xe1\x33\xe6\xd3\x03\x02\xdb\x46\xef\x50\xc0\xd5\x8a\x19\x07\xc7\x03\xe0\x2c\xd4\xda\x84\x84\x2e\xe4\x1a\xd5\xa3\x54\x3e\x05\x25\x3c\x8b\x4a\xb2\x8d\x2b\x92\x91\xb4\xc0\x32\x8e\x4b\x96\x0b\x56\xa7\x69\x5a\x53\x9a\x66\x79\x4e\xea\x4c\x24\x75\x9a\x53\xc2\x26\xe2\x05\xfc\x92\xed\x24\xcf\x09\x27\xc9\x44\x24\x71\x9c\x66\x09\xab\x89\xc8\x4a\x9e\xe5\x79\x5e\xd0\x44\x4c\x38\xad\x59\x21\x72\xe4\x2f\x20\x9d\x6c\x71\x52\x56\x84\xe7\x42\x4c\x08\xcd\x8b\x34\xa9\x8b\x24\xcf\x0b\xac\x59\x5d\xb2\x49\x46\x04\x11\x65\x9d\x4e\x04\x7d\xa9\x27\xc8\xb6\xe2\x31\xc3\x82\xd6\x55\x95\x33\x4a\x4a\x9a\xd5\x59\x9c\xe4\x9c\x57\x8c\x60\x99\x88\xbc\x2a\xb1\x28\x53\x1f\x4f\xe8\x9e\xf7\x7a\xcd\xfa\xf4\x3d\xc0\x7a\x85\x46\xb1\x66\x89\x72\xb1\x74\x03\x16\x5f\xbd\x7a\x35\x14\xa6\x97\x78\x3d\xbb\x18\x7e\x47\x70\xe3\xe9\x50\xaa\xba\x33\x0c\x76\xba\x83\x85\xe7\x71\x05\x68\x8c\x36\x1e\x65\xd7\x4b\x69\xc1\xe0\xd7\xce\x5b\x91\x16\x94\x76\x60\xbb\xb6\xd5\xc6\xa1\x80\x0a\x39\xeb\x2c\x7a\x49\x13\x9a\xc8\x2f\x31\x9d\x52\x9e\x8b\x03\xd3\x5a\xc7\x9c\xef\xa4\xce\x0f\x8d\xe1\xb2\x53\xfd\x78\x14\x0d\x63\xbf\x30\xc3\x97\x72\x8d\xe3\x83\xff\x18\x9c\x02\xd8\xf8\x46\x74\x1a\x84\xfe\xcf\x20\xc1\xa0\x09\x2c\xdf\x32\x23\xdd\xae\x37\x14\xb4\xdc\x85\x78\x70\x31\xed\x7f\x7e\x1e\x16\x44\x11\x5f\x32\xa9\x7e\xe9\xa7\xa3\xc8\x7b\xfb\x4b\x42\x12\x92\x42\x14\x6d\x98\x69\x87\x7f\x51\xc5\x8c\x91\x68\x20\xcb\x4b\x42\x08\x81\x28\x52\x3a\x62\x8a\x4b\x54\x2e\xaa\x1a\xcd\xef\x6c\x3f\x66\xd1\xac\x31\x6a\x7c\x52\x21\x8a\x56\x6c\x1b\xb5\xbe\xd7\x81\x66\x5e\xc8\x2a\xd6\xda\xa5\x76\xc3\x60\x18\x5b\x49\xf5\xe8\xa7\xf7\x99\x71\x27\xd7\x08\x51\xe4\x31\xee\x53\xa4\xeb\xfa\x69\x26\x20\x8a\x44\x15\x71\xbd\x6a\xfd\x7a\xad\xc0\x5a\xe1\x43\x62\x7c\x89\x91\x95\xdf\x10\x52\x32\xc9\x21\x8a\xbe\x58\xad\x4c\xcb\xa3\xa5\xb6\xce\x02\x6b\x9a\x07\x63\x52\x39\x34\x35\xe3\xe8\xc7\x3f\x3f\x2e\xf7\xd3\x64\xfe\xa8\xf2\x47\x3e\x7c\x14\xbe\x25\x15\xf6\x8e\x38\x0d\x37\x58\x5d\xf9\x71\x67\x21\xe4\xc4\x40\x6d\xf4\x0a\x3a\xe5\x4c\x67\x3d\x24\xb4\x91\x0b\xa9\xa6\x30\x1e\x1f\x3c\x5b\x4f\xdf\xfb\x4f\x6a\xf9\x39\x8a\x3a\x65\x59\x8d\x11\x6e\x5b\x6d\xf1\x33\xd4\x0d\x5b\x7c\x07\xe0\xff\x1d\xe1\xd3\x7f\x48\xf8\x8f\x7a\xe9\x7f\x4c\xf9\x31\x49\xc7\x71\x96\x8e\xe3\x72\x9c\x3d\xd9\xfe\xf7\x9c\x3c\xb7\xb9\x64\xf8\xb1\x7b\x7d\x7b\xde\xc5\x6f\xb6\x6b\xbb\x3b\xba\xbe\x32\xd7\x76\xb2\x76\x47\x79\xe5\x3e\xcc\xd4\xdb\xd7\xfa\xec\x4b\x75\xf7\xed\x98\x1d\xfc\x40\x7d\x36\x8e\xcb\x6c\x4c\x93\xe2\x59\x03\xc7\x6f\xf8\x46\x5e\x7f\xd1\xef\x6f\xde\xd6\x47\x2c\x2d\xe9\xc7\xb9\x63\xf8\x71\x7b\x7e\xb6\x11\xe5\xb7\x4a\x1d\xc5\x57\xc5\x06\x67\xb7\x1f\xb7\xb7\x2f\x93\x7e\x20\x8d\x67\x29\x9f\xfe\x0b\x9c\xff\x02\xe5\x4f\xf2\x3c\xce\x4b\x12\x97\x98\x12\x9e\xc6\x65\x91\x8a\x32\xe7\x28\xea\x8a\x97\x04\x31\xaf\xaa\x92\x65\x45\x9e\xbe\x48\xf9\x59\xca\x30\x29\x92\x9a\x4c\xf2\x9a\xd5\x54\x54\x79\x55\xb2\x34\x2f\xe2\x82\x93\x6a\x52\x22\xaf\x19\x29\x32\x21\x5e\xa4\xfc\xba\x28\xe2\x98\x08\x91\x23\x2d\x2b\xca\x59\x91\xc5\x49\x41\x58\x5e\x97\x94\x60\x45\x8b\x22\x15\x55\x52\xc6\xe4\x65\xca\xa7\x45\x11\xd3\x09\x47\x5a\x57\x05\x25\x05\x27\x35\xc1\x94\xe5\x44\x50\x41\xaa\xac\x2e\xbd\x2b\x55\x55\x55\x03\xe5\x5f\xea\xd6\x3a\x7c\x42\xfa\x42\x2f\x5a\xe6\xf8\xf2\xef\x9d\x8b\x92\x7f\xd8\x26\x7b\xeb\xf0\xd3\xf5\x6f\x27\xbf\x01\x37\xe8\x39\xdf\x0c\xae\xfa\x56\x09\x7a\x7e\x7e\xb6\x73\xfe\xf5\xe3\xd2\xff\xdf\x81\xa9\x4f\xc2\x73\xdd\x93\xfc\xdf\x36\x4f\xc9\xb2\x94\xa7\x85\xc8\xf3\x8c\xc6\x98\xd7\x82\x8b\x3a\x89\x79\x4a\x63\x24\x79\x4c\xe3\x2c\x15\x75\x99\xe6\xd5\xcb\xcd\x93\xc5\x39\x39\x8a\x29\x99\xc4\x3c\x8d\x4f\x8b\xe3\x34\xae\xc9\xd1\x2c\x9b\xe1\x84\x66\x8c\xa4\x34\xe7\x29\x9b\x9d\xce\x5e\x6e\x9e\x9c\xd2\x22\x2d\x0b\x12\xf3\x98\x66\x28\x28\x4d\x62\xce\xeb\xa4\xe6\x75\x55\x30\x5a\x91\xb8\x66\x65\x92\x65\x2f\x37\x8f\x10\x69\xc1\x90\x15\x69\xc1\x29\x25\xa9\xa0\x69\x4a\xfc\x89\x29\x41\x4c\x49\xc5\x69\x95\xd1\x8a\x4f\x44\x7d\x30\xf2\x97\x4d\xe6\x18\x5c\x39\x6d\xd8\x02\x47\xb6\xff\xdf\x5f\x21\xe7\xcc\x2d\x43\x8a\x1b\x7f\x13\x39\x39\x82\x5a\x36\x38\xf2\x46\xdd\x72\x0a\x87\x6e\xd5\x1e\xfe\x79\x95\xfd\x2f\xc1\x1c\x1b\x87\x95\xa2\xf2\x7a\x8f\xb5\xaa\xe5\xa2\x33\xc1\xad\x7b\x03\x3c\x8c\x5e\xfd\x7d\x33\xbd\x82\x27\xd6\x66\x9c\xeb\x4e\x39\x0b\x77\xb8\x83\x21\x8a\x11\x1b\x06\xbd\x9d\x3b\xdc\xf9\x61\x1c\x34\xee\xa7\xbc\xec\xbb\xfb\x33\xc1\xc6\x23\x31\x20\x6a\x36\x7f\x07\x4c\x09\x98\xd3\x39\x5c\xf5\x1b\xba\x6f\x7e\x54\xbe\xbb\x47\xbe\x6f\xdf\x6a\xeb\x14\x5b\xe1\x14\x48\xb8\x7c\x92\xd1\x2b\x98\x6b\xe3\x06\x25\x5e\xc1\x8f\x05\xfd\xa2\x29\x94\xa4\xa4\xde\xb8\x6f\xf7\xc8\xe9\x70\x26\x02\xfe\x30\x67\x76\xd4\xd2\xb6\x4f\xd1\x55\x8b\x5c\xd6\x3b\x38\xdd\xba\xb0\xf5\xc2\xbb\xf9\x03\x5f\xc3\x59\x81\x33\xe5\xaf\xf2\x06\xfd\x71\x48\x00\x73\x20\x6b\xa8\x70\x29\x95\x80\xf3\xd9\xb5\x57\x83\x83\xf4\xbb\xf9\x14\x36\xe3\xed\x78\x37\xfe\xd6\x17\xc0\x7b\xdd\x59\x14\xf7\xfd\xe4\xa3\x6e\xd8\x0e\x8d\x2f\x43\x70\x37\xb0\x41\x58\x7d\x2d\x57\xa8\xbb\x10\xa6\x02\xdd\xa2\x1a\xde\x17\x86\xc3\x50\x60\xbf\x70\xc0\x1b\xc1\x7e\x78\x10\x99\xc2\x41\x42\x6c\x00\xdd\x45\x87\x1d\x7e\x17\x6e\xb0\xce\xec\x4e\xf1\xa5\xd1\x4a\x77\xd6\x13\x2a\x47\x6b\xa5\x5a\x8c\xbe\x7a\x81\x3e\x19\xfd\xeb\x88\xed\x43\xef\x56\x15\x1a\x4f\xc9\x9e\x3a\xd0\xd8\x43\xae\x95\xf5\x2c\x3f\xd0\xf3\xc6\x5f\x4a\xab\x70\xda\xd3\x9c\xb9\x3e\x33\xd6\x31\xe3\xba\x76\x04\x5e\xfe\xa6\x17\x9c\x42\x1f\xde\x6b\x83\x68\xa1\x6b\xe1\x78\xfe\x11\xf8\x8e\x37\x68\xfb\x50\x7b\x03\xfe\x20\xbf\x61\x32\x3c\xaa\x78\x7f\x71\x8d\x1e\x45\x30\x4c\xdf\x30\x19\xa2\xfd\x70\x35\x85\x78\x34\x6c\x39\x83\x87\x06\x9d\x91\x18\x0e\xa4\x7a\x33\x24\x9b\x81\x63\xd6\x6f\x39\xfe\xdf\x65\xbf\x60\x0a\x31\xf1\x39\xba\x67\x4e\x1b\xaa\x2f\xf9\xe3\x7c\x8d\xf6\xbc\x39\x40\x04\x1b\xf4\x94\xb8\x59\x4a\xbe\xbc\xe7\x54\x18\x70\xee\x8b\xe2\x2f\x24\xc3\xae\xa7\x7d\xfe\x86\xed\x4a\x80\xec\x4f\x9e\xbc\xb3\x4e\xaf\x06\x23\xfb\x26\x1c\xde\x9f\x86\xf6\x3a\x0f\x78\x3f\x58\x31\xa9\x0e\xee\x5f\x99\x42\x7f\x0f\x8a\xef\xed\xf2\xc6\xdf\x15\x7a\x68\xfe\xb4\xc1\x70\x55\x92\x06\x61\x63\x41\x1b\x90\x2d\x1f\x9e\x9e\x58\xd5\xa0\xff\xe4\x61\xa3\xec\xb3\xe9\x37\x44\x2f\xf8\xf1\xf2\x6c\x0a\x4b\xe7\xda\xe9\xe1\x61\x38\x9b\xfb\x03\xfd\x74\x92\xa5\xd9\x1e\x07\xe1\x69\x6c\xc1\x7c\x2c\x92\x7b\x77\x17\xcc\xce\xfd\xa7\xcf\xe1\xfe\xef\xc9\xe2\x46\xae\xa4\xeb\x17\x9f\xf9\xcf\x29\xa4\x45\x4c\x93\xb2\x7c\x84\x6f\xa7\x43\xa1\xfb\x32\xa9\x3f\x23\x73\x86\x29\xcb\xee\x0f\xfe\x3e\x06\x21\xfa\xa7\x34\x06\xe1\x6e\x14\x88\xa3\x0f\x05\x9c\x91\x8b\x05\x1a\x14\x7d\x37\x38\xdc\xba\x3d\x46\xfa\x8e\xc8\x89\x6f\x89\xe7\x0c\x1b\x64\x02\xb4\x6a\x76\xbe\xd3\xf6\x7d\xb2\x7f\x4f\xdc\xbb\xf4\xa7\xea\x4b\x64\xe2\xb1\xfa\x38\x1b\xb4\x9f\xfb\x4a\x3c\xf4\xbd\xd5\xba\x81\x15\xdb\xde\xe3\xd2\x69\xb0\xa8\x84\xc7\xe4\x83\x65\x7a\x1d\x58\x60\xc5\xb6\xf7\xf0\xa4\x43\x4e\x7f\xac\x32\xdc\xb0\xd6\xac\x09\x7a\x77\x7d\xef\x30\xef\x20\xef\x8c\x09\x6f\x59\x0f\x24\x96\xcc\x42\x85\xa8\x40\xa0\x43\xee\x42\x9a\xf6\x0a\xbc\x3d\xbf\x2b\xd2\x21\x82\x13\x69\x03\x5a\x82\x46\xab\x57\x4f\xd0\x66\x41\xe8\x87\x17\x71\x70\xdb\xe0\x11\x6b\xa5\xef\xb0\xed\x5c\xeb\x66\xc6\x3d\xa3\x9c\x2a\xaf\x49\x4c\xc1\x99\x0e\x7d\xaf\x31\xb5\x03\x81\x55\xb7\x58\x0c\x6c\xe6\x5b\x20\x70\xc7\x42\x83\x37\x32\x0a\xb3\x7d\xab\xb5\xad\xd1\x75\x28\xcf\xbd\x88\xe7\x49\x3f\x3a\x85\x9a\x35\x16\x47\xa3\x7e\x77\x1f\x9e\x4e\x5b\x83\x5c\xaf\x02\xd2\x82\xc1\xff\x0e\x00\x00\xff\xff\x78\x36\xb5\xe4\x2f\x16\x00\x00") +var _goCentrifugeBuildConfigsDefault_configYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\x5b\x73\xdb\x36\x16\x7e\xd7\xaf\x38\xe3\xbc\xb4\x33\x4b\x99\x77\x51\x9a\xe9\xec\xf8\x92\x8b\x1b\xc7\x95\x6d\xb9\x6e\xfc\xb2\x39\x04\x0e\x25\xc4\x14\xc0\x00\xa0\x2e\xf9\xf5\x3b\x00\x29\xd5\x8e\x63\x77\xb7\x9d\xee\xfa\xc5\x14\x80\x73\xff\xce\x87\xcb\x2b\x38\xa5\x0a\xdb\xda\x02\xa7\x15\xd5\xaa\x59\x92\xb4\x60\xc9\x58\x49\x16\x70\x8e\x42\x1a\x0b\x5a\xc8\x7b\x2a\xb7\x03\x46\xd2\x6a\x51\xb5\x73\xba\x20\xbb\x56\xfa\x7e\x02\xba\x35\x46\xa0\x5c\x88\xba\x1e\x78\x65\x42\x12\xd8\x05\x01\xef\xf5\xca\x6e\xa5\x01\xbb\x40\x0b\x27\x7b\x0d\xb0\x44\x21\xad\xd3\x3f\xd8\x2d\x99\x0c\x00\x5e\xc1\xb9\x62\x58\x7b\x17\x84\x9c\x03\x53\xd2\x6a\x64\x16\x90\x73\x4d\xc6\x90\x01\x49\xc4\xc1\x2a\x28\x09\x0c\x59\x58\x0b\xbb\x00\x92\x2b\x58\xa1\x16\x58\xd6\x64\x86\x03\xd8\xc9\x3b\x95\x00\x82\x4f\x20\x49\x12\xff\x4d\x76\x41\x9a\xda\x65\x1f\xc1\x19\x9f\x40\x91\x14\xdd\x5c\xa9\x94\x35\x56\x63\x33\x25\xd2\xa6\x93\x0d\xe0\xe0\x50\x34\xe9\x61\x14\x8f\x86\xe1\x30\x1c\x46\x87\x96\x35\x87\x49\x11\x87\xf1\xa1\x68\x2a\x73\x78\xb9\x9c\x5d\x6e\xca\xf5\x7d\x7b\xf7\xf1\xe3\x69\xd5\x7e\x9d\x95\x9b\xd7\x47\x57\x34\xbb\x38\x39\x57\x5f\xb7\xdb\x2c\x2b\x56\x97\x72\xfe\xeb\x6a\xfa\xe1\xf3\xf9\xc7\xfb\x83\x3f\x50\x9a\xec\x94\xfe\x5a\xe5\xaf\x2f\xf2\xe5\xfd\x97\x5b\xfa\x7c\xfb\xfe\x36\xfe\x32\x6d\xa3\xfc\xb7\x86\xbf\x4d\xee\x7f\x56\xd1\x2c\x59\x2e\x70\x31\x3d\xce\xae\x29\x93\x51\xa7\x74\x97\xaa\xa3\x5d\xa6\xba\x00\x5c\xf8\x24\xad\xb0\xdb\x37\xc8\xac\xd2\xdb\x09\x1c\x1c\xf4\x33\x28\xd9\x42\xe9\x2b\x6a\x94\x11\xdf\x4c\x35\xb8\x75\x58\xf8\xa5\xac\xc5\x1c\xad\x50\xd2\xcf\xf9\x0a\x7d\x40\x21\xbf\x8b\x97\xbe\x90\xf0\xc3\x55\x07\x98\x1f\x07\xf0\x10\x20\x9d\x3f\xaf\xe0\xa2\x5d\x92\x16\x0c\xce\x4e\x41\x55\x1e\x2c\x0f\x60\xd1\xeb\xd8\xd7\x2d\x8b\x7a\xa9\xe3\x5d\x71\xa0\x16\xc6\x3a\x49\xa9\x38\x3d\xc5\x55\xa3\xd5\x4a\xf8\x09\xe5\x75\x3f\x70\x60\xe7\xe8\x1f\x16\x3b\xc9\x86\x71\x9c\x0d\xe3\x30\x1c\xa6\xf1\xb7\x05\x8f\xe2\xd3\xe4\xbd\x52\xb7\xe7\x42\xb0\xcb\x5f\xd7\xb3\xc5\xec\xf8\x63\xbe\x79\xcf\xa6\xea\xbc\xca\xaf\x2e\x3f\xfe\xfc\xa6\x59\x57\x91\x1e\x65\xeb\xf3\x4d\x7c\x77\x95\x34\x27\x3c\x3a\xf8\x9e\xfa\x22\x1f\xc6\x51\xf8\x9c\xfa\xcb\xbb\x0f\x47\xc5\xdb\xe9\x3b\xbd\x7a\x7d\x77\x3c\x5e\xf3\x7b\x75\xc3\x8e\x8e\x96\x27\x77\xef\x9a\x31\x6d\xb7\x77\xe9\xf5\xeb\x62\xfe\x46\x27\x8b\xd9\xc5\x6f\x07\x7d\x8e\x5e\xf7\xe0\xde\x57\xe2\xec\x14\x02\xe8\xab\xf1\x1c\xfc\xd3\x5e\xf8\x1c\x5d\x7a\x80\x53\x53\xab\x2d\x71\xb8\x5e\xa2\xb6\x70\xd2\xa3\xca\x40\xa5\xb4\x4f\xe8\x5c\xac\x48\x3e\x4a\xe5\x53\xe4\xc1\xb3\xd0\x0b\x37\x55\x45\x61\x1e\xc5\x61\x98\x13\x71\x24\x8e\x51\x51\x30\x3e\xe6\x55\x96\x66\xa3\x14\xf3\x62\x1c\x87\x38\x1e\xf1\x17\x40\x1a\x6e\x78\x52\xd2\xa8\x48\xf3\x30\xca\x93\x7c\x84\x61\x81\x3c\x2c\x92\x32\xcc\x79\x35\x2e\x90\x8f\x8a\x38\x8a\x79\x88\xd9\x4b\x70\x0e\x37\x31\xcf\xca\x3c\x1d\x85\x58\x45\xc8\xc6\x79\xcc\xb2\xac\xcc\x4b\xa2\x71\x5c\x25\x2c\x29\x58\x1e\x8e\xab\x64\x14\x51\x0f\xfc\xf7\x6a\x85\x5d\xe4\x0f\x60\x5a\x92\x96\x58\x2f\x48\xcc\x17\xb6\x87\xd1\xab\x57\xaf\xfa\x9c\x76\x12\x6f\x8e\x2e\xfb\xdf\x01\xdc\x3a\xba\x12\xb2\x6a\x35\xc2\x56\xb5\x30\x77\x3c\x2b\x81\xb4\x56\xda\x01\x64\xb6\x10\x06\x34\x7d\x69\x9d\x15\x61\x40\x2a\x0b\xa6\x6d\x1a\xa5\x2d\x71\x28\x89\x61\x6b\xc8\x49\x6a\x8f\x7f\xb7\x44\xb7\x52\x3a\xae\xf4\x4c\x68\x2c\x5a\xd7\x04\xad\x1b\x1a\xc2\x55\x2b\xbb\xf1\x20\xe8\xc7\x7e\x42\xcd\x16\x62\x45\xc3\x83\x7f\xf4\x4e\x01\xac\x5d\x0f\x59\x05\x5c\xfd\xd3\x4b\x20\xd4\x9e\x85\x1b\xd4\xc2\x6e\x3b\x43\x5e\xcb\xbd\x8f\x87\xe6\x93\xee\xe7\xa7\x7e\x41\x10\xb0\x05\x0a\xf9\x53\x37\x1d\x04\xce\xdb\x9f\x92\x30\x09\x53\x08\x82\x35\xea\xa6\xff\x17\x94\xa8\xb5\x20\x0d\x59\x5e\x84\x61\x18\x42\x10\x48\x15\xa0\x64\x82\xa4\x0d\xca\x5a\xb1\x7b\xd3\x8d\x19\xd2\x2b\x0a\x6a\x97\x54\x08\x82\x25\x6e\x82\xc6\xb5\x29\xc4\x99\x13\x32\x12\x1b\xb3\x50\xb6\x1f\xf4\x63\x4b\x21\x1f\xfd\x74\x3e\x23\xb3\x62\x45\x10\x04\x0e\x9e\x2e\x45\xaa\xaa\x9e\x66\x02\x82\x80\x97\x01\x53\xcb\xc6\xad\x57\x12\x8c\xe1\x2e\x24\x64\x0b\x0a\x8c\xf8\x4a\x90\x86\xe3\x1c\x82\xe0\xb3\x51\x52\x37\x2c\x58\x28\x63\x0d\x60\x5d\x3f\x18\x13\xd2\x92\xae\x90\x91\x1b\xff\xf4\xb8\xdc\x4f\x93\xf9\xbd\xca\x1f\xbb\xf0\x89\xbb\x6e\x92\xd4\x39\x62\x15\xdc\x52\x79\xed\xc6\xad\x01\x9f\x13\x0d\x95\x56\x4b\x68\xa5\xd5\xad\x71\x90\x50\x5a\xcc\x85\x9c\xc0\x70\x78\xf0\x6c\x3d\x5d\xdb\x3e\xa9\xe5\xa7\x20\x68\xa5\xc1\x8a\x02\xda\x34\xca\xd0\x27\xa8\x6a\x9c\x7f\x03\xe0\xff\x8e\xab\xe3\xbf\xc8\xd5\x8f\x7a\xe9\x3f\x66\xeb\x28\x4c\x87\x51\x96\x0e\xa3\x62\x98\x3d\xd9\x9e\x77\x74\x3a\x35\xb9\x40\xba\x69\xdf\xdc\x5d\xb4\xd1\xdb\xcd\xca\x6c\x8f\x67\xd7\x7a\x66\xc6\x2b\x7b\x9c\x97\xf6\xc3\x91\x7c\xf7\x46\x9d\x7f\x2e\xef\xbf\x9e\xe0\xc1\x77\xd4\x67\xc3\xa8\xc8\x86\x71\x32\x7a\xd6\xc0\xc9\x5b\xb6\x16\xb3\xcf\xea\xfd\xed\xbb\xea\x18\xd3\x22\xbe\x99\x5a\xa4\x9b\xcd\xc5\xf9\x9a\x17\x5f\x4b\x79\x1c\x5d\x8f\xd6\x74\x74\x77\xb3\xb9\x7b\x99\xaf\x3d\x69\x3c\xcb\xd6\xf1\xdf\x40\xd7\x2f\xb0\x75\x18\x21\x2f\xf3\x3c\xc1\x8a\x27\x98\xf1\x51\x9e\x65\xac\x18\xf3\x78\x34\x4a\x19\x55\x59\x54\x84\x61\x95\x94\x65\xfe\x22\x5b\x47\x79\x95\x66\x84\x6c\x94\x8c\xb2\x98\xb0\x1c\x25\xe1\x28\xae\x38\x2f\x91\x95\x8e\xa5\x0b\xe4\x2c\xc1\x34\x7c\x99\xad\xa9\x8c\x58\x8e\x49\xce\xd2\x32\x8a\x93\x14\x11\x69\x44\x8c\x8a\xa2\x2a\xd3\x2a\x2d\x78\x9c\xf0\x3c\x89\xd2\xbc\x67\xeb\x2b\xd5\x18\x4b\x4f\xf8\x9a\xab\x79\x83\x96\x2d\xfe\xdc\x69\x24\xf9\x8b\x08\xdf\x59\x87\x1f\x66\xbf\x9c\xfe\x02\x4c\x93\xa3\x6b\xdd\xbb\xea\x50\xee\xf5\xfc\xf8\x2c\xe8\xff\xf6\x43\xca\xff\xef\x98\xd2\x25\xe1\x39\xe0\x27\xff\x5b\xdc\x47\x25\x46\x45\x99\x47\x49\x32\xaa\x30\x8a\xa3\x24\x19\x27\xc9\xb8\xcc\xb2\x74\x94\x84\x2c\xa4\x51\x58\x8e\xb1\x88\xd8\x8b\xb8\xaf\xaa\xac\x4a\xb2\x2a\xaf\x92\x71\x14\x12\xcf\x73\x8c\xd3\x32\xa7\x2c\xcb\xd2\x98\xf2\xbc\x2c\xf2\x22\x8d\x72\x4c\x5e\xc6\x7d\x5a\xb0\x38\xa3\x51\x9e\x8c\xa9\x28\x0a\xca\xf3\x51\x15\x87\x3c\x09\xcb\x71\x9e\x67\x09\xa7\x30\x4b\xe3\x2c\xe2\xc5\xc1\xc0\x5d\xc1\xd0\x22\x5c\x5b\xa5\x71\x4e\x03\xd3\xfd\xef\x2e\x56\x53\xb4\x0b\x9f\x9d\xda\x1d\xdd\x4f\x8f\xa1\x12\x35\x0d\x9c\x51\xbb\x98\xc0\xa1\x5d\x36\x87\xbf\x5f\xf0\xfe\xc5\xd1\xe2\xd0\xaf\xe4\xa5\xd3\x7b\xa2\x64\x25\xe6\xad\xf6\x6e\xed\x0d\x30\x3f\x7a\xfd\xe7\xcd\x74\x0a\x9e\x58\x3b\x62\x4c\xb5\xd2\x1a\xb8\xa7\x2d\xf4\x51\x0c\xb0\x1f\x74\x76\xee\x69\xeb\x86\xa9\xd7\xb8\x9b\x72\xb2\x67\xfb\x9d\x78\xed\x40\xe4\xc1\x70\x34\x3d\x03\x94\x1c\xa6\xf1\x14\xae\xbb\x6d\xd4\xf5\x2d\x49\xd7\x98\x03\xd7\x72\xef\x94\xb1\x12\x97\x34\x81\xd0\x5f\xc9\xc2\xc1\x2b\x98\x2a\x6d\x7b\x25\x4e\xc1\xf7\x05\xdd\xa2\x09\x14\x61\x11\x3b\xe3\xae\x53\x03\xab\xfc\x49\x04\xd8\xc3\x9c\x99\x41\x13\x37\x5d\x8a\xae\x1b\x62\xa2\xda\xc2\xeb\x8d\xf5\x1b\x1e\x9c\x4d\x1f\xf8\xea\x77\x68\x86\xd2\x5d\x70\x35\xb9\x43\x08\x07\xb4\x20\x2a\x28\x69\x21\x24\x87\x8b\xa3\x99\x53\x43\xbd\xf4\xd9\x74\x02\xeb\xe1\x66\xb8\x1d\x7e\xed\x0a\xe0\xbc\x6e\x0d\xf1\x7d\x2b\xb8\xa8\x6b\xdc\x92\x76\x65\xf0\xee\xfa\x46\xf6\xab\x67\x62\x49\xaa\xf5\x61\x4a\x50\x0d\xc9\xfe\xd6\xdd\x1f\x41\x3c\x71\xf9\x63\xd5\x00\x76\xc3\xbd\xc8\x04\x0e\x92\xd0\x78\xd0\x5d\xb6\xd4\xd2\x37\xe1\x7a\xeb\x68\xb6\x92\x2d\xb4\x92\xaa\x35\x8e\x0b\x19\x19\x23\xe4\x7c\xf0\xc5\x09\x74\xc9\xe8\xde\x0c\x4c\x17\x7a\xbb\x2c\x49\x3b\x36\x75\x5d\x4f\xda\x1c\x32\x25\x8d\x23\xe8\x9e\x59\xd7\xee\x16\x57\xfa\x33\x96\x62\x68\xbb\xcc\x18\x8b\xda\xb6\xcd\x00\x9c\xfc\x6d\x27\x38\x81\x2e\xbc\x37\x9a\xc8\x40\xdb\xc0\xc9\xf4\x06\xd8\x96\xd5\x64\xba\x50\x3b\x03\xee\xf8\xbc\x46\xe1\x9f\x1a\x9c\xbf\xb4\x22\x87\x22\xe8\xa7\x6f\x51\xf8\x68\x3f\x5c\x4f\x20\x1a\xf4\xbb\x45\xef\xa1\x26\xab\x05\xf9\x63\xa0\x5a\xf7\xc9\x46\xb0\x68\xdc\x6e\xe1\xfe\x5d\x75\x0b\x26\x10\x85\x2e\x47\x7b\xd2\x33\xbe\xfa\x82\x3d\xce\xd7\x60\x47\x79\x3d\x44\xa8\x26\xc7\x66\xeb\x85\x60\x8b\x3d\x1d\x42\x8f\x73\x57\x14\x77\x0d\xe8\x37\x2c\xe5\xf2\xd7\xef\x34\x1c\x44\x77\xde\x63\xad\xb1\x6a\xd9\x1b\xd9\x35\x61\xff\x2a\xd3\xb7\xd7\x85\xc7\xfb\xc1\x12\x85\x3c\xd8\xbf\xbd\xf8\xfe\xee\x15\xef\xed\xb2\xda\x9d\xd0\x3b\x68\xfe\xb0\x26\x7f\x41\x11\x9a\x60\x6d\x40\x69\x10\x0d\xeb\x1f\x64\xb0\xac\xc9\x7d\x32\xbf\xc7\x75\xd9\x74\x7b\x99\x13\xbc\xb9\x3a\x9f\xc0\xc2\xda\x66\x72\x78\xe8\x4f\xc4\xee\x18\x3d\x19\x67\x69\xb6\xc3\x81\x7f\x30\x9a\xa3\x8b\x45\x30\xe7\xee\x1c\xcd\xd4\x7d\xba\x1c\xee\xfe\x9e\x2c\xae\xc5\x52\xd8\x6e\xf1\xb9\xfb\x9c\x40\x3a\x8a\xe2\xa4\x28\x1e\xe1\xdb\x2a\x5f\xe8\xae\x4c\xf2\xf7\xc8\xac\x46\x69\x70\x7f\xdc\x76\x31\x70\xde\x3d\x30\x21\xf8\x1b\x89\x27\x8e\x2e\x14\xb0\x5a\xcc\xe7\xa4\x89\x77\xdd\x60\x69\x63\x77\x18\xe9\x3a\x22\x0f\x5d\x4b\x3c\x67\x58\x13\x72\x50\xb2\xde\xba\x4e\xdb\xf5\xc9\xee\x95\x6d\xe7\xd2\xef\xaa\xaf\x08\xf9\x63\xf5\x51\xd6\x6b\xbf\x70\x95\x78\xe8\x7b\xa3\x54\x0d\x4b\xdc\xec\x71\x69\x15\x18\x92\xdc\x61\xf2\xc1\x32\xb5\xf2\x2c\xb0\xc4\xcd\x1e\x9e\x71\x9f\xd3\xef\xab\xf4\xf7\x9a\x15\xd6\x5e\xef\xb6\xeb\x1d\x74\x0e\xb2\x56\x6b\xff\xf8\xf3\x40\x62\x81\x06\x4a\x22\x09\x9c\x2c\x31\xeb\xd3\xb4\x53\xe0\xec\xb9\x5d\x31\xee\x23\x38\x15\xc6\xa3\xc5\x6b\x34\x6a\xf9\x04\x6d\x06\xb8\x7a\x78\xfd\x05\xbb\xf1\x1e\x61\x23\x5c\x87\x6d\xa6\x4a\xd5\x47\xcc\x31\xca\x6b\xe9\x34\xf1\x09\x58\xdd\x92\xeb\x35\x94\x5b\xe0\x54\xb6\xf3\x79\xcf\x66\xae\x05\x3c\x77\xcc\x15\x38\x23\x03\x3f\xdb\xb5\x5a\xd3\x68\x55\xf9\xf2\xec\x45\x1c\x4f\xba\xd1\x09\x54\x58\x1b\x1a\x0c\xba\xdd\xbd\x7f\x50\x6c\x34\x31\xb5\xf4\x48\xf3\x06\xff\x1d\x00\x00\xff\xff\xf9\xd1\x4a\xaf\x45\x15\x00\x00") func goCentrifugeBuildConfigsDefault_configYamlBytes() ([]byte, error) { return bindataRead( @@ -84,7 +84,7 @@ func goCentrifugeBuildConfigsDefault_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5679, mode: os.FileMode(420), modTime: time.Unix(1551869118, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/default_config.yaml", size: 5445, mode: os.FileMode(420), modTime: time.Unix(1551950596, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -104,7 +104,7 @@ func goCentrifugeBuildConfigsTesting_configYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1076, mode: os.FileMode(420), modTime: time.Unix(1551869111, 0)} + info := bindataFileInfo{name: "go-centrifuge/build/configs/testing_config.yaml", size: 1076, mode: os.FileMode(420), modTime: time.Unix(1551953677, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -204,6 +204,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "go-centrifuge": &bintree{nil, map[string]*bintree{ "build": &bintree{nil, map[string]*bintree{ @@ -261,4 +262,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/testworld/nft_test.go b/testworld/nft_test.go index e0bcba91a..11c02d37c 100644 --- a/testworld/nft_test.go +++ b/testworld/nft_test.go @@ -100,7 +100,7 @@ func paymentObligationMint(t *testing.T, documentType string, grantNFTAccess, to "identifier": docIdentifier, "registryAddress": doctorFord.getHost("Alice").config.GetContractAddress(config.PaymentObligation).String(), "depositAddress": "0x44a0579754d6c94e7bb2c26bfa7394311cc50ccb", // Centrifuge address - "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", documents.CDTreePrefix + ".next_version"}, + "proofFields": []string{proofPrefix + ".gross_amount", proofPrefix + ".currency", proofPrefix + ".due_date", proofPrefix + ".sender", proofPrefix + ".invoice_status", documents.CDTreePrefix + ".next_version"}, "submitTokenProof": tokenProof, "submitNftOwnerAccessProof": nftReadAccessProof, "grantNftAccess": grantNFTAccess, diff --git a/testworld/payloads.go b/testworld/payloads.go index 8084f79bd..f946747a6 100644 --- a/testworld/payloads.go +++ b/testworld/payloads.go @@ -51,6 +51,8 @@ func invoiceNFTPayload(collaborators []string) map[string]interface{} { "currency": "USD", "net_amount": "40", "document_type": "invoice", + "sender": collaborators[0], + "invoice_status": "unpaid", }, "collaborators": collaborators, } From b4d2e4f4a9daf6739aee1f3cd19acfff8eab9f38 Mon Sep 17 00:00:00 2001 From: Charly Date: Thu, 7 Mar 2019 15:01:16 +0100 Subject: [PATCH 220/220] updated protos removing unused access token field (#822) * updated protos removing unused access token field * regenerate swagger --- protobufs/gen/go/invoice/service.pb.go | 164 ++++++++--------- protobufs/gen/go/purchaseorder/service.pb.go | 169 ++++++++---------- protobufs/gen/swagger.json | 2 +- .../gen/swagger/invoice/service.swagger.json | 29 --- .../purchaseorder/service.swagger.json | 29 --- protobufs/invoice/service.proto | 2 - protobufs/purchaseorder/service.proto | 2 - 7 files changed, 156 insertions(+), 241 deletions(-) diff --git a/protobufs/gen/go/invoice/service.pb.go b/protobufs/gen/go/invoice/service.pb.go index 1e5372d8b..d18ce8226 100644 --- a/protobufs/gen/go/invoice/service.pb.go +++ b/protobufs/gen/go/invoice/service.pb.go @@ -6,7 +6,6 @@ package invoicepb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" -import document "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" import timestamp "github.com/golang/protobuf/ptypes/timestamp" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" @@ -38,7 +37,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{0} + return fileDescriptor_service_114606e088e3c0a1, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -77,7 +76,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{1} + return fileDescriptor_service_114606e088e3c0a1, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -123,7 +122,7 @@ func (m *InvoiceCreatePayload) Reset() { *m = InvoiceCreatePayload{} } func (m *InvoiceCreatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceCreatePayload) ProtoMessage() {} func (*InvoiceCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{2} + return fileDescriptor_service_114606e088e3c0a1, []int{2} } func (m *InvoiceCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceCreatePayload.Unmarshal(m, b) @@ -158,20 +157,19 @@ func (m *InvoiceCreatePayload) GetData() *InvoiceData { } type InvoiceUpdatePayload struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` - Data *InvoiceData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - AccessTokenPayload *document.UpdateAccessTokenPayload `protobuf:"bytes,4,opt,name=access_token_payload,json=accessTokenPayload,proto3" json:"access_token_payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + Data *InvoiceData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *InvoiceUpdatePayload) Reset() { *m = InvoiceUpdatePayload{} } func (m *InvoiceUpdatePayload) String() string { return proto.CompactTextString(m) } func (*InvoiceUpdatePayload) ProtoMessage() {} func (*InvoiceUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{3} + return fileDescriptor_service_114606e088e3c0a1, []int{3} } func (m *InvoiceUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceUpdatePayload.Unmarshal(m, b) @@ -212,13 +210,6 @@ func (m *InvoiceUpdatePayload) GetData() *InvoiceData { return nil } -func (m *InvoiceUpdatePayload) GetAccessTokenPayload() *document.UpdateAccessTokenPayload { - if m != nil { - return m.AccessTokenPayload - } - return nil -} - type InvoiceResponse struct { Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Data *InvoiceData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -231,7 +222,7 @@ func (m *InvoiceResponse) Reset() { *m = InvoiceResponse{} } func (m *InvoiceResponse) String() string { return proto.CompactTextString(m) } func (*InvoiceResponse) ProtoMessage() {} func (*InvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{4} + return fileDescriptor_service_114606e088e3c0a1, []int{4} } func (m *InvoiceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceResponse.Unmarshal(m, b) @@ -281,7 +272,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{5} + return fileDescriptor_service_114606e088e3c0a1, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -379,7 +370,7 @@ func (m *InvoiceData) Reset() { *m = InvoiceData{} } func (m *InvoiceData) String() string { return proto.CompactTextString(m) } func (*InvoiceData) ProtoMessage() {} func (*InvoiceData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_493cda4133eb71cc, []int{6} + return fileDescriptor_service_114606e088e3c0a1, []int{6} } func (m *InvoiceData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InvoiceData.Unmarshal(m, b) @@ -748,70 +739,67 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ Metadata: "invoice/service.proto", } -func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_493cda4133eb71cc) } - -var fileDescriptor_service_493cda4133eb71cc = []byte{ - // 983 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x5f, 0x6f, 0x1b, 0x45, - 0x10, 0x97, 0x93, 0xd4, 0x89, 0xc7, 0x71, 0xd2, 0x6c, 0x9d, 0xe4, 0x72, 0x6a, 0xc9, 0xd5, 0x14, - 0x64, 0x4a, 0x6b, 0x4b, 0x41, 0x08, 0x81, 0xc4, 0x83, 0x9b, 0x4a, 0x21, 0x0f, 0x54, 0xd1, 0x25, - 0xf0, 0xd0, 0x17, 0x6b, 0xbd, 0x37, 0x76, 0x4f, 0xf8, 0x76, 0x8f, 0xdb, 0x75, 0x88, 0x5b, 0xf5, - 0x05, 0xf1, 0x09, 0x02, 0xdf, 0x84, 0x8f, 0xc2, 0x2b, 0x8f, 0x7c, 0x06, 0x9e, 0xd1, 0xfe, 0xf3, - 0xdf, 0x28, 0xa1, 0x4f, 0xa7, 0xfd, 0xcd, 0x6f, 0x67, 0x7e, 0x33, 0x37, 0x3b, 0x03, 0xbb, 0x29, - 0xbf, 0x14, 0x29, 0xc3, 0xb6, 0xc4, 0xe2, 0x32, 0x65, 0xd8, 0xca, 0x0b, 0xa1, 0x04, 0x59, 0x77, - 0x70, 0xb8, 0x97, 0x08, 0x36, 0xca, 0x90, 0xab, 0x79, 0x42, 0xf8, 0x70, 0x20, 0xc4, 0x60, 0x88, - 0x6d, 0x9a, 0xa7, 0x6d, 0xca, 0xb9, 0x50, 0x54, 0xa5, 0x82, 0x4b, 0x67, 0x3d, 0x74, 0x56, 0x73, - 0xea, 0x8d, 0xfa, 0x6d, 0x95, 0x66, 0x28, 0x15, 0xcd, 0x72, 0x47, 0x78, 0x66, 0x3e, 0xec, 0xf9, - 0x00, 0xf9, 0x73, 0xf9, 0x0b, 0x1d, 0x0c, 0xb0, 0x68, 0x8b, 0xdc, 0xb8, 0x58, 0x76, 0xd7, 0x78, - 0x06, 0x70, 0x82, 0x2a, 0xc6, 0x9f, 0x47, 0x28, 0x15, 0xf9, 0x08, 0x20, 0x4d, 0x90, 0xab, 0xb4, - 0x9f, 0x62, 0x11, 0x94, 0xa2, 0x52, 0xb3, 0x12, 0xcf, 0x20, 0x8d, 0xef, 0x61, 0xe7, 0x04, 0xd5, - 0x8f, 0x58, 0xc8, 0x54, 0xf0, 0xff, 0x79, 0x89, 0x04, 0xb0, 0x7e, 0x69, 0x6f, 0x04, 0x2b, 0xc6, - 0xe8, 0x8f, 0x8d, 0x3e, 0xd4, 0x4f, 0x6d, 0x31, 0x8e, 0x0b, 0xa4, 0x0a, 0xcf, 0xe8, 0x78, 0x28, - 0x68, 0x42, 0x9e, 0x40, 0x8d, 0x89, 0xe1, 0x90, 0xf6, 0x44, 0x41, 0x95, 0x28, 0x64, 0x50, 0x8a, - 0x56, 0x9b, 0x95, 0x78, 0x1e, 0x24, 0x4d, 0x58, 0x4b, 0xa8, 0xa2, 0xc6, 0x69, 0xf5, 0xa8, 0xde, - 0x72, 0x75, 0x6d, 0x39, 0x97, 0x2f, 0xa9, 0xa2, 0xb1, 0x61, 0x34, 0xfe, 0x2e, 0x4d, 0x02, 0xfd, - 0x90, 0x27, 0x33, 0x81, 0xee, 0x92, 0xbe, 0x24, 0x64, 0xe5, 0x36, 0x21, 0xab, 0x77, 0x09, 0x21, - 0x17, 0x50, 0xa7, 0x8c, 0xa1, 0x94, 0x5d, 0x25, 0x7e, 0x42, 0xde, 0xcd, 0xad, 0x8e, 0x60, 0xcd, - 0xdc, 0x6c, 0xb4, 0x7c, 0x47, 0xb4, 0xac, 0xcc, 0x8e, 0xe1, 0x5e, 0x68, 0xaa, 0x53, 0x1c, 0x13, - 0xba, 0x84, 0x35, 0x86, 0xb0, 0xed, 0x42, 0xc5, 0x28, 0x73, 0xc1, 0x25, 0x92, 0x36, 0x94, 0xdf, - 0x20, 0x4d, 0x5c, 0x52, 0xd5, 0xa3, 0xfd, 0x89, 0x28, 0x4f, 0xf9, 0xce, 0x98, 0x63, 0x47, 0xfb, - 0x80, 0x62, 0xfe, 0x59, 0x82, 0xad, 0x79, 0x27, 0xe4, 0x10, 0xaa, 0x5e, 0x79, 0x37, 0x4d, 0x7c, - 0x1d, 0x3d, 0x74, 0x9a, 0x90, 0x47, 0x00, 0xee, 0x9f, 0x6b, 0xbb, 0xed, 0x82, 0x8a, 0x43, 0x4e, - 0x13, 0x52, 0x87, 0x7b, 0x52, 0x51, 0x85, 0xa6, 0x82, 0x95, 0xd8, 0x1e, 0x96, 0x8b, 0xbf, 0x76, - 0x53, 0xf1, 0x3f, 0x81, 0x2d, 0x55, 0x50, 0x2e, 0x29, 0x53, 0xce, 0xfd, 0x3d, 0xe3, 0xa4, 0x36, - 0x83, 0x9e, 0x26, 0x8d, 0x7f, 0xcb, 0x50, 0x9d, 0xc9, 0x45, 0x5f, 0x73, 0x29, 0x76, 0x75, 0xb4, - 0x91, 0x0c, 0x0e, 0xec, 0x35, 0x87, 0x9e, 0x1b, 0x70, 0x96, 0xc6, 0x47, 0x59, 0x6f, 0xd2, 0x24, - 0x9e, 0xf6, 0xca, 0x80, 0xba, 0x00, 0x12, 0x79, 0x82, 0x45, 0x97, 0xd3, 0xcc, 0xa7, 0x01, 0x16, - 0x7a, 0x45, 0x33, 0x24, 0x1f, 0x43, 0xcd, 0x11, 0xa4, 0x2a, 0x10, 0x95, 0xf9, 0xe3, 0x95, 0x78, - 0xd3, 0x82, 0xe7, 0x06, 0x9b, 0xf1, 0xc2, 0x52, 0x35, 0x76, 0x79, 0x38, 0x2f, 0xc7, 0xa9, 0x1a, - 0x6b, 0x35, 0x8e, 0xf0, 0x36, 0xcd, 0x99, 0x48, 0x30, 0x28, 0x5b, 0x35, 0x16, 0x7d, 0x6d, 0xc1, - 0x19, 0x1a, 0x13, 0x23, 0xae, 0x8a, 0x71, 0xb0, 0x3e, 0x4b, 0x3b, 0xb6, 0xa0, 0xa6, 0x15, 0xc8, - 0xd2, 0x3c, 0xd5, 0xbf, 0xcd, 0xe8, 0xde, 0xb0, 0xb4, 0x09, 0x6a, 0xa4, 0x7f, 0x06, 0xf7, 0xa7, - 0x34, 0xa7, 0xbe, 0x62, 0x88, 0xdb, 0x13, 0xdc, 0x25, 0x30, 0xe7, 0xd1, 0xe4, 0x00, 0x0b, 0x1e, - 0x4d, 0x1a, 0x9f, 0xc3, 0xce, 0x94, 0xe6, 0x33, 0xa9, 0x1a, 0xe6, 0x34, 0x94, 0x4f, 0x66, 0x8e, - 0xec, 0xf3, 0xd9, 0x5c, 0x20, 0xfb, 0x94, 0x42, 0xd8, 0x60, 0xa3, 0xa2, 0x40, 0xce, 0xc6, 0x41, - 0xcd, 0x70, 0x26, 0x67, 0xf2, 0x18, 0x36, 0x07, 0x85, 0x90, 0xb2, 0x4b, 0x33, 0xcd, 0x0e, 0xb6, - 0xa2, 0x52, 0x73, 0x35, 0xae, 0x1a, 0xac, 0x63, 0x20, 0xdd, 0xa6, 0x1c, 0x95, 0x27, 0x6c, 0x1b, - 0x42, 0x85, 0xa3, 0x9a, 0x9a, 0x15, 0xbd, 0xf2, 0xe6, 0xfb, 0xd6, 0xac, 0xe8, 0x95, 0x33, 0x1f, - 0xc0, 0x86, 0x36, 0x17, 0xba, 0x91, 0x77, 0x8c, 0x71, 0x5d, 0xd1, 0xab, 0x58, 0xb7, 0xf2, 0x43, - 0xa8, 0x4c, 0xb4, 0x06, 0xc4, 0xb6, 0xff, 0x04, 0x20, 0x7b, 0x50, 0xb6, 0x7f, 0x26, 0x78, 0x60, - 0x4c, 0xee, 0xa4, 0x9f, 0x45, 0x4e, 0xc7, 0x88, 0x41, 0xdd, 0x3e, 0x0b, 0x73, 0xd0, 0xe3, 0x94, - 0x89, 0x4c, 0x3f, 0xac, 0x60, 0xd7, 0x8e, 0x53, 0x77, 0x24, 0x5f, 0xc2, 0x46, 0x32, 0xc2, 0xae, - 0x9e, 0x1c, 0xc1, 0x9e, 0x79, 0xc7, 0x61, 0xcb, 0x6e, 0x8b, 0x96, 0xdf, 0x16, 0xad, 0x0b, 0xbf, - 0x2d, 0xe2, 0xf5, 0x64, 0xa4, 0x9f, 0x02, 0x92, 0x6f, 0x61, 0x53, 0x5f, 0xe9, 0x32, 0x33, 0x83, - 0x93, 0x60, 0xff, 0xce, 0xab, 0x55, 0xcd, 0xb7, 0x23, 0xdb, 0xbc, 0x6d, 0xbc, 0x52, 0x05, 0xed, - 0x9a, 0xf9, 0x11, 0xd8, 0xe4, 0x0c, 0xa2, 0x1f, 0xda, 0xd1, 0x6f, 0x6b, 0xb0, 0xfd, 0xd2, 0x4d, - 0x82, 0x73, 0xbb, 0xe7, 0x48, 0x06, 0x65, 0x7b, 0x9b, 0x3c, 0x5a, 0x1c, 0x34, 0x73, 0x8b, 0x20, - 0x0c, 0x16, 0xcd, 0x7e, 0xf0, 0x34, 0x9e, 0x5e, 0x77, 0xea, 0x21, 0xb1, 0x6c, 0x19, 0x51, 0x1e, - 0x39, 0xe2, 0xaf, 0x7f, 0xfd, 0xf3, 0xfb, 0x4a, 0xad, 0xb1, 0xd1, 0x76, 0xe7, 0x6f, 0x4a, 0x4f, - 0xc9, 0x5b, 0x28, 0xdb, 0x79, 0xba, 0x1c, 0x6e, 0x6e, 0x1d, 0xdc, 0x12, 0xee, 0x2b, 0x13, 0xce, - 0xb2, 0x97, 0xc2, 0x85, 0xe1, 0xae, 0x0f, 0xd7, 0x7e, 0x37, 0xdd, 0x1e, 0xef, 0x75, 0xec, 0x3f, - 0x4a, 0x66, 0xc1, 0xba, 0x95, 0x49, 0xc2, 0x49, 0x84, 0xa5, 0x3d, 0x7a, 0x4b, 0xf4, 0xb3, 0xeb, - 0xce, 0xa7, 0xe1, 0x93, 0x13, 0x54, 0x11, 0x8d, 0x64, 0x8e, 0x2c, 0xed, 0xa7, 0x2c, 0x72, 0xe3, - 0x33, 0x12, 0xfd, 0x45, 0x3d, 0x8f, 0xc9, 0xe1, 0x8d, 0x7a, 0xda, 0xef, 0xdc, 0x9d, 0xf7, 0x44, - 0xc0, 0xea, 0x09, 0x2a, 0xf2, 0x60, 0x56, 0xce, 0xdd, 0x3a, 0xbe, 0xbe, 0xee, 0x1c, 0x84, 0xfb, - 0x5a, 0x87, 0x7a, 0x83, 0x91, 0x7d, 0x59, 0x6a, 0x2e, 0xf4, 0x3e, 0xb9, 0xb9, 0x14, 0x2f, 0x9a, - 0x50, 0x65, 0x22, 0xf3, 0x9e, 0x5f, 0x6c, 0xba, 0x56, 0x38, 0xd3, 0xcd, 0x75, 0x56, 0x7a, 0x5d, - 0x71, 0x86, 0xbc, 0xd7, 0x2b, 0x9b, 0x86, 0xfb, 0xe2, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdd, - 0x1f, 0x15, 0x2c, 0x3f, 0x09, 0x00, 0x00, +func init() { proto.RegisterFile("invoice/service.proto", fileDescriptor_service_114606e088e3c0a1) } + +var fileDescriptor_service_114606e088e3c0a1 = []byte{ + // 939 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0x1b, 0x45, + 0x1b, 0x96, 0x93, 0xd4, 0x3f, 0xaf, 0xed, 0xa4, 0x99, 0x3a, 0xcd, 0x66, 0xd5, 0x7e, 0xd9, 0xfa, + 0x2b, 0xc8, 0x94, 0xd6, 0x96, 0x82, 0x10, 0x02, 0x89, 0x83, 0x34, 0x95, 0x42, 0x0e, 0xa8, 0xa2, + 0x0d, 0x70, 0xd0, 0x13, 0x6b, 0xbc, 0xfb, 0xda, 0x1d, 0xc9, 0x3b, 0xb3, 0xcc, 0x8c, 0x43, 0xdc, + 0xaa, 0x27, 0x08, 0x71, 0x01, 0x81, 0x3b, 0xe1, 0x52, 0xb8, 0x05, 0xae, 0x81, 0x63, 0x34, 0x3f, + 0xeb, 0xdf, 0x28, 0x81, 0xa3, 0xd5, 0x3c, 0xef, 0xf3, 0xfe, 0x3c, 0xf3, 0xf3, 0x2c, 0xec, 0x31, + 0x7e, 0x29, 0x58, 0x82, 0x3d, 0x85, 0xf2, 0x92, 0x25, 0xd8, 0xcd, 0xa5, 0xd0, 0x82, 0x54, 0x3c, + 0x1c, 0x3e, 0x1a, 0x09, 0x31, 0x1a, 0x63, 0x8f, 0xe6, 0xac, 0x47, 0x39, 0x17, 0x9a, 0x6a, 0x26, + 0xb8, 0x72, 0xb4, 0xf0, 0xd0, 0x47, 0xed, 0x6a, 0x30, 0x19, 0xf6, 0x34, 0xcb, 0x50, 0x69, 0x9a, + 0xe5, 0x9e, 0xf0, 0xdc, 0x7e, 0x92, 0x17, 0x23, 0xe4, 0x2f, 0xd4, 0x4f, 0x74, 0x34, 0x42, 0xd9, + 0x13, 0xb9, 0x2d, 0xb1, 0x5e, 0xae, 0xfd, 0x1c, 0xe0, 0x14, 0x75, 0x8c, 0x3f, 0x4e, 0x50, 0x69, + 0xf2, 0x3f, 0x00, 0x96, 0x22, 0xd7, 0x6c, 0xc8, 0x50, 0x06, 0xa5, 0xa8, 0xd4, 0xa9, 0xc5, 0x0b, + 0x48, 0xfb, 0x5b, 0xd8, 0x3d, 0x45, 0xfd, 0x03, 0x4a, 0xc5, 0x04, 0xff, 0x97, 0x49, 0x24, 0x80, + 0xca, 0xa5, 0xcb, 0x08, 0x36, 0x6c, 0xb0, 0x58, 0xb6, 0x87, 0xd0, 0x3a, 0x73, 0xa2, 0x4f, 0x24, + 0x52, 0x8d, 0xe7, 0x74, 0x3a, 0x16, 0x34, 0x25, 0x4f, 0xa1, 0x99, 0x88, 0xf1, 0x98, 0x0e, 0x84, + 0xa4, 0x5a, 0x48, 0x15, 0x94, 0xa2, 0xcd, 0x4e, 0x2d, 0x5e, 0x06, 0x49, 0x07, 0xb6, 0x52, 0xaa, + 0xa9, 0x2d, 0x5a, 0x3f, 0x6a, 0x75, 0xfd, 0xfe, 0x75, 0x7d, 0xc9, 0x57, 0x54, 0xd3, 0xd8, 0x32, + 0xda, 0xbf, 0x96, 0x66, 0x8d, 0xbe, 0xcf, 0xd3, 0x85, 0x46, 0x77, 0x8d, 0xbe, 0x36, 0xc8, 0xc6, + 0x6d, 0x83, 0x6c, 0xde, 0x39, 0xc8, 0x18, 0x76, 0x3c, 0x18, 0xa3, 0xca, 0x05, 0x57, 0x48, 0x7a, + 0x50, 0x7e, 0x8b, 0x34, 0xf5, 0xed, 0xeb, 0x47, 0xfb, 0xb3, 0xf4, 0x82, 0xf2, 0x8d, 0x0d, 0xc7, + 0x9e, 0xf6, 0x1f, 0x64, 0xff, 0x51, 0x82, 0xed, 0xe5, 0x22, 0xe4, 0x10, 0xea, 0xa9, 0x48, 0x26, + 0x19, 0x72, 0xdd, 0x67, 0x69, 0xa1, 0xb8, 0x80, 0xce, 0x52, 0xf2, 0x18, 0xc0, 0x9f, 0x8e, 0x89, + 0xbb, 0xf3, 0xaa, 0x79, 0xe4, 0x2c, 0x25, 0x2d, 0xb8, 0xa7, 0x34, 0xd5, 0x68, 0xb5, 0xd6, 0x62, + 0xb7, 0x58, 0xdf, 0xa6, 0xad, 0x9b, 0xb6, 0xe9, 0x23, 0xd8, 0xd6, 0x92, 0x72, 0x45, 0x13, 0xed, + 0xcb, 0xdf, 0xb3, 0x45, 0x9a, 0x0b, 0xe8, 0x59, 0xda, 0xfe, 0xbb, 0x0c, 0xf5, 0x05, 0x2d, 0x26, + 0xcd, 0x4b, 0xec, 0x9b, 0x6e, 0x13, 0x15, 0x1c, 0xb8, 0x34, 0x8f, 0x5e, 0x58, 0x70, 0x91, 0xc6, + 0x27, 0xd9, 0x60, 0x76, 0x9c, 0x05, 0xed, 0xb5, 0x05, 0xcd, 0x06, 0x28, 0xe4, 0x29, 0xca, 0x3e, + 0xa7, 0x59, 0x21, 0x03, 0x1c, 0xf4, 0x9a, 0x66, 0x48, 0xfe, 0x0f, 0x4d, 0x4f, 0x50, 0x5a, 0x22, + 0xea, 0x60, 0xcb, 0x52, 0x1a, 0x0e, 0xbc, 0xb0, 0xd8, 0x42, 0x95, 0x84, 0xe9, 0xa9, 0xd7, 0xe1, + 0xab, 0x9c, 0x30, 0x3d, 0x35, 0xd3, 0x78, 0xc2, 0x3b, 0x96, 0x27, 0x22, 0xc5, 0xa0, 0xec, 0xa6, + 0x71, 0xe8, 0x1b, 0x07, 0x2e, 0xd0, 0x12, 0x31, 0xe1, 0x5a, 0x4e, 0x83, 0xca, 0x22, 0xed, 0xc4, + 0x81, 0x86, 0x26, 0x31, 0x61, 0x39, 0x33, 0xc7, 0x66, 0xe7, 0xae, 0x3a, 0xda, 0x0c, 0xb5, 0xa3, + 0x7f, 0x02, 0xf7, 0xe7, 0x34, 0x3f, 0x7d, 0xcd, 0x12, 0x77, 0x66, 0xb8, 0x17, 0xb0, 0x54, 0xd1, + 0x6a, 0x80, 0x95, 0x8a, 0x56, 0xc6, 0xa7, 0xb0, 0x3b, 0xa7, 0x15, 0x4a, 0xea, 0x96, 0x39, 0x6f, + 0x55, 0x88, 0x59, 0x22, 0x17, 0x7a, 0x1a, 0x2b, 0xe4, 0x42, 0x52, 0x08, 0xd5, 0x64, 0x22, 0x25, + 0xf2, 0x64, 0x1a, 0x34, 0x2d, 0x67, 0xb6, 0x26, 0x4f, 0xa0, 0x31, 0x92, 0x42, 0xa9, 0x3e, 0xcd, + 0x0c, 0x3b, 0xd8, 0x8e, 0x4a, 0x9d, 0xcd, 0xb8, 0x6e, 0xb1, 0x63, 0x0b, 0x99, 0x6b, 0xca, 0x51, + 0x17, 0x84, 0x1d, 0x4b, 0xa8, 0x71, 0xd4, 0xf3, 0xb0, 0xa6, 0x57, 0x45, 0xf8, 0xbe, 0x0b, 0x6b, + 0x7a, 0xe5, 0xc3, 0x07, 0x50, 0x35, 0x61, 0x69, 0x2e, 0xf2, 0xae, 0x0d, 0x56, 0x34, 0xbd, 0x8a, + 0xcd, 0x55, 0x7e, 0x04, 0xb5, 0xd9, 0xac, 0x01, 0x71, 0xd7, 0x7f, 0x06, 0x90, 0x87, 0x50, 0x76, + 0x27, 0x13, 0x3c, 0xb0, 0x21, 0xbf, 0x32, 0xcf, 0x22, 0xa7, 0x53, 0xc4, 0xa0, 0xe5, 0x9e, 0x85, + 0x5d, 0x18, 0xe3, 0x4b, 0x44, 0x66, 0x1e, 0x56, 0xb0, 0xe7, 0x8c, 0xcf, 0x2f, 0xc9, 0xe7, 0x50, + 0x4d, 0x27, 0xd8, 0x37, 0x56, 0x14, 0x3c, 0xb4, 0xef, 0x38, 0xec, 0x3a, 0x5f, 0xef, 0x16, 0xbe, + 0xde, 0xfd, 0xae, 0xf0, 0xf5, 0xb8, 0x92, 0x4e, 0xcc, 0x53, 0x40, 0xf2, 0x35, 0x34, 0x4c, 0x4a, + 0x3f, 0xb1, 0x6e, 0x99, 0x06, 0xfb, 0x77, 0xa6, 0xd6, 0x0d, 0xdf, 0x99, 0xab, 0x7d, 0xdb, 0x78, + 0xa5, 0x25, 0xed, 0x5b, 0xff, 0x08, 0x9c, 0x38, 0x8b, 0x98, 0x87, 0x76, 0xf4, 0xcb, 0x16, 0xec, + 0xbc, 0xf2, 0x4e, 0x70, 0xe1, 0x7e, 0x4d, 0x24, 0x83, 0xb2, 0xcb, 0x26, 0x8f, 0x57, 0x8d, 0x66, + 0xc9, 0xb2, 0xc3, 0x60, 0x35, 0x5c, 0x18, 0x4f, 0xfb, 0xd9, 0xf5, 0x71, 0x2b, 0x24, 0x8e, 0xad, + 0x22, 0xca, 0x23, 0x4f, 0xfc, 0xf9, 0xcf, 0xbf, 0x7e, 0xdb, 0x68, 0xb6, 0xab, 0x3d, 0xbf, 0xfe, + 0xaa, 0xf4, 0x8c, 0xbc, 0x83, 0xb2, 0x33, 0xe8, 0xf5, 0x76, 0x4b, 0xc6, 0x7d, 0x4b, 0xbb, 0x2f, + 0x6c, 0x3b, 0xc7, 0x5e, 0x6b, 0x17, 0x86, 0x7b, 0x45, 0xbb, 0xde, 0xfb, 0xb9, 0xcf, 0x7f, 0x30, + 0xbd, 0x7f, 0x2f, 0xd9, 0x5f, 0xa1, 0xff, 0xb9, 0x91, 0x70, 0xd6, 0x61, 0xed, 0x8f, 0x77, 0x4b, + 0xf7, 0xf3, 0xeb, 0xe3, 0x8f, 0xc3, 0xa7, 0xa7, 0xa8, 0x23, 0x1a, 0xa9, 0x1c, 0x13, 0x36, 0x64, + 0x49, 0xe4, 0xed, 0x33, 0x12, 0xc3, 0xd5, 0x79, 0x9e, 0x90, 0xc3, 0x1b, 0xe7, 0xe9, 0xbd, 0xf7, + 0x39, 0x1f, 0x88, 0x80, 0xcd, 0x53, 0xd4, 0xe4, 0xc1, 0xe2, 0x38, 0x77, 0xcf, 0xf1, 0xe5, 0xf5, + 0xf1, 0x41, 0xb8, 0x6f, 0xe6, 0xd0, 0x6f, 0x31, 0x72, 0x2f, 0x4b, 0x2f, 0xb5, 0xde, 0x27, 0x37, + 0x6f, 0xc5, 0xcb, 0x0e, 0xd4, 0x13, 0x91, 0x15, 0x95, 0x5f, 0x36, 0xfc, 0x55, 0x38, 0x37, 0x97, + 0xeb, 0xbc, 0xf4, 0xa6, 0xe6, 0x03, 0xf9, 0x60, 0x50, 0xb6, 0x17, 0xee, 0xb3, 0x7f, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x0c, 0x8d, 0xd7, 0x8a, 0xd1, 0x08, 0x00, 0x00, } diff --git a/protobufs/gen/go/purchaseorder/service.pb.go b/protobufs/gen/go/purchaseorder/service.pb.go index 184716ea1..d1b20e857 100644 --- a/protobufs/gen/go/purchaseorder/service.pb.go +++ b/protobufs/gen/go/purchaseorder/service.pb.go @@ -6,7 +6,6 @@ package purchaseorderpb import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" -import document "github.com/centrifuge/go-centrifuge/protobufs/gen/go/document" import timestamp "github.com/golang/protobuf/ptypes/timestamp" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" @@ -38,7 +37,7 @@ func (m *GetRequest) Reset() { *m = GetRequest{} } func (m *GetRequest) String() string { return proto.CompactTextString(m) } func (*GetRequest) ProtoMessage() {} func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{0} + return fileDescriptor_service_393a7cd179a9d71e, []int{0} } func (m *GetRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetRequest.Unmarshal(m, b) @@ -77,7 +76,7 @@ func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{1} + return fileDescriptor_service_393a7cd179a9d71e, []int{1} } func (m *GetVersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetVersionRequest.Unmarshal(m, b) @@ -123,7 +122,7 @@ func (m *PurchaseOrderCreatePayload) Reset() { *m = PurchaseOrderCreateP func (m *PurchaseOrderCreatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderCreatePayload) ProtoMessage() {} func (*PurchaseOrderCreatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{2} + return fileDescriptor_service_393a7cd179a9d71e, []int{2} } func (m *PurchaseOrderCreatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderCreatePayload.Unmarshal(m, b) @@ -158,20 +157,19 @@ func (m *PurchaseOrderCreatePayload) GetData() *PurchaseOrderData { } type PurchaseOrderUpdatePayload struct { - Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` - Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` - Data *PurchaseOrderData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - AccessTokenPayload *document.UpdateAccessTokenPayload `protobuf:"bytes,4,opt,name=access_token_payload,json=accessTokenPayload,proto3" json:"access_token_payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` + Collaborators []string `protobuf:"bytes,2,rep,name=collaborators,proto3" json:"collaborators,omitempty"` + Data *PurchaseOrderData `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *PurchaseOrderUpdatePayload) Reset() { *m = PurchaseOrderUpdatePayload{} } func (m *PurchaseOrderUpdatePayload) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderUpdatePayload) ProtoMessage() {} func (*PurchaseOrderUpdatePayload) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{3} + return fileDescriptor_service_393a7cd179a9d71e, []int{3} } func (m *PurchaseOrderUpdatePayload) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderUpdatePayload.Unmarshal(m, b) @@ -212,13 +210,6 @@ func (m *PurchaseOrderUpdatePayload) GetData() *PurchaseOrderData { return nil } -func (m *PurchaseOrderUpdatePayload) GetAccessTokenPayload() *document.UpdateAccessTokenPayload { - if m != nil { - return m.AccessTokenPayload - } - return nil -} - type PurchaseOrderResponse struct { Header *ResponseHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Data *PurchaseOrderData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -231,7 +222,7 @@ func (m *PurchaseOrderResponse) Reset() { *m = PurchaseOrderResponse{} } func (m *PurchaseOrderResponse) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderResponse) ProtoMessage() {} func (*PurchaseOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{4} + return fileDescriptor_service_393a7cd179a9d71e, []int{4} } func (m *PurchaseOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderResponse.Unmarshal(m, b) @@ -281,7 +272,7 @@ func (m *ResponseHeader) Reset() { *m = ResponseHeader{} } func (m *ResponseHeader) String() string { return proto.CompactTextString(m) } func (*ResponseHeader) ProtoMessage() {} func (*ResponseHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{5} + return fileDescriptor_service_393a7cd179a9d71e, []int{5} } func (m *ResponseHeader) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResponseHeader.Unmarshal(m, b) @@ -382,7 +373,7 @@ func (m *PurchaseOrderData) Reset() { *m = PurchaseOrderData{} } func (m *PurchaseOrderData) String() string { return proto.CompactTextString(m) } func (*PurchaseOrderData) ProtoMessage() {} func (*PurchaseOrderData) Descriptor() ([]byte, []int) { - return fileDescriptor_service_a9b80dc96b015f6f, []int{6} + return fileDescriptor_service_393a7cd179a9d71e, []int{6} } func (m *PurchaseOrderData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PurchaseOrderData.Unmarshal(m, b) @@ -752,72 +743,70 @@ var _DocumentService_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_a9b80dc96b015f6f) -} - -var fileDescriptor_service_a9b80dc96b015f6f = []byte{ - // 1008 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdf, 0x6e, 0x1b, 0xc5, - 0x17, 0xd6, 0xe6, 0x8f, 0x13, 0x8f, 0xe3, 0xa4, 0x99, 0xa6, 0xfd, 0x6d, 0x37, 0xcd, 0xaf, 0x8b, - 0x69, 0x45, 0xda, 0x26, 0xb6, 0x14, 0x0a, 0x17, 0x48, 0x08, 0xa5, 0x89, 0x14, 0x72, 0x41, 0x89, - 0x36, 0x81, 0x8b, 0x0a, 0xc9, 0x1a, 0xcf, 0x9e, 0x38, 0x2b, 0xec, 0x9d, 0x65, 0x76, 0x1c, 0x6c, - 0xaa, 0xde, 0x20, 0x5e, 0x80, 0x70, 0x85, 0x90, 0x78, 0x08, 0x78, 0x14, 0x5e, 0x81, 0x6b, 0xee, - 0xb8, 0x47, 0x73, 0x66, 0xc6, 0xf6, 0xda, 0xc5, 0x49, 0xb9, 0x5a, 0xcd, 0x77, 0xbe, 0x73, 0xf6, - 0x3b, 0x67, 0xce, 0x9c, 0x43, 0x36, 0xb3, 0x9e, 0xe4, 0x17, 0x2c, 0x07, 0x21, 0x63, 0x90, 0x8d, - 0x1c, 0xe4, 0x65, 0xc2, 0xa1, 0x9e, 0x49, 0xa1, 0x04, 0xad, 0x16, 0x8c, 0xc1, 0xdd, 0x58, 0xf0, - 0x5e, 0x17, 0x52, 0x55, 0xa4, 0x05, 0xf7, 0xdb, 0x42, 0xb4, 0x3b, 0xd0, 0x60, 0x59, 0xd2, 0x60, - 0x69, 0x2a, 0x14, 0x53, 0x89, 0x48, 0x73, 0x6b, 0x7d, 0x60, 0xad, 0x78, 0x6a, 0xf5, 0xce, 0x1b, - 0x2a, 0xe9, 0x42, 0xae, 0x58, 0x37, 0xb3, 0x84, 0x1d, 0xfc, 0xf0, 0xdd, 0x36, 0xa4, 0xbb, 0xf9, - 0xb7, 0xac, 0xdd, 0x06, 0xd9, 0x10, 0x19, 0x86, 0x98, 0x0e, 0x57, 0xdb, 0x21, 0xe4, 0x08, 0x54, - 0x04, 0xdf, 0xf4, 0x20, 0x57, 0xf4, 0xff, 0x84, 0x24, 0x31, 0xa4, 0x2a, 0x39, 0x4f, 0x40, 0xfa, - 0x5e, 0xe8, 0x6d, 0x97, 0xa3, 0x31, 0xa4, 0xf6, 0x19, 0x59, 0x3f, 0x02, 0xf5, 0x25, 0xc8, 0x3c, - 0x11, 0xe9, 0x0d, 0x9d, 0xa8, 0x4f, 0x96, 0x2e, 0x8d, 0x87, 0x3f, 0x87, 0x46, 0x77, 0xac, 0xf5, - 0x49, 0x70, 0x62, 0x4b, 0xf2, 0xb9, 0x2e, 0xc9, 0x81, 0x04, 0xa6, 0xe0, 0x84, 0x0d, 0x3a, 0x82, - 0xc5, 0xf4, 0x21, 0xa9, 0x72, 0xd1, 0xe9, 0xb0, 0x96, 0x90, 0x4c, 0x09, 0x99, 0xfb, 0x5e, 0x38, - 0xbf, 0x5d, 0x8e, 0x8a, 0x20, 0x7d, 0x46, 0x16, 0x62, 0xa6, 0x18, 0x86, 0xae, 0xec, 0x85, 0xf5, - 0x42, 0x8d, 0xeb, 0x85, 0xf0, 0x87, 0x4c, 0xb1, 0x08, 0xd9, 0xb5, 0xbf, 0xbc, 0x89, 0x5f, 0x7f, - 0x91, 0xc5, 0x63, 0xbf, 0xbe, 0x2e, 0xa5, 0x29, 0x69, 0x73, 0xb3, 0xa4, 0xcd, 0xbf, 0x8d, 0x34, - 0x7a, 0x46, 0x36, 0x18, 0xe7, 0x90, 0xe7, 0x4d, 0x25, 0xbe, 0x86, 0xb4, 0x99, 0x19, 0x4d, 0xfe, - 0x02, 0x46, 0xa9, 0xd5, 0x5d, 0xd7, 0xd4, 0x8d, 0xe4, 0x7d, 0xe4, 0x9e, 0x69, 0xaa, 0x55, 0x1f, - 0x51, 0x36, 0x85, 0xd5, 0x7e, 0xf0, 0xc8, 0x9d, 0xc2, 0x1f, 0x23, 0xc8, 0x33, 0x91, 0xe6, 0x40, - 0x3f, 0x20, 0xa5, 0x0b, 0x60, 0xb1, 0xcd, 0xb3, 0xb2, 0xb7, 0x35, 0xa1, 0xd3, 0x11, 0x3f, 0x45, - 0x52, 0x64, 0xc9, 0xff, 0xb1, 0xee, 0xbf, 0x7b, 0x64, 0xb5, 0x18, 0x90, 0x3e, 0x20, 0x15, 0x97, - 0x52, 0x33, 0x89, 0x5d, 0xb1, 0x1d, 0x74, 0x1c, 0xd3, 0x2d, 0x42, 0x6c, 0xc3, 0x68, 0xbb, 0x69, - 0xa1, 0xb2, 0x45, 0x8e, 0x63, 0xba, 0x41, 0x16, 0x73, 0xc5, 0x14, 0x60, 0x99, 0xcb, 0x91, 0x39, - 0x4c, 0xdf, 0xd0, 0xc2, 0x9b, 0x6e, 0xe8, 0x11, 0x59, 0x55, 0x92, 0xa5, 0x39, 0xe3, 0xca, 0x86, - 0x5f, 0xc4, 0x20, 0xd5, 0x31, 0xf4, 0x38, 0xae, 0xfd, 0x5d, 0x22, 0xeb, 0x53, 0x19, 0xd1, 0x4d, - 0x52, 0xce, 0x44, 0x53, 0xff, 0xae, 0x97, 0xfb, 0x3e, 0xfa, 0x2d, 0x67, 0xe2, 0x14, 0xcf, 0xd6, - 0x98, 0xf6, 0xba, 0xad, 0x61, 0x03, 0x2d, 0x67, 0xe2, 0x05, 0x9e, 0x75, 0x46, 0x58, 0xa6, 0x66, - 0xca, 0xba, 0xe0, 0x32, 0x42, 0xe4, 0x05, 0xeb, 0x02, 0x7d, 0x87, 0xac, 0x18, 0x73, 0xae, 0x24, - 0x80, 0xb2, 0x89, 0x55, 0x10, 0x3b, 0x45, 0x68, 0x14, 0x81, 0x27, 0x6a, 0x80, 0xad, 0xe1, 0x22, - 0x1c, 0x24, 0x6a, 0x40, 0xdf, 0x25, 0x55, 0x63, 0xfe, 0x2e, 0xc9, 0xb8, 0x88, 0xc1, 0xa6, 0x65, - 0xc2, 0xbe, 0x34, 0xd8, 0x88, 0xc4, 0x45, 0x2f, 0x55, 0x72, 0xe0, 0x97, 0xc6, 0x48, 0x07, 0x06, - 0xd3, 0x15, 0x92, 0xc0, 0x93, 0x2c, 0xd1, 0xd7, 0x83, 0x72, 0x97, 0x4c, 0x85, 0x86, 0x28, 0x4a, - 0x7e, 0x4c, 0x6e, 0x8d, 0x68, 0x56, 0xf6, 0x32, 0x12, 0xd7, 0x86, 0xb8, 0x95, 0x5e, 0x88, 0x88, - 0xf2, 0xcb, 0x13, 0x11, 0x31, 0x85, 0xa7, 0x64, 0x7d, 0x44, 0x73, 0x69, 0x10, 0x64, 0x8e, 0x7e, - 0xe5, 0x52, 0x29, 0x90, 0x5d, 0x3a, 0x95, 0x09, 0xb2, 0x4b, 0x29, 0x20, 0xcb, 0xbc, 0x27, 0x25, - 0xa4, 0x7c, 0xe0, 0xaf, 0x98, 0x9b, 0x71, 0xe7, 0x51, 0xe9, 0x59, 0x57, 0xb3, 0xfd, 0x6a, 0xe8, - 0x6d, 0xcf, 0xdb, 0xd2, 0xef, 0x23, 0xa4, 0x4b, 0x9f, 0x82, 0x72, 0x84, 0x55, 0x24, 0x94, 0x53, - 0x50, 0x23, 0xb3, 0x62, 0x7d, 0x67, 0x5e, 0x33, 0x66, 0xc5, 0xfa, 0xd6, 0x7c, 0x8f, 0x2c, 0x6b, - 0xb3, 0xd4, 0x0d, 0x7b, 0x0b, 0x8d, 0x4b, 0x8a, 0xf5, 0x23, 0xdd, 0xb2, 0xf7, 0x49, 0x79, 0xa8, - 0xd5, 0x5f, 0x37, 0x57, 0x3a, 0x04, 0x74, 0x9b, 0xa3, 0x0a, 0x9f, 0x9a, 0x36, 0xc7, 0xc3, 0xf8, - 0x1d, 0xa6, 0x8a, 0x71, 0xe5, 0xdf, 0x2e, 0xdc, 0x21, 0x62, 0x7a, 0x00, 0x73, 0xd1, 0xd5, 0xaf, - 0xc9, 0xdf, 0x30, 0x03, 0xd8, 0x1e, 0xe9, 0x27, 0xa4, 0x1a, 0x43, 0x27, 0xb9, 0x04, 0x39, 0x68, - 0xea, 0x61, 0xe2, 0xdf, 0xc1, 0xd7, 0x1c, 0xd4, 0xcd, 0x92, 0xa9, 0xbb, 0x25, 0x53, 0x3f, 0x73, - 0x4b, 0x26, 0x5a, 0x71, 0x0e, 0x87, 0x5a, 0xf3, 0xc7, 0x64, 0x45, 0xfb, 0x35, 0x39, 0x4e, 0xee, - 0xd8, 0xbf, 0x7b, 0xad, 0x7f, 0x45, 0xf3, 0xcd, 0xa0, 0xc7, 0xa7, 0x0d, 0x7d, 0x25, 0x59, 0x13, - 0x47, 0xc9, 0xff, 0x4c, 0xce, 0x88, 0xe8, 0x17, 0xb6, 0xf7, 0xf3, 0x22, 0x59, 0x3b, 0xb4, 0x83, - 0xe0, 0xd4, 0xec, 0x48, 0xfa, 0xa3, 0x47, 0x4a, 0xc6, 0x9d, 0x3e, 0x9e, 0x35, 0x74, 0x0a, 0xbb, - 0x24, 0x78, 0x38, 0x8b, 0xea, 0x06, 0x52, 0xed, 0xc3, 0xab, 0xfd, 0x20, 0xf0, 0x8d, 0x67, 0x1e, - 0xb2, 0xd0, 0xf9, 0x84, 0xe8, 0xf4, 0xfd, 0x1f, 0x7f, 0xfe, 0x34, 0x77, 0xbb, 0xb6, 0xda, 0x28, - 0x84, 0xfa, 0xc8, 0x7b, 0x42, 0x7f, 0xf5, 0x48, 0xc9, 0x4c, 0xe3, 0xd9, 0x9a, 0x0a, 0x4b, 0xe6, - 0x86, 0x9a, 0x0e, 0x50, 0x93, 0xf1, 0xfc, 0x17, 0x4d, 0x61, 0xb0, 0x59, 0xd4, 0xd4, 0x78, 0x35, - 0xda, 0x55, 0xaf, 0xb5, 0xc0, 0xdf, 0x3c, 0x5c, 0xf3, 0x76, 0x71, 0xd3, 0xc9, 0x69, 0x3d, 0xb5, - 0xd3, 0x6f, 0xa8, 0xed, 0xab, 0xab, 0xfd, 0x9d, 0xe0, 0xc9, 0x11, 0xa8, 0x90, 0x85, 0x79, 0x06, - 0x3c, 0x39, 0x4f, 0x78, 0x68, 0x27, 0x73, 0x28, 0xce, 0xdf, 0xac, 0xf6, 0x3d, 0xfa, 0x68, 0x86, - 0xda, 0xc6, 0x2b, 0xeb, 0xff, 0x9a, 0xfe, 0xe2, 0x91, 0xf9, 0x23, 0x50, 0xf4, 0xde, 0xb4, 0xda, - 0xb7, 0x93, 0x79, 0x7a, 0xb5, 0xbf, 0x1b, 0x3c, 0xd5, 0x32, 0xd5, 0x05, 0x84, 0xe6, 0xad, 0xab, - 0x6b, 0x75, 0x6e, 0xd1, 0x59, 0x55, 0x7d, 0xfe, 0x8c, 0xac, 0x73, 0xd1, 0x2d, 0xfe, 0xff, 0xf9, - 0x8a, 0xed, 0xd2, 0x13, 0xdd, 0xf7, 0x27, 0xde, 0xcb, 0xb5, 0x82, 0x39, 0x6b, 0xb5, 0x4a, 0xf8, - 0x22, 0xde, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0x50, 0xe0, 0xb3, 0xc0, 0x28, 0x0a, 0x00, 0x00, + proto.RegisterFile("purchaseorder/service.proto", fileDescriptor_service_393a7cd179a9d71e) +} + +var fileDescriptor_service_393a7cd179a9d71e = []byte{ + // 963 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x5f, 0x6f, 0x1b, 0x45, + 0x10, 0xd7, 0xe5, 0x8f, 0x63, 0xaf, 0xed, 0xa4, 0xde, 0xb6, 0x70, 0xbd, 0x34, 0xf4, 0x30, 0xad, + 0x48, 0xdb, 0xc4, 0x96, 0x42, 0xe1, 0x01, 0x09, 0xa1, 0x34, 0x91, 0x42, 0x1e, 0x28, 0xd1, 0x05, + 0x78, 0xa8, 0x90, 0xac, 0xf5, 0xde, 0xc4, 0x39, 0xc9, 0x77, 0x7b, 0xec, 0xad, 0x83, 0x4d, 0xd5, + 0x17, 0xc4, 0x17, 0x20, 0xbc, 0x80, 0x90, 0xf8, 0x10, 0xf0, 0x51, 0xf8, 0x0a, 0x7c, 0x05, 0xde, + 0xd1, 0xce, 0xee, 0xd9, 0x3e, 0xbb, 0x38, 0x09, 0x4f, 0xa7, 0xfd, 0xcd, 0x6f, 0xe6, 0x7e, 0x33, + 0xb3, 0x3b, 0x43, 0x36, 0xd3, 0x81, 0xe4, 0xe7, 0x2c, 0x03, 0x21, 0x43, 0x90, 0xed, 0x0c, 0xe4, + 0x45, 0xc4, 0xa1, 0x95, 0x4a, 0xa1, 0x04, 0xad, 0x17, 0x8c, 0xde, 0xfd, 0x9e, 0x10, 0xbd, 0x3e, + 0xb4, 0x59, 0x1a, 0xb5, 0x59, 0x92, 0x08, 0xc5, 0x54, 0x24, 0x92, 0xcc, 0x90, 0xbd, 0x07, 0xd6, + 0x8a, 0xa7, 0xee, 0xe0, 0xac, 0xad, 0xa2, 0x18, 0x32, 0xc5, 0xe2, 0xd4, 0x12, 0x76, 0xf0, 0xc3, + 0x77, 0x7b, 0x90, 0xec, 0x66, 0xdf, 0xb1, 0x5e, 0x0f, 0x64, 0x5b, 0xa4, 0x18, 0x62, 0x3e, 0x5c, + 0x73, 0x87, 0x90, 0x23, 0x50, 0x01, 0x7c, 0x3b, 0x80, 0x4c, 0xd1, 0x77, 0x08, 0x89, 0x42, 0x48, + 0x54, 0x74, 0x16, 0x81, 0x74, 0x1d, 0xdf, 0xd9, 0xae, 0x04, 0x53, 0x48, 0xf3, 0x73, 0xd2, 0x38, + 0x02, 0xf5, 0x35, 0xc8, 0x2c, 0x12, 0xc9, 0x35, 0x9d, 0xa8, 0x4b, 0xd6, 0x2e, 0x8c, 0x87, 0xbb, + 0x84, 0xc6, 0xfc, 0xd8, 0x1c, 0x12, 0xef, 0xc4, 0xa6, 0xfe, 0x85, 0x4e, 0xfd, 0x40, 0x02, 0x53, + 0x70, 0xc2, 0x46, 0x7d, 0xc1, 0x42, 0xfa, 0x90, 0xd4, 0xb9, 0xe8, 0xf7, 0x59, 0x57, 0x48, 0xa6, + 0x84, 0xcc, 0x5c, 0xc7, 0x5f, 0xde, 0xae, 0x04, 0x45, 0x90, 0x3e, 0x23, 0x2b, 0x21, 0x53, 0x0c, + 0x43, 0x57, 0xf7, 0xfc, 0x56, 0xa1, 0x96, 0xad, 0x42, 0xf8, 0x43, 0xa6, 0x58, 0x80, 0xec, 0xe6, + 0x2f, 0xce, 0xcc, 0xaf, 0xbf, 0x4a, 0xc3, 0xa9, 0x5f, 0x5f, 0x95, 0xd2, 0x9c, 0xb4, 0xa5, 0x45, + 0xd2, 0x96, 0x6f, 0x24, 0xed, 0x47, 0x87, 0xdc, 0x2d, 0xd8, 0x02, 0xc8, 0x52, 0x91, 0x64, 0x40, + 0x3f, 0x24, 0xa5, 0x73, 0x60, 0xa1, 0x55, 0x54, 0xdd, 0xdb, 0x9a, 0x89, 0x98, 0x13, 0x3f, 0x43, + 0x52, 0x60, 0xc9, 0xff, 0xb3, 0x42, 0x7f, 0x3a, 0x64, 0xbd, 0x18, 0x90, 0x3e, 0x20, 0xd5, 0x50, + 0xf0, 0x41, 0x0c, 0x89, 0xea, 0x44, 0x61, 0x5e, 0x96, 0x1c, 0x3a, 0x0e, 0xe9, 0x16, 0x21, 0xb6, + 0xb5, 0xda, 0x6e, 0x9a, 0x5d, 0xb1, 0xc8, 0x71, 0x48, 0xef, 0x90, 0xd5, 0x4c, 0x31, 0x05, 0x58, + 0x90, 0x4a, 0x60, 0x0e, 0xf3, 0xb5, 0x5c, 0x79, 0x53, 0x2d, 0x1f, 0x91, 0x75, 0x25, 0x59, 0x92, + 0x31, 0xae, 0x6c, 0xf8, 0x55, 0x0c, 0x52, 0x9f, 0x42, 0x8f, 0xc3, 0xe6, 0x3f, 0x25, 0xd2, 0x98, + 0xcb, 0x88, 0x6e, 0x92, 0x4a, 0x2a, 0x3a, 0xfa, 0x77, 0x83, 0xcc, 0x75, 0xd1, 0xaf, 0x9c, 0x8a, + 0x53, 0x3c, 0x5b, 0x63, 0x32, 0x88, 0xbb, 0xe3, 0x56, 0x97, 0x53, 0xf1, 0x02, 0xcf, 0x3a, 0x23, + 0x2c, 0x53, 0x27, 0x61, 0x31, 0xe4, 0x19, 0x21, 0xf2, 0x82, 0xc5, 0x40, 0xdf, 0x25, 0x35, 0x63, + 0xce, 0x94, 0x04, 0x50, 0x36, 0xb1, 0x2a, 0x62, 0xa7, 0x08, 0x4d, 0x22, 0xf0, 0x48, 0x8d, 0xdc, + 0x95, 0xa9, 0x08, 0x07, 0x91, 0x1a, 0xd1, 0xf7, 0x48, 0xdd, 0x98, 0xbf, 0x8f, 0x52, 0x2e, 0x42, + 0xb0, 0x69, 0x99, 0xb0, 0x2f, 0x0d, 0x36, 0x21, 0x71, 0x31, 0x48, 0x94, 0x1c, 0xb9, 0xa5, 0x29, + 0xd2, 0x81, 0xc1, 0x74, 0x85, 0x24, 0xf0, 0x28, 0x8d, 0x74, 0x7b, 0x50, 0xee, 0x9a, 0xa9, 0xd0, + 0x18, 0x45, 0xc9, 0x8f, 0xc9, 0xad, 0x09, 0xcd, 0xca, 0x2e, 0x23, 0x71, 0x63, 0x8c, 0x5b, 0xe9, + 0x85, 0x88, 0x28, 0xbf, 0x32, 0x13, 0x11, 0x53, 0x78, 0x4a, 0x1a, 0x13, 0x5a, 0x9e, 0x06, 0x41, + 0xe6, 0xe4, 0x57, 0x79, 0x2a, 0x05, 0x72, 0x9e, 0x4e, 0x75, 0x86, 0x9c, 0xa7, 0xe4, 0x91, 0x32, + 0x1f, 0x48, 0x09, 0x09, 0x1f, 0xb9, 0x35, 0xd3, 0x99, 0xfc, 0x3c, 0x29, 0x3d, 0x8b, 0x35, 0xdb, + 0xad, 0xfb, 0xce, 0xf6, 0xb2, 0x2d, 0xfd, 0x3e, 0x42, 0xba, 0xf4, 0x09, 0xa8, 0x9c, 0xb0, 0x8e, + 0x84, 0x4a, 0x02, 0x6a, 0x62, 0x56, 0x6c, 0x98, 0x9b, 0x37, 0x8c, 0x59, 0xb1, 0xa1, 0x35, 0xdf, + 0x23, 0x65, 0x6d, 0x96, 0xfa, 0xc2, 0xde, 0x42, 0xe3, 0x9a, 0x62, 0xc3, 0x40, 0x5f, 0xd9, 0xfb, + 0xa4, 0x32, 0xd6, 0xea, 0x36, 0x4c, 0x4b, 0xc7, 0x80, 0xbe, 0xe6, 0xa8, 0xc2, 0xa5, 0xe6, 0x9a, + 0xe3, 0x61, 0xba, 0x87, 0x89, 0x62, 0x5c, 0xb9, 0xb7, 0x0b, 0x3d, 0x44, 0x4c, 0x8f, 0x4a, 0x2e, + 0x62, 0xfd, 0x9a, 0xdc, 0x3b, 0x66, 0x54, 0xda, 0x23, 0xfd, 0x94, 0xd4, 0x43, 0xe8, 0x47, 0x17, + 0x20, 0x47, 0x1d, 0x3d, 0xa9, 0xdc, 0xbb, 0xf8, 0x9a, 0xbd, 0x96, 0x59, 0x07, 0xad, 0x7c, 0x1d, + 0xb4, 0xbe, 0xcc, 0xd7, 0x41, 0x50, 0xcb, 0x1d, 0x0e, 0xb5, 0xe6, 0x4f, 0x48, 0x4d, 0xfb, 0x75, + 0x38, 0xce, 0xd8, 0xd0, 0x7d, 0xeb, 0x4a, 0xff, 0xaa, 0xe6, 0x9b, 0x91, 0x8c, 0x4f, 0x1b, 0x86, + 0x4a, 0xb2, 0x0e, 0x8e, 0x92, 0xb7, 0x4d, 0xce, 0x88, 0xe8, 0x17, 0xb6, 0xf7, 0xeb, 0x2a, 0xd9, + 0x38, 0xb4, 0x83, 0xe0, 0xd4, 0x2c, 0x37, 0xfa, 0x93, 0x43, 0x4a, 0xc6, 0x9d, 0x3e, 0x5e, 0x34, + 0x74, 0x0a, 0x53, 0xdf, 0x7b, 0xb8, 0x88, 0x9a, 0x0f, 0xa4, 0xe6, 0x47, 0x97, 0xfb, 0x9e, 0xe7, + 0x1a, 0xcf, 0xcc, 0x67, 0x7e, 0xee, 0xe3, 0xa3, 0xd3, 0x0f, 0x7f, 0xfd, 0xfd, 0xf3, 0xd2, 0xed, + 0xe6, 0x7a, 0xbb, 0x10, 0xea, 0x63, 0xe7, 0x09, 0xfd, 0xdd, 0x21, 0x25, 0x33, 0xea, 0x17, 0x6b, + 0x2a, 0xac, 0x83, 0x6b, 0x6a, 0x3a, 0x40, 0x4d, 0xc6, 0xf3, 0x3f, 0x34, 0xf9, 0xde, 0x66, 0x51, + 0x53, 0xfb, 0xd5, 0x64, 0xab, 0xbc, 0xd6, 0x02, 0xff, 0x70, 0x70, 0x21, 0xdb, 0x15, 0x4b, 0x67, + 0xa7, 0xf5, 0xdc, 0xf6, 0xbd, 0xa6, 0xb6, 0x6f, 0x2e, 0xf7, 0x77, 0xbc, 0x27, 0x47, 0xa0, 0x7c, + 0xe6, 0x67, 0x29, 0xf0, 0xe8, 0x2c, 0xe2, 0xbe, 0x9d, 0xcc, 0xbe, 0x38, 0x7b, 0xb3, 0xda, 0xf7, + 0xe9, 0xa3, 0x05, 0x6a, 0xdb, 0xaf, 0xac, 0xff, 0x6b, 0xfa, 0x9b, 0x43, 0x96, 0x8f, 0x40, 0xd1, + 0x7b, 0xf3, 0x6a, 0x6f, 0x26, 0xf3, 0xf4, 0x72, 0x7f, 0xd7, 0x7b, 0xaa, 0x65, 0xaa, 0x73, 0xf0, + 0xcd, 0x5b, 0x57, 0x57, 0xea, 0xdc, 0xa2, 0x8b, 0xaa, 0xfa, 0xfc, 0x19, 0x69, 0x70, 0x11, 0x17, + 0xff, 0xff, 0xbc, 0x66, 0x6f, 0xe9, 0x89, 0xbe, 0xf7, 0x27, 0xce, 0xcb, 0x8d, 0x82, 0x39, 0xed, + 0x76, 0x4b, 0xf8, 0x22, 0x3e, 0xf8, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xa0, 0xe0, 0x99, 0xba, + 0x09, 0x00, 0x00, } diff --git a/protobufs/gen/swagger.json b/protobufs/gen/swagger.json index d79acae9a..96785d89a 100644 --- a/protobufs/gen/swagger.json +++ b/protobufs/gen/swagger.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"smart_contract_bytecode":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"documentAccessTokenParams":{"type":"object","properties":{"grantee":{"type":"string","title":"The identity being granted access to the document"},"document_identifier":{"type":"string","title":"Original identifier of the document"}}},"documentUpdateAccessTokenPayload":{"type":"object","properties":{"delegating_document_identifier":{"type":"string","title":"The document which should contain the access token referenced below"},"access_token_params":{"$ref":"#/definitions/documentAccessTokenParams","title":"The access token to be appended to the indicated document above"}}},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"},"access_token_payload":{"$ref":"#/definitions/documentUpdateAccessTokenPayload"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"version":"0.0.3","title":"Centrifuge OS Node API","description":"\n","contact":{"name":"Centrifuge","url":"https://github.com/centrifuge/go-centrifuge","email":"hello@centrifuge.io"}},"host":"localhost","basePath":"","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"tags":[],"definitions":{"accountAccountData":{"type":"object","properties":{"eth_account":{"$ref":"#/definitions/accountEthereumAccount"},"eth_default_account_name":{"type":"string"},"receive_event_notification_endpoint":{"type":"string"},"identity_id":{"type":"string"},"signing_key_pair":{"$ref":"#/definitions/accountKeyPair"},"p2p_key_pair":{"$ref":"#/definitions/accountKeyPair"}}},"accountEthereumAccount":{"type":"object","properties":{"address":{"type":"string"},"key":{"type":"string"},"password":{"type":"string"}}},"accountGetAllAccountResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/definitions/accountAccountData"}}}},"accountKeyPair":{"type":"object","properties":{"pub":{"type":"string"},"pvt":{"type":"string"}}},"accountUpdateAccountRequest":{"type":"object","properties":{"identifier":{"type":"string"},"data":{"$ref":"#/definitions/accountAccountData"}}},"configConfigData":{"type":"object","properties":{"storage_path":{"type":"string"},"p2p_port":{"type":"integer","format":"int32"},"p2p_external_ip":{"type":"string"},"p2p_connection_timeout":{"type":"string"},"server_port":{"type":"integer","format":"int32"},"server_address":{"type":"string"},"num_workers":{"type":"integer","format":"int32"},"worker_wait_time_ms":{"type":"integer","format":"int32"},"eth_node_url":{"type":"string"},"eth_context_read_wait_timeout":{"type":"string"},"eth_context_wait_timeout":{"type":"string"},"eth_interval_retry":{"type":"string"},"eth_max_retries":{"type":"integer","format":"int64"},"eth_gas_price":{"type":"string","format":"uint64"},"eth_gas_limit":{"type":"string","format":"uint64"},"tx_pool_enabled":{"type":"boolean","format":"boolean"},"network":{"type":"string"},"bootstrap_peers":{"type":"array","items":{"type":"string"}},"network_id":{"type":"integer","format":"int64"},"main_identity":{"$ref":"#/definitions/accountAccountData"},"smart_contract_addresses":{"type":"object","additionalProperties":{"type":"string"}},"smart_contract_bytecode":{"type":"object","additionalProperties":{"type":"string"}},"pprof_enabled":{"type":"boolean","format":"boolean"}}},"documentCreateDocumentProofForVersionRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"version":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentCreateDocumentProofRequest":{"type":"object","properties":{"identifier":{"type":"string"},"type":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"documentDocumentProof":{"type":"object","properties":{"header":{"$ref":"#/definitions/documentResponseHeader"},"field_proofs":{"type":"array","items":{"$ref":"#/definitions/documentProof"}}}},"documentProof":{"type":"object","properties":{"property":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"hash":{"type":"string","title":"hash is filled if value & salt are not available"},"sorted_hashes":{"type":"array","items":{"type":"string"}}}},"documentResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"healthPong":{"type":"object","properties":{"version":{"type":"string"},"network":{"type":"string"}},"title":"Pong contains basic information about the node"},"invoiceInvoiceCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceData":{"type":"object","properties":{"invoice_status":{"type":"string"},"invoice_number":{"type":"string","title":"invoice number or reference number"},"sender_name":{"type":"string","title":"name of the sender company"},"sender_street":{"type":"string","title":"street and address details of the sender company"},"sender_city":{"type":"string"},"sender_zipcode":{"type":"string"},"sender_country":{"type":"string","title":"country ISO code of the sender of this invoice"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this invoice"},"currency":{"type":"string","title":"ISO currency code"},"gross_amount":{"type":"string","format":"int64","title":"invoice amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"sender":{"type":"string"},"payee":{"type":"string"},"comment":{"type":"string"},"due_date":{"type":"string","format":"date-time"},"date_created":{"type":"string","format":"date-time"},"extra_data":{"type":"string"}}},"invoiceInvoiceResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/invoiceResponseHeader"},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceInvoiceUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/invoiceInvoiceData"}}},"invoiceResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most document"},"nftNFTMintRequest":{"type":"object","properties":{"identifier":{"type":"string","title":"Document identifier"},"registry_address":{"type":"string","title":"The contract address of the registry where the token should be minted"},"deposit_address":{"type":"string"},"proof_fields":{"type":"array","items":{"type":"string"}},"submit_token_proof":{"type":"boolean","format":"boolean","title":"proof that nft is part of document"},"submit_nft_owner_access_proof":{"type":"boolean","format":"boolean","title":"proof that nft owner can access the document if nft_grant_access is true"},"grant_nft_access":{"type":"boolean","format":"boolean","title":"grant nft read access to the document"}}},"nftNFTMintResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/nftResponseHeader"},"token_id":{"type":"string"}}},"nftResponseHeader":{"type":"object","properties":{"transaction_id":{"type":"string"}}},"notificationNotificationMessage":{"type":"object","properties":{"event_type":{"type":"integer","format":"int64"},"recorded":{"type":"string","format":"date-time"},"document_type":{"type":"string"},"document_id":{"type":"string"},"account_id":{"type":"string","title":"account_id is the account associated to webhook"},"from_id":{"type":"string","title":"from_id if provided, original trigger of the event"},"to_id":{"type":"string","title":"to_id if provided, final destination of the event"}},"title":"NotificationMessage wraps a single CoreDocument to be notified to upstream services"},"purchaseorderPurchaseOrderCreatePayload":{"type":"object","properties":{"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderData":{"type":"object","properties":{"po_status":{"type":"string"},"po_number":{"type":"string","title":"purchase order number or reference number"},"order_name":{"type":"string","title":"name of the ordering company"},"order_street":{"type":"string","title":"street and address details of the ordering company"},"order_city":{"type":"string"},"order_zipcode":{"type":"string"},"order_country":{"type":"string","title":"country ISO code of the ordering company of this purchase order"},"recipient_name":{"type":"string","title":"name of the recipient company"},"recipient_street":{"type":"string"},"recipient_city":{"type":"string"},"recipient_zipcode":{"type":"string"},"recipient_country":{"type":"string","title":"country ISO code of the receipient of this purchase order"},"currency":{"type":"string","title":"ISO currency code"},"order_amount":{"type":"string","format":"int64","title":"ordering gross amount including tax"},"net_amount":{"type":"string","format":"int64","title":"invoice amount excluding tax"},"tax_amount":{"type":"string","format":"int64"},"tax_rate":{"type":"string","format":"int64"},"recipient":{"type":"string"},"order":{"type":"string"},"order_contact":{"type":"string","title":"contact or requester or purchaser at the ordering company"},"comment":{"type":"string"},"delivery_date":{"type":"string","format":"date-time","title":"requested delivery date"},"date_created":{"type":"string","format":"date-time","title":"purchase order date"},"extra_data":{"type":"string"}}},"purchaseorderPurchaseOrderResponse":{"type":"object","properties":{"header":{"$ref":"#/definitions/purchaseorderResponseHeader"},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderPurchaseOrderUpdatePayload":{"type":"object","properties":{"identifier":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"data":{"$ref":"#/definitions/purchaseorderPurchaseOrderData"}}},"purchaseorderResponseHeader":{"type":"object","properties":{"document_id":{"type":"string"},"version_id":{"type":"string"},"state":{"type":"string"},"collaborators":{"type":"array","items":{"type":"string"}},"transaction_id":{"type":"string"}},"title":"ResponseHeader contains a set of common fields for most documents"},"transactionsTransactionStatusResponse":{"type":"object","properties":{"transaction_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"last_updated":{"type":"string","format":"date-time"}}}},"paths":{"/accounts":{"get":{"description":"Get All Accounts","operationId":"GetAllAccounts","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountGetAllAccountResponse"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]},"post":{"description":"Creates an Account","operationId":"CreateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountAccountData"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/accounts/generate":{"post":{"description":"Generates an Account taking defaults based on the main account","operationId":"GenerateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"tags":["AccountService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/accounts/{identifier}":{"get":{"description":"Get Account","operationId":"GetAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]},"put":{"description":"Updates an Account","operationId":"UpdateAccount","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/accountAccountData"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/accountUpdateAccountRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["AccountService"]}},"/config":{"get":{"description":"Get Node Config","operationId":"GetConfig","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/configConfigData"}}},"tags":["ConfigService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/document/{identifier}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the document given by ID","operationId":"CreateDocumentProof","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/document/{identifier}/{version}/proof":{"post":{"description":"Creates a list of precise proofs for the specified fields of the given version of the document given by ID","operationId":"CreateDocumentProofForVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/documentDocumentProof"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/documentCreateDocumentProofForVersionRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/ping":{"get":{"description":"Health check for the Node","operationId":"Ping","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/healthPong"}}},"tags":["HealthCheckService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/invoice":{"post":{"description":"Creates an invoice","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}":{"get":{"description":"Get the current invoice","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates an invoice","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/invoiceInvoiceUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/invoice/{identifier}/{version}":{"get":{"description":"Get a specific version of an invoice","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/invoiceInvoiceResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/token/mint":{"post":{"description":"Mint an NFT from a Centrifuge Document","operationId":"MintNFT","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/nftNFTMintResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/nftNFTMintRequest"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["NFTService"]}},"/dummy":{"get":{"description":"Dummy notification endpoint","operationId":"Notify","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/notificationNotificationMessage"}}},"tags":["NotificationDummyService"],"parameters":[{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}]}},"/purchaseorder":{"post":{"description":"Creates a purchase order","operationId":"Create","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderCreatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}":{"get":{"description":"Get the current version of a purchase order","operationId":"Get","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]},"put":{"description":"Updates a purchase order","operationId":"Update","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"body","in":"body","required":true,"schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderUpdatePayload"}},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/purchaseorder/{identifier}/{version}":{"get":{"description":"Get a specific version of a purchase order","operationId":"GetVersion","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/purchaseorderPurchaseOrderResponse"}}},"parameters":[{"name":"identifier","in":"path","required":true,"type":"string"},{"name":"version","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["DocumentService"]}},"/transactions/{transaction_id}":{"get":{"description":"Get Transaction Status","operationId":"GetTransactionStatus","responses":{"200":{"description":"","schema":{"$ref":"#/definitions/transactionsTransactionStatusResponse"}}},"parameters":[{"name":"transaction_id","in":"path","required":true,"type":"string"},{"name":"authorization","in":"header","description":"Hex encoded centrifuge ID of the account for the intended API action","required":true,"type":"string"}],"tags":["TransactionService"]}}}} \ No newline at end of file diff --git a/protobufs/gen/swagger/invoice/service.swagger.json b/protobufs/gen/swagger/invoice/service.swagger.json index c5f299e1b..40c3f0044 100644 --- a/protobufs/gen/swagger/invoice/service.swagger.json +++ b/protobufs/gen/swagger/invoice/service.swagger.json @@ -131,32 +131,6 @@ } }, "definitions": { - "documentAccessTokenParams": { - "type": "object", - "properties": { - "grantee": { - "type": "string", - "title": "The identity being granted access to the document" - }, - "document_identifier": { - "type": "string", - "title": "Original identifier of the document" - } - } - }, - "documentUpdateAccessTokenPayload": { - "type": "object", - "properties": { - "delegating_document_identifier": { - "type": "string", - "title": "The document which should contain the access token referenced below" - }, - "access_token_params": { - "$ref": "#/definitions/documentAccessTokenParams", - "title": "The access token to be appended to the indicated document above" - } - } - }, "invoiceInvoiceCreatePayload": { "type": "object", "properties": { @@ -288,9 +262,6 @@ }, "data": { "$ref": "#/definitions/invoiceInvoiceData" - }, - "access_token_payload": { - "$ref": "#/definitions/documentUpdateAccessTokenPayload" } } }, diff --git a/protobufs/gen/swagger/purchaseorder/service.swagger.json b/protobufs/gen/swagger/purchaseorder/service.swagger.json index 9d922d72d..143880d90 100644 --- a/protobufs/gen/swagger/purchaseorder/service.swagger.json +++ b/protobufs/gen/swagger/purchaseorder/service.swagger.json @@ -131,32 +131,6 @@ } }, "definitions": { - "documentAccessTokenParams": { - "type": "object", - "properties": { - "grantee": { - "type": "string", - "title": "The identity being granted access to the document" - }, - "document_identifier": { - "type": "string", - "title": "Original identifier of the document" - } - } - }, - "documentUpdateAccessTokenPayload": { - "type": "object", - "properties": { - "delegating_document_identifier": { - "type": "string", - "title": "The document which should contain the access token referenced below" - }, - "access_token_params": { - "$ref": "#/definitions/documentAccessTokenParams", - "title": "The access token to be appended to the indicated document above" - } - } - }, "purchaseorderPurchaseOrderCreatePayload": { "type": "object", "properties": { @@ -291,9 +265,6 @@ }, "data": { "$ref": "#/definitions/purchaseorderPurchaseOrderData" - }, - "access_token_payload": { - "$ref": "#/definitions/documentUpdateAccessTokenPayload" } } }, diff --git a/protobufs/invoice/service.proto b/protobufs/invoice/service.proto index a0e11808e..d4ce4b36a 100644 --- a/protobufs/invoice/service.proto +++ b/protobufs/invoice/service.proto @@ -7,7 +7,6 @@ option java_multiple_files = true; option java_outer_classname = "ServiceProto"; option java_package = "com.invoice"; -import "document/service.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-swagger/options/annotations.proto"; @@ -68,7 +67,6 @@ message InvoiceUpdatePayload { string identifier = 1; repeated string collaborators = 2; InvoiceData data = 3; - document.UpdateAccessTokenPayload access_token_payload = 4; } message InvoiceResponse { diff --git a/protobufs/purchaseorder/service.proto b/protobufs/purchaseorder/service.proto index c2acf79db..952fb6093 100644 --- a/protobufs/purchaseorder/service.proto +++ b/protobufs/purchaseorder/service.proto @@ -7,7 +7,6 @@ option java_multiple_files = true; option java_outer_classname = "ServiceProto"; option java_package = "com.purchaseorder"; -import "document/service.proto"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-swagger/options/annotations.proto"; @@ -68,7 +67,6 @@ message PurchaseOrderUpdatePayload { string identifier = 1; repeated string collaborators = 2; PurchaseOrderData data = 3; - document.UpdateAccessTokenPayload access_token_payload = 4; } message PurchaseOrderResponse {